Sleep GPS near homepoints, wait for significant motion sensor.

First attempts, will test for a few days.
master
voussoir 2023-03-30 21:49:26 -07:00
parent 1ef59f49f5
commit 67382ce90a
7 changed files with 277 additions and 134 deletions

View File

@ -30,9 +30,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import android.widget.Button import android.widget.*
import android.widget.EditText
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -62,13 +60,9 @@ class MapFragment : Fragment()
private var bound: Boolean = false private var bound: Boolean = false
val handler: Handler = Handler(Looper.getMainLooper()) val handler: Handler = Handler(Looper.getMainLooper())
private var trackingState: Int = Keys.STATE_TRACKING_STOPPED
private var gpsProviderActive: Boolean = false
private var networkProviderActive: Boolean = false
private lateinit var currentBestLocation: Location
var continuous_auto_center: Boolean = true var continuous_auto_center: Boolean = true
private lateinit var trackerService: TrackerService private var trackerService: TrackerService? = null
private lateinit var database_changed_listener: DatabaseChangedListener private lateinit var database_changed_listener: DatabaseChangedListener
var thismapfragment: MapFragment? = null var thismapfragment: MapFragment? = null
@ -79,6 +73,8 @@ class MapFragment : Fragment()
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 currentLocationButton: FloatingActionButton lateinit var currentLocationButton: FloatingActionButton
lateinit var map_current_time: TextView
lateinit var power_level_indicator: ImageButton
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>()
@ -107,8 +103,6 @@ class MapFragment : Fragment()
update_main_button() update_main_button()
} }
} }
currentBestLocation = getLastKnownLocation(requireContext())
trackingState = PreferencesHelper.loadTrackingState()
} }
/* Overrides onStop from Fragment */ /* Overrides onStop from Fragment */
@ -121,6 +115,8 @@ class MapFragment : Fragment()
currentLocationButton = rootView.findViewById(R.id.location_button) currentLocationButton = rootView.findViewById(R.id.location_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)
map_current_time = rootView.findViewById(R.id.map_current_time)
power_level_indicator = rootView.findViewById(R.id.power_level_indicator)
mainButton = rootView.findViewById(R.id.main_button) mainButton = rootView.findViewById(R.id.main_button)
locationErrorBar = Snackbar.make(mapView, String(), Snackbar.LENGTH_INDEFINITE) locationErrorBar = Snackbar.make(mapView, String(), Snackbar.LENGTH_INDEFINITE)
@ -200,9 +196,7 @@ class MapFragment : Fragment()
trackbook.database_changed_listeners.add(database_changed_listener) trackbook.database_changed_listeners.add(database_changed_listener)
} }
create_current_position_overlays(currentBestLocation, trackingState) centerMap(getLastKnownLocation(requireContext()))
centerMap(currentBestLocation)
current_track_overlay = null current_track_overlay = null
@ -213,9 +207,14 @@ class MapFragment : Fragment()
update_main_button() update_main_button()
mainButton.setOnClickListener { mainButton.setOnClickListener {
if (trackingState == Keys.STATE_TRACKING_ACTIVE) val tracker = trackerService
if (tracker == null)
{ {
trackerService.stopTracking() return@setOnClickListener
}
if (tracker.trackingState == Keys.STATE_TRACKING_ACTIVE)
{
tracker.stopTracking()
} }
else else
{ {
@ -224,7 +223,12 @@ class MapFragment : Fragment()
handler.postDelayed(location_update_redraw, 0) handler.postDelayed(location_update_redraw, 0)
} }
currentLocationButton.setOnClickListener { currentLocationButton.setOnClickListener {
centerMap(currentBestLocation, animated=true) val tracker = trackerService
if (tracker == null)
{
return@setOnClickListener
}
centerMap(tracker.currentBestLocation, animated=true)
} }
zoom_in_button.setOnClickListener { zoom_in_button.setOnClickListener {
mapView.controller.setZoom(mapView.zoomLevelDouble + 0.5) mapView.controller.setZoom(mapView.zoomLevelDouble + 0.5)
@ -256,6 +260,7 @@ class MapFragment : Fragment()
{ {
Log.i("VOUSSOIR", "MapFragment.onResume") Log.i("VOUSSOIR", "MapFragment.onResume")
super.onResume() super.onResume()
redraw()
requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
// if (bound) { // if (bound) {
// trackerService.addGpsLocationListener() // trackerService.addGpsLocationListener()
@ -268,26 +273,31 @@ class MapFragment : Fragment()
{ {
Log.i("VOUSSOIR", "MapFragment.onPause") Log.i("VOUSSOIR", "MapFragment.onPause")
super.onPause() super.onPause()
if (::trackerService.isInitialized)
{
trackerService.mapfragment = null
}
saveBestLocationState(currentBestLocation)
if (bound && trackingState != Keys.STATE_TRACKING_ACTIVE) {
trackerService.removeGpsLocationListener()
trackerService.removeNetworkLocationListener()
trackerService.trackbook.database.commit()
}
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
val tracker = trackerService
if (tracker == null)
{
return
}
saveBestLocationState(tracker.currentBestLocation)
tracker.mapfragment = null
if (bound && tracker.trackingState != Keys.STATE_TRACKING_ACTIVE)
{
tracker.removeGpsLocationListener()
tracker.removeNetworkLocationListener()
tracker.trackbook.database.commit()
}
} }
/* Overrides onStop from Fragment */ /* Overrides onStop from Fragment */
override fun onStop() override fun onStop()
{ {
super.onStop() super.onStop()
if (::trackerService.isInitialized) val tracker = trackerService
if (tracker != null)
{ {
trackerService.mapfragment = null tracker.mapfragment = null
} }
// unbind from TrackerService // unbind from TrackerService
if (bound) if (bound)
@ -311,7 +321,10 @@ class MapFragment : Fragment()
{ {
Log.i("VOUSSOIR", "MapFragment.onDestroy") Log.i("VOUSSOIR", "MapFragment.onDestroy")
super.onDestroy() super.onDestroy()
trackerService.mapfragment = null if (trackerService != null)
{
trackerService!!.mapfragment = null
}
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} }
@ -328,6 +341,8 @@ class MapFragment : Fragment()
// permission denied - unbind service // permission denied - unbind service
activity?.unbindService(connection) activity?.unbindService(connection)
} }
val gpsProviderActive = if (trackerService == null) false else trackerService!!.gpsProviderActive
val networkProviderActive = if (trackerService == null) false else trackerService!!.networkProviderActive
toggleLocationErrorBar(gpsProviderActive, networkProviderActive) toggleLocationErrorBar(gpsProviderActive, networkProviderActive)
} }
@ -344,7 +359,10 @@ class MapFragment : Fragment()
{ {
activity?.startService(intent) activity?.startService(intent)
} }
trackerService.startTracking() if (trackerService != null)
{
trackerService!!.startTracking()
}
} }
@ -354,24 +372,14 @@ class MapFragment : Fragment()
bound = false bound = false
// unregister listener for changes in shared preferences // unregister listener for changes in shared preferences
PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener) PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener)
if (::trackerService.isInitialized) if (trackerService != null)
{ {
trackerService.mapfragment = null trackerService!!.mapfragment = null
} }
} }
private val sharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key -> private val sharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
when (key) redraw()
{
Keys.PREF_TRACKING_STATE ->
{
if (activity != null)
{
trackingState = PreferencesHelper.loadTrackingState()
}
}
}
update_main_button()
} }
fun centerMap(location: Location, animated: Boolean = false) { fun centerMap(location: Location, animated: Boolean = false) {
@ -557,6 +565,7 @@ class MapFragment : Fragment()
fun update_main_button() fun update_main_button()
{ {
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)
@ -564,13 +573,13 @@ class MapFragment : Fragment()
mainButton.text = requireContext().getString(R.string.button_not_ready) mainButton.text = requireContext().getString(R.string.button_not_ready)
mainButton.icon = null mainButton.icon = null
} }
else if (trackingState == Keys.STATE_TRACKING_STOPPED) else if (tracker == null || tracker.trackingState == Keys.STATE_TRACKING_STOPPED)
{ {
mainButton.setIconResource(R.drawable.ic_fiber_manual_record_inactive_24dp) mainButton.setIconResource(R.drawable.ic_fiber_manual_record_inactive_24dp)
mainButton.text = requireContext().getString(R.string.button_start) mainButton.text = requireContext().getString(R.string.button_start)
mainButton.contentDescription = requireContext().getString(R.string.descr_button_start) mainButton.contentDescription = requireContext().getString(R.string.descr_button_start)
} }
else if (trackingState == Keys.STATE_TRACKING_ACTIVE) else if (tracker.trackingState == Keys.STATE_TRACKING_ACTIVE)
{ {
mainButton.setIconResource(R.drawable.ic_fiber_manual_stop_24dp) mainButton.setIconResource(R.drawable.ic_fiber_manual_stop_24dp)
mainButton.text = requireContext().getString(R.string.button_pause) mainButton.text = requireContext().getString(R.string.button_pause)
@ -609,11 +618,9 @@ class MapFragment : Fragment()
} }
bound = true bound = true
trackerService = serviceref trackerService = serviceref
trackerService.mapfragment = thismapfragment trackerService!!.mapfragment = thismapfragment
// get state of tracking and update button if necessary // get state of tracking and update button if necessary
trackingState = trackerService.trackingState redraw()
update_main_button()
handler.postDelayed(location_update_redraw, 0)
// 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
@ -625,27 +632,57 @@ class MapFragment : Fragment()
} }
} }
fun redraw()
{
// Log.i("VOUSSOIR", "MapFragment.redraw")
update_main_button()
val tracker = trackerService
if (tracker == null)
{
return
}
create_current_position_overlays(tracker.currentBestLocation, tracker.trackingState)
if (current_track_overlay == null)
{
create_track_overlay()
}
current_track_overlay!!.setPoints(tracker.recent_trackpoints_for_mapview)
if (continuous_auto_center)
{
centerMap(tracker.currentBestLocation, animated=false)
}
map_current_time.text = iso8601_local_noms(tracker.currentBestLocation.time)
if (tracker.arrived_at_home == 0L)
{
power_level_indicator.setImageResource(R.drawable.ic_satellite_24dp)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
power_level_indicator.tooltipText = "GPS tracking at full power"
}
}
else if (tracker.location_interval == tracker.LOCATION_INTERVAL_SLEEP)
{
power_level_indicator.setImageResource(R.drawable.ic_sleep_24dp)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
power_level_indicator.tooltipText = "GPS sleeping until movement"
}
}
else
{
power_level_indicator.setImageResource(R.drawable.ic_homepoint_24dp)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
power_level_indicator.tooltipText = "You are at home"
}
}
}
val location_update_redraw: Runnable = object : Runnable val location_update_redraw: Runnable = object : Runnable
{ {
override fun run() override fun run()
{ {
Log.i("VOUSSOIR", "MapFragment.location_update_redraw") redraw()
currentBestLocation = trackerService.currentBestLocation
gpsProviderActive = trackerService.gpsProviderActive
networkProviderActive = trackerService.networkProviderActive
trackingState = trackerService.trackingState
create_current_position_overlays(currentBestLocation, trackingState)
if (current_track_overlay == null)
{
create_track_overlay()
}
current_track_overlay!!.setPoints(trackerService.recent_trackpoints_for_mapview)
if (continuous_auto_center)
{
centerMap(currentBestLocation, animated=false)
}
} }
} }
} }

View File

@ -57,7 +57,6 @@ 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
import java.text.SimpleDateFormat
import java.util.* import java.util.*
class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener

View File

@ -31,6 +31,10 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.hardware.Sensor
import android.hardware.SensorManager
import android.hardware.TriggerEvent
import android.hardware.TriggerEventListener
import android.location.Location import android.location.Location
import android.location.LocationListener import android.location.LocationListener
import android.location.LocationManager import android.location.LocationManager
@ -39,23 +43,14 @@ import android.media.ToneGenerator
import android.os.Binder import android.os.Binder
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.Vibrator
import android.util.Log import android.util.Log
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import net.voussoir.trkpt.helpers.PreferencesHelper import net.voussoir.trkpt.helpers.*
import net.voussoir.trkpt.helpers.getDefaultLocation
import net.voussoir.trkpt.helpers.getLastKnownLocation
import net.voussoir.trkpt.helpers.isAccurateEnough
import net.voussoir.trkpt.helpers.isBetterLocation
import net.voussoir.trkpt.helpers.isDifferentEnough
import net.voussoir.trkpt.helpers.isGpsEnabled
import net.voussoir.trkpt.helpers.isNetworkEnabled
import net.voussoir.trkpt.helpers.isRecentEnough
import net.voussoir.trkpt.helpers.iso8601_local
import net.voussoir.trkpt.helpers.random_device_id
import org.osmdroid.util.GeoPoint import org.osmdroid.util.GeoPoint
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.*
@ -70,7 +65,11 @@ class TrackerService: Service()
var device_id: String = random_device_id() var device_id: String = random_device_id()
var currentBestLocation: Location = getDefaultLocation() var currentBestLocation: Location = getDefaultLocation()
var lastCommit: Long = 0 var lastCommit: Long = 0
var location_min_time_ms: Long = 0 var last_significant_motion: Long = 0
var arrived_at_home: Long = 0
var location_interval: Long = 0
val LOCATION_INTERVAL_FULLPOWER: Long = 0
val LOCATION_INTERVAL_SLEEP: Long = Keys.ONE_MINUTE_IN_MILLISECONDS
private val RECENT_TRKPT_COUNT = 3600 private val RECENT_TRKPT_COUNT = 3600
private val DISPLACEMENT_LOCATION_COUNT = 5 private val DISPLACEMENT_LOCATION_COUNT = 5
lateinit var recent_displacement_locations: Deque<Location> lateinit var recent_displacement_locations: Deque<Location>
@ -94,7 +93,10 @@ class TrackerService: Service()
var mapfragment: MapFragment? = null var mapfragment: MapFragment? = null
private fun addGpsLocationListener() private lateinit var sensor_manager: SensorManager
private var significant_motion_sensor: Sensor? = null
private fun addGpsLocationListener(interval: Long)
{ {
if (! use_gps_location) if (! use_gps_location)
{ {
@ -124,7 +126,7 @@ class TrackerService: Service()
locationManager.requestLocationUpdates( locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LocationManager.GPS_PROVIDER,
location_min_time_ms, interval,
0f, 0f,
gpsLocationListener, gpsLocationListener,
) )
@ -132,7 +134,7 @@ class TrackerService: Service()
Log.i("VOUSSOIR", "Added GPS location listener.") Log.i("VOUSSOIR", "Added GPS location listener.")
} }
private fun addNetworkLocationListener() private fun addNetworkLocationListener(interval: Long)
{ {
if (! use_network_location) if (! use_network_location)
{ {
@ -162,7 +164,7 @@ class TrackerService: Service()
locationManager.requestLocationUpdates( locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, LocationManager.NETWORK_PROVIDER,
0, interval,
0f, 0f,
networkLocationListener, networkLocationListener,
) )
@ -198,6 +200,27 @@ class TrackerService: Service()
} }
} }
fun reset_location_listeners(interval: Long)
{
location_interval = interval
if (gpsLocationListenerRegistered)
{
removeGpsLocationListener()
}
if (networkLocationListenerRegistered)
{
removeNetworkLocationListener()
}
if (use_gps_location)
{
addGpsLocationListener(interval)
}
if (use_network_location)
{
addNetworkLocationListener(interval)
}
}
private fun createLocationListener(): LocationListener private fun createLocationListener(): LocationListener
{ {
return object : LocationListener return object : LocationListener
@ -208,17 +231,11 @@ class TrackerService: Service()
// beeper.startTone(ToneGenerator.TONE_PROP_ACK, 150) // beeper.startTone(ToneGenerator.TONE_PROP_ACK, 150)
if (location.time == currentBestLocation.time) if (location.time <= currentBestLocation.time)
{ {
return return
} }
if (! isBetterLocation(location, currentBestLocation))
{
Log.i("VOUSSOIR", "Not better than previous.")
return
}
currentBestLocation = location currentBestLocation = location
val mf = mapfragment val mf = mapfragment
@ -241,16 +258,12 @@ class TrackerService: Service()
Log.i("VOUSSOIR", "Omitting due to 0,0 location.") Log.i("VOUSSOIR", "Omitting due to 0,0 location.")
return return
} }
if (! isRecentEnough(location))
{ // The Homepoint checks need to come before the other checks because if there
Log.i("VOUSSOIR", "Omitting due to not recent enough.") // is even the slightest chance that the user has left the homepoint, we want to
return // wake back up to full power. We do not want to put this below the isAccurateEnough
} // of isRecentEnough checks because we already know that the sleeping GPS produces
if (! isAccurateEnough(location, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY)) // very inaccurate points so if those bail early we'd stay in sleep mode.
{
Log.i("VOUSSOIR", "Omitting due to not accurate enough.")
return
}
for ((index, homepoint) in trackbook.homepoints.withIndex()) for ((index, homepoint) in trackbook.homepoints.withIndex())
{ {
if (homepoint.location.distanceTo(location) < homepoint.radius) if (homepoint.location.distanceTo(location) < homepoint.radius)
@ -261,9 +274,42 @@ class TrackerService: Service()
trackbook.homepoints.remove(homepoint) trackbook.homepoints.remove(homepoint)
trackbook.homepoints.addFirst(homepoint) trackbook.homepoints.addFirst(homepoint)
} }
if (arrived_at_home == 0L)
{
Log.i("VOUSSOIR", "Arrived at home.")
arrived_at_home = System.currentTimeMillis()
}
else if (location_interval == LOCATION_INTERVAL_SLEEP || significant_motion_sensor == null)
{
// If we are already asleep, do not reset the listeners again because
// that immediately fetches a new location.
// If we cannot rely on the motion sensor, then don't sleep!
}
else if ((System.currentTimeMillis() - arrived_at_home) > Keys.ONE_MINUTE_IN_MILLISECONDS)
{
Log.i("VOUSSOIR", "Staying at home.")
reset_location_listeners(interval=LOCATION_INTERVAL_SLEEP)
}
return return
} }
} }
if (arrived_at_home > 0)
{
Log.i("VOUSSOIR", "Leaving home.")
arrived_at_home = 0
reset_location_listeners(interval=LOCATION_INTERVAL_FULLPOWER)
}
if (! isRecentEnough(location))
{
Log.i("VOUSSOIR", "Omitting due to not recent enough.")
return
}
if (! isAccurateEnough(location, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY))
{
Log.i("VOUSSOIR", "Omitting due to not accurate enough.")
return
}
if (recent_displacement_locations.isEmpty()) if (recent_displacement_locations.isEmpty())
{ {
// pass // pass
@ -321,13 +367,20 @@ class TrackerService: Service()
private fun displayNotification(): Notification private fun displayNotification(): Notification
{ {
val timestamp = iso8601_local(currentBestLocation.time) val timestamp = iso8601_local_noms(currentBestLocation.time)
if (shouldCreateNotificationChannel()) if (shouldCreateNotificationChannel())
{ {
createNotificationChannel() createNotificationChannel()
} }
notification_builder.setContentText(timestamp) if (location_interval == LOCATION_INTERVAL_SLEEP)
{
notification_builder.setContentText("${timestamp} (sleeping)")
}
else
{
notification_builder.setContentText(timestamp)
}
notification_builder.setWhen(currentBestLocation.time) notification_builder.setWhen(currentBestLocation.time)
if (trackingState == Keys.STATE_TRACKING_ACTIVE) if (trackingState == Keys.STATE_TRACKING_ACTIVE)
@ -400,8 +453,7 @@ class TrackerService: Service()
{ {
Log.i("VOUSSOIR", "TrackerService.onBind") Log.i("VOUSSOIR", "TrackerService.onBind")
bound = true bound = true
addGpsLocationListener() reset_location_listeners(interval=LOCATION_INTERVAL_FULLPOWER)
addNetworkLocationListener()
return binder return binder
} }
@ -410,8 +462,7 @@ class TrackerService: Service()
{ {
Log.i("VOUSSOIR", "TrackerService.onRebind") Log.i("VOUSSOIR", "TrackerService.onRebind")
bound = true bound = true
addGpsLocationListener() reset_location_listeners(interval=LOCATION_INTERVAL_FULLPOWER)
addNetworkLocationListener()
} }
/* Overrides onUnbind from Service */ /* Overrides onUnbind from Service */
@ -466,6 +517,31 @@ class TrackerService: Service()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int
{ {
Log.i("VOUSSOIR", "TrackerService.onStartCommand") Log.i("VOUSSOIR", "TrackerService.onStartCommand")
val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
sensor_manager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
significant_motion_sensor = sensor_manager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION)
if (significant_motion_sensor != null)
{
val triggerEventListener = object : TriggerEventListener() {
override fun onTrigger(event: TriggerEvent?) {
Log.i("VOUSSOIR", "Significant motion")
// beeper.startTone(ToneGenerator.TONE_PROP_ACK, 150)
vibrator.vibrate(50)
last_significant_motion = System.currentTimeMillis()
arrived_at_home = 0L
if (location_interval == LOCATION_INTERVAL_SLEEP)
{
reset_location_listeners(LOCATION_INTERVAL_FULLPOWER)
val mf = mapfragment
mf?.handler?.postDelayed(mf.location_update_redraw, 0)
}
sensor_manager.requestTriggerSensor(this, significant_motion_sensor)
}
}
sensor_manager.requestTriggerSensor(triggerEventListener, significant_motion_sensor)
}
// SERVICE RESTART (via START_STICKY) // SERVICE RESTART (via START_STICKY)
if (intent == null) if (intent == null)
{ {
@ -507,8 +583,8 @@ class TrackerService: Service()
fun startTracking() fun startTracking()
{ {
Log.i("VOUSSOIR", "TrackerService.startTracking") Log.i("VOUSSOIR", "TrackerService.startTracking")
addGpsLocationListener() arrived_at_home = 0
addNetworkLocationListener() reset_location_listeners(interval=LOCATION_INTERVAL_FULLPOWER)
trackingState = Keys.STATE_TRACKING_ACTIVE trackingState = Keys.STATE_TRACKING_ACTIVE
PreferencesHelper.saveTrackingState(trackingState) PreferencesHelper.saveTrackingState(trackingState)
recent_displacement_locations.clear() recent_displacement_locations.clear()
@ -519,7 +595,8 @@ class TrackerService: Service()
{ {
Log.i("VOUSSOIR", "TrackerService.stopTracking") Log.i("VOUSSOIR", "TrackerService.stopTracking")
trackbook.database.commit() trackbook.database.commit()
arrived_at_home = 0
reset_location_listeners(interval=LOCATION_INTERVAL_FULLPOWER)
trackingState = Keys.STATE_TRACKING_STOPPED trackingState = Keys.STATE_TRACKING_STOPPED
PreferencesHelper.saveTrackingState(trackingState) PreferencesHelper.saveTrackingState(trackingState)
recent_displacement_locations.clear() recent_displacement_locations.clear()
@ -533,26 +610,12 @@ class TrackerService: Service()
Keys.PREF_LOCATION_GPS -> Keys.PREF_LOCATION_GPS ->
{ {
use_gps_location = PreferencesHelper.load_location_gps() use_gps_location = PreferencesHelper.load_location_gps()
if (use_gps_location) reset_location_listeners(interval=LOCATION_INTERVAL_FULLPOWER)
{
addGpsLocationListener()
}
else
{
removeGpsLocationListener()
}
} }
Keys.PREF_LOCATION_NETWORK -> Keys.PREF_LOCATION_NETWORK ->
{ {
use_network_location = PreferencesHelper.load_location_network() use_network_location = PreferencesHelper.load_location_network()
if (use_network_location) reset_location_listeners(interval=LOCATION_INTERVAL_FULLPOWER)
{
addNetworkLocationListener()
}
else
{
removeNetworkLocationListener()
}
} }
Keys.PREF_USE_IMPERIAL_UNITS -> Keys.PREF_USE_IMPERIAL_UNITS ->
{ {

View File

@ -20,16 +20,10 @@ fun iso8601_local(timestamp: Long): String
return iso8601_format.format(timestamp) return iso8601_format.format(timestamp)
} }
fun iso8601(datetime: Date): String fun iso8601_local_noms(timestamp: Long): String
{ {
return iso8601(datetime.time) val iso8601_format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
} return iso8601_format.format(timestamp)
fun iso8601_parse(datetime: String): Date
{
val iso8601_format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
iso8601_format.timeZone = TimeZone.getTimeZone("UTC")
return iso8601_format.parse(datetime)
} }
fun random_int(): Int fun random_int(): Int

View File

@ -0,0 +1,13 @@
<!--
Thank you
https://pictogrammers.com/library/mdi/icon/satellite-variant/
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="@color/icon_default"
android:pathData="M11.62,1L17.28,6.67L15.16,8.79L13.04,6.67L11.62,8.09L13.95,10.41L12.79,11.58L13.24,12.04C14.17,11.61 15.31,11.77 16.07,12.54L12.54,16.07C11.77,15.31 11.61,14.17 12.04,13.24L11.58,12.79L10.41,13.95L8.09,11.62L6.67,13.04L8.79,15.16L6.67,17.28L1,11.62L3.14,9.5L5.26,11.62L6.67,10.21L3.84,7.38C3.06,6.6 3.06,5.33 3.84,4.55L4.55,3.84C5.33,3.06 6.6,3.06 7.38,3.84L10.21,6.67L11.62,5.26L9.5,3.14L11.62,1M18,14A4,4 0 0,1 14,18V16A2,2 0 0,0 16,14H18M22,14A8,8 0 0,1 14,22V20A6,6 0 0,0 20,14H22Z" />
</vector>

View File

@ -0,0 +1,14 @@
<!--
Thank you
https://pictogrammers.com/library/mdi/icon/sleep/
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/icon_default"
android:pathData="M23,12H17V10L20.39,6H17V4H23V6L19.62,10H23V12M15,16H9V14L12.39,10H9V8H15V10L11.62,14H15V16M7,20H1V18L4.39,14H1V12H7V14L3.62,18H7V20Z" />
</vector>

View File

@ -87,6 +87,29 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:tint="@color/location_button_icon" /> app:tint="@color/location_button_icon" />
<TextView
android:id="@+id/map_current_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<ImageButton
android:id="@+id/power_level_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:src="@drawable/ic_satellite_24dp"
app:backgroundTint="@color/default_transparent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_satellite_24dp"
app:tint="@color/location_button_icon" />
<!-- GROUPS --> <!-- GROUPS -->
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>