Also watch step counter movement, notification icon by status.
This commit is contained in:
parent
59389accc5
commit
6ad4c2dbe5
7 changed files with 178 additions and 154 deletions
|
@ -5,6 +5,7 @@
|
|||
<!-- USE GPS AND NETWORK - EXCLUDE NON-GPS DEVICES -->
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="true" />
|
||||
<uses-feature android:name="android.hardware.location.network" />
|
||||
<uses-feature android:name="android.hardware.sensor.stepcounter" />
|
||||
|
||||
<!-- NORMAL PERMISSIONS, automatically granted -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
@ -15,6 +16,7 @@
|
|||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
|
||||
<!-- DANGEROUS PERMISSIONS, must request -->
|
||||
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
|
|
@ -26,6 +26,11 @@ object Keys {
|
|||
// application name
|
||||
const val APPLICATION_NAME: String = "trkpt"
|
||||
|
||||
// axioms
|
||||
const val ONE_SECOND_IN_MILLISECONDS: Long = 1000
|
||||
const val ONE_MINUTE_IN_MILLISECONDS: Long = 60 * ONE_SECOND_IN_MILLISECONDS
|
||||
const val ONE_HOUR_IN_MILLISECONDS: Long = 60 * ONE_MINUTE_IN_MILLISECONDS
|
||||
|
||||
// version numbers
|
||||
const val CURRENT_TRACK_FORMAT_VERSION: Int = 4
|
||||
const val DATABASE_VERSION: Int = 1
|
||||
|
@ -63,6 +68,9 @@ object Keys {
|
|||
// states
|
||||
const val STATE_TRACKING_STOPPED: Int = 0
|
||||
const val STATE_TRACKING_ACTIVE: Int = 1
|
||||
const val LOCATION_INTERVAL_FULL_POWER: Long = 0
|
||||
const val LOCATION_INTERVAL_SLEEP: Long = ONE_MINUTE_IN_MILLISECONDS
|
||||
const val LOCATION_INTERVAL_GIVE_UP: 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"
|
||||
|
@ -85,9 +93,6 @@ object Keys {
|
|||
|
||||
// default values
|
||||
val DEFAULT_DATE: Date = Date(0L)
|
||||
const val ONE_SECOND_IN_MILLISECONDS: Long = 1000
|
||||
const val ONE_MINUTE_IN_MILLISECONDS: Long = 60 * ONE_SECOND_IN_MILLISECONDS
|
||||
const val ONE_HOUR_IN_MILLISECONDS: Long = 60 * ONE_MINUTE_IN_MILLISECONDS
|
||||
const val EMPTY_STRING_RESOURCE: Int = 0
|
||||
const val REQUEST_CURRENT_LOCATION_INTERVAL: Long = 1 * ONE_SECOND_IN_MILLISECONDS
|
||||
const val SAVE_TEMP_TRACK_INTERVAL: Long = 30 * ONE_SECOND_IN_MILLISECONDS
|
||||
|
|
|
@ -107,6 +107,7 @@ class MainActivity: AppCompatActivity()
|
|||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.ACTIVITY_RECOGNITION,
|
||||
)
|
||||
val permissions_needed = ArrayList<String>()
|
||||
for (permission in permissions_wanted)
|
||||
|
|
|
@ -71,7 +71,6 @@ class MapFragment : Fragment()
|
|||
lateinit var zoom_out_button: 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_position_overlays = ArrayList<Overlay>()
|
||||
private var homepoints_overlays = ArrayList<Overlay>()
|
||||
|
@ -113,7 +112,6 @@ class MapFragment : Fragment()
|
|||
zoom_in_button = rootView.findViewById(R.id.zoom_in_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)
|
||||
locationErrorBar = Snackbar.make(mapView, String(), Snackbar.LENGTH_INDEFINITE)
|
||||
|
||||
|
@ -390,38 +388,74 @@ class MapFragment : Fragment()
|
|||
}
|
||||
|
||||
/* Mark current position on map */
|
||||
fun create_current_position_overlays(location: Location, trackingState: Int = Keys.STATE_TRACKING_STOPPED)
|
||||
fun create_current_position_overlays()
|
||||
{
|
||||
clear_current_position_overlays()
|
||||
|
||||
val locationIsOld: Boolean = !(isRecentEnough(location))
|
||||
val tracker = trackerService
|
||||
if (tracker == null)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
val locationIsOld: Boolean = !(isRecentEnough(tracker.currentBestLocation))
|
||||
|
||||
val newMarker: Drawable
|
||||
val fillcolor: Int
|
||||
if (locationIsOld)
|
||||
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_GIVE_UP)
|
||||
{
|
||||
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)
|
||||
{
|
||||
fillcolor = Color.argb(64, 220, 61, 51)
|
||||
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_sleep_24dp)!!
|
||||
description = "GPS sleeping until movement"
|
||||
}
|
||||
else if (locationIsOld)
|
||||
{
|
||||
fillcolor = Color.argb(64, 0, 0, 0)
|
||||
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_black_24dp)!!
|
||||
description = "GPS tracking at full power"
|
||||
}
|
||||
else if (trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
else if (tracker.trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
{
|
||||
fillcolor = Color.argb(64, 220, 61, 51)
|
||||
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_red_24dp)!!
|
||||
description = "GPS tracking at full power"
|
||||
}
|
||||
else
|
||||
{
|
||||
fillcolor = Color.argb(64, 60, 152, 219)
|
||||
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_blue_24dp)!!
|
||||
description = "GPS tracking at full power"
|
||||
}
|
||||
|
||||
val current_location_radius = Polygon()
|
||||
current_location_radius.points = Polygon.pointsAsCircle(GeoPoint(location.latitude, location.longitude), location.accuracy.toDouble())
|
||||
current_location_radius.points = Polygon.pointsAsCircle(
|
||||
GeoPoint(tracker.currentBestLocation.latitude, tracker.currentBestLocation.longitude),
|
||||
tracker.currentBestLocation.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(requireContext(), location.latitude, location.longitude, location.accuracy, location.provider.toString(), location.time)
|
||||
val overlayItem: OverlayItem = createOverlayItem(
|
||||
tracker.currentBestLocation.latitude,
|
||||
tracker.currentBestLocation.longitude,
|
||||
title="Current location",
|
||||
description=description,
|
||||
)
|
||||
overlayItem.setMarker(newMarker)
|
||||
overlayItems.add(overlayItem)
|
||||
current_position_overlays.add(createOverlay(requireContext(), overlayItems))
|
||||
|
@ -478,12 +512,10 @@ class MapFragment : Fragment()
|
|||
|
||||
val overlayItems: java.util.ArrayList<OverlayItem> = java.util.ArrayList<OverlayItem>()
|
||||
val overlayItem: OverlayItem = createOverlayItem(
|
||||
context,
|
||||
homepoint.location.latitude,
|
||||
homepoint.location.longitude,
|
||||
homepoint.location.accuracy,
|
||||
homepoint.location.provider.toString(),
|
||||
homepoint.location.time
|
||||
title=homepoint.name,
|
||||
description="Radius ${homepoint.radius}"
|
||||
)
|
||||
overlayItem.setMarker(newMarker)
|
||||
overlayItems.add(overlayItem)
|
||||
|
@ -615,7 +647,7 @@ class MapFragment : Fragment()
|
|||
{
|
||||
return
|
||||
}
|
||||
create_current_position_overlays(tracker.currentBestLocation, tracker.trackingState)
|
||||
create_current_position_overlays()
|
||||
if (current_track_overlay == null)
|
||||
{
|
||||
create_track_overlay()
|
||||
|
@ -629,28 +661,7 @@ class MapFragment : Fragment()
|
|||
|
||||
map_current_time.text = iso8601_local_noms(tracker.currentBestLocation.time)
|
||||
|
||||
|
||||
if (tracker.location_interval == tracker.LOCATION_INTERVAL_FULL_POWER)
|
||||
{
|
||||
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 if (tracker.location_interval == tracker.LOCATION_INTERVAL_GIVE_UP)
|
||||
{
|
||||
power_level_indicator.setImageResource(R.drawable.ic_skull_24dp)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
power_level_indicator.tooltipText = "GPS is struggling; disabled until movement"
|
||||
}
|
||||
}
|
||||
mapView.invalidate()
|
||||
}
|
||||
|
||||
val redraw_runnable: Runnable = object : Runnable
|
||||
|
|
|
@ -31,10 +31,7 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.PackageManager
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorManager
|
||||
import android.hardware.TriggerEvent
|
||||
import android.hardware.TriggerEventListener
|
||||
import android.hardware.*
|
||||
import android.location.Location
|
||||
import android.location.LocationListener
|
||||
import android.location.LocationManager
|
||||
|
@ -68,9 +65,9 @@ class TrackerService: Service()
|
|||
var last_significant_motion: Long = 0
|
||||
var arrived_at_home: Long = 0
|
||||
var location_interval: Long = 0
|
||||
val LOCATION_INTERVAL_FULL_POWER: Long = 0
|
||||
val LOCATION_INTERVAL_SLEEP: Long = Keys.ONE_MINUTE_IN_MILLISECONDS
|
||||
val LOCATION_INTERVAL_GIVE_UP: Long = -1
|
||||
val TIME_UNTIL_SLEEP: Long = 2 * Keys.ONE_MINUTE_IN_MILLISECONDS
|
||||
val TIME_UNTIL_GIVE_UP: Long = 3 * Keys.ONE_MINUTE_IN_MILLISECONDS
|
||||
val WATCHDOG_INTERVAL: Long = 30 * Keys.ONE_SECOND_IN_MILLISECONDS
|
||||
private val RECENT_TRKPT_COUNT = 3600
|
||||
private val DISPLACEMENT_LOCATION_COUNT = 5
|
||||
lateinit var recent_displacement_locations: Deque<Location>
|
||||
|
@ -94,27 +91,23 @@ class TrackerService: Service()
|
|||
|
||||
private lateinit var sensor_manager: SensorManager
|
||||
private var significant_motion_sensor: Sensor? = null
|
||||
private var step_counter_sensor: Sensor? = null
|
||||
var has_motion_sensor: Boolean = false
|
||||
|
||||
private fun addGpsLocationListener(interval: Long)
|
||||
private fun addGpsLocationListener(interval: Long): Boolean
|
||||
{
|
||||
if (! use_gps_location)
|
||||
{
|
||||
Log.i("VOUSSOIR", "Skipping GPS listener.")
|
||||
return
|
||||
}
|
||||
|
||||
gpsProviderActive = isGpsEnabled(locationManager)
|
||||
if (! gpsProviderActive)
|
||||
{
|
||||
Log.w("VOUSSOIR", "Device GPS is not enabled.")
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
val has_permission: Boolean = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
if (! has_permission)
|
||||
{
|
||||
Log.w("VOUSSOIR", "Location permission is not granted.")
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
locationManager.requestLocationUpdates(
|
||||
|
@ -125,28 +118,23 @@ class TrackerService: Service()
|
|||
)
|
||||
gpsLocationListenerRegistered = true
|
||||
Log.i("VOUSSOIR", "Added GPS location listener.")
|
||||
return true
|
||||
}
|
||||
|
||||
private fun addNetworkLocationListener(interval: Long)
|
||||
private fun addNetworkLocationListener(interval: Long): Boolean
|
||||
{
|
||||
if (! use_network_location)
|
||||
{
|
||||
Log.i("VOUSSOIR", "Skipping Network listener.")
|
||||
return
|
||||
}
|
||||
|
||||
networkProviderActive = isNetworkEnabled(locationManager)
|
||||
if (!networkProviderActive)
|
||||
{
|
||||
Log.w("VOUSSOIR", "Unable to add Network location listener.")
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
val has_permission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
if (! has_permission)
|
||||
{
|
||||
Log.w("VOUSSOIR", "Unable to add Network location listener. Location permission is not granted.")
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
locationManager.requestLocationUpdates(
|
||||
|
@ -157,6 +145,7 @@ class TrackerService: Service()
|
|||
)
|
||||
networkLocationListenerRegistered = true
|
||||
Log.i("VOUSSOIR", "Added Network location listener.")
|
||||
return true
|
||||
}
|
||||
|
||||
fun removeGpsLocationListener()
|
||||
|
@ -193,19 +182,17 @@ class TrackerService: Service()
|
|||
location_interval = interval
|
||||
var gps_added = false
|
||||
var network_added = false
|
||||
if (use_gps_location && interval != LOCATION_INTERVAL_GIVE_UP)
|
||||
if (use_gps_location && interval != Keys.LOCATION_INTERVAL_GIVE_UP)
|
||||
{
|
||||
addGpsLocationListener(interval)
|
||||
gps_added = true
|
||||
gps_added = addGpsLocationListener(interval)
|
||||
}
|
||||
else if (gpsLocationListenerRegistered)
|
||||
{
|
||||
removeGpsLocationListener()
|
||||
}
|
||||
if (use_network_location && interval != LOCATION_INTERVAL_GIVE_UP)
|
||||
if (use_network_location && interval != Keys.LOCATION_INTERVAL_GIVE_UP)
|
||||
{
|
||||
addNetworkLocationListener(interval)
|
||||
network_added = true
|
||||
network_added = addNetworkLocationListener(interval)
|
||||
}
|
||||
else if (networkLocationListenerRegistered)
|
||||
{
|
||||
|
@ -219,7 +206,9 @@ class TrackerService: Service()
|
|||
else
|
||||
{
|
||||
listeners_enabled_at = 0
|
||||
location_interval = Keys.LOCATION_INTERVAL_GIVE_UP
|
||||
}
|
||||
displayNotification()
|
||||
}
|
||||
|
||||
private fun createLocationListener(): LocationListener
|
||||
|
@ -277,16 +266,20 @@ class TrackerService: Service()
|
|||
Log.i("VOUSSOIR", "Arrived at home.")
|
||||
arrived_at_home = System.currentTimeMillis()
|
||||
}
|
||||
else if (location_interval == LOCATION_INTERVAL_SLEEP || significant_motion_sensor == null)
|
||||
else if (location_interval == Keys.LOCATION_INTERVAL_SLEEP)
|
||||
{
|
||||
// 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 (allow_sleep && (System.currentTimeMillis() - arrived_at_home) > Keys.ONE_MINUTE_IN_MILLISECONDS)
|
||||
else if (
|
||||
allow_sleep &&
|
||||
has_motion_sensor &&
|
||||
(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=LOCATION_INTERVAL_SLEEP)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_SLEEP)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -295,7 +288,7 @@ class TrackerService: Service()
|
|||
{
|
||||
Log.i("VOUSSOIR", "Leaving home.")
|
||||
arrived_at_home = 0
|
||||
reset_location_listeners(interval=LOCATION_INTERVAL_FULL_POWER)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
}
|
||||
|
||||
if (! isRecentEnough(location))
|
||||
|
@ -365,31 +358,41 @@ class TrackerService: Service()
|
|||
|
||||
private fun displayNotification(): Notification
|
||||
{
|
||||
val timestamp = iso8601_local_noms(currentBestLocation.time)
|
||||
notification_builder.setWhen(currentBestLocation.time)
|
||||
if (shouldCreateNotificationChannel())
|
||||
{
|
||||
createNotificationChannel()
|
||||
}
|
||||
|
||||
if (location_interval == LOCATION_INTERVAL_SLEEP)
|
||||
{
|
||||
notification_builder.setContentText("${timestamp} (sleeping)")
|
||||
}
|
||||
else
|
||||
{
|
||||
notification_builder.setContentText(timestamp)
|
||||
}
|
||||
notification_builder.setWhen(currentBestLocation.time)
|
||||
|
||||
val timestamp = iso8601_local_noms(currentBestLocation.time)
|
||||
if (trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
{
|
||||
notification_builder.setContentTitle(this.getString(R.string.notification_title_trackbook_running))
|
||||
notification_builder.setLargeIcon(AppCompatResources.getDrawable(this, R.drawable.ic_notification_icon_large_tracking_active_48dp)!!.toBitmap())
|
||||
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_GIVE_UP)
|
||||
{
|
||||
notification_builder.setContentTitle("${timestamp} (deadzone)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_skull_24dp)
|
||||
}
|
||||
else
|
||||
{
|
||||
notification_builder.setContentText(timestamp)
|
||||
notification_builder.setSmallIcon(R.drawable.ic_fiber_manual_record_inactive_24dp)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
notification_builder.setContentTitle(this.getString(R.string.notification_title_trackbook_not_running))
|
||||
notification_builder.setLargeIcon(AppCompatResources.getDrawable(this, R.drawable.ic_notification_icon_large_tracking_stopped_48dp)!!.toBitmap())
|
||||
notification_builder.setContentTitle("${timestamp} (stopped)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_fiber_manual_stop_24dp)
|
||||
}
|
||||
|
||||
val notification = notification_builder.build()
|
||||
|
@ -452,8 +455,9 @@ class TrackerService: Service()
|
|||
Log.i("VOUSSOIR", "TrackerService.onBind")
|
||||
if (listeners_enabled_at == 0L)
|
||||
{
|
||||
reset_location_listeners(interval=LOCATION_INTERVAL_FULL_POWER)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
}
|
||||
displayNotification()
|
||||
bound = true
|
||||
return binder
|
||||
}
|
||||
|
@ -464,8 +468,9 @@ class TrackerService: Service()
|
|||
Log.i("VOUSSOIR", "TrackerService.onRebind")
|
||||
if (listeners_enabled_at == 0L)
|
||||
{
|
||||
reset_location_listeners(interval=LOCATION_INTERVAL_FULL_POWER)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
}
|
||||
displayNotification()
|
||||
bound = true
|
||||
}
|
||||
|
||||
|
@ -478,7 +483,7 @@ class TrackerService: Service()
|
|||
// stop receiving location updates - if not tracking
|
||||
if (trackingState != Keys.STATE_TRACKING_ACTIVE)
|
||||
{
|
||||
reset_location_listeners(LOCATION_INTERVAL_GIVE_UP)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_GIVE_UP)
|
||||
}
|
||||
// ensures onRebind is called
|
||||
return true
|
||||
|
@ -516,6 +521,52 @@ class TrackerService: Service()
|
|||
currentBestLocation = getLastKnownLocation(this)
|
||||
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||
|
||||
val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
has_motion_sensor = false
|
||||
sensor_manager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
||||
significant_motion_sensor = sensor_manager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION)
|
||||
if (significant_motion_sensor != null)
|
||||
{
|
||||
val significant_motion_listener = object : TriggerEventListener() {
|
||||
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)
|
||||
{
|
||||
vibrator.vibrate(100)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
}
|
||||
sensor_manager.requestTriggerSensor(this, significant_motion_sensor)
|
||||
}
|
||||
}
|
||||
Log.i("VOUSSOIR", "Got significant motion sensor.")
|
||||
sensor_manager.requestTriggerSensor(significant_motion_listener, significant_motion_sensor)
|
||||
has_motion_sensor = true
|
||||
}
|
||||
|
||||
step_counter_sensor = sensor_manager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
|
||||
if (step_counter_sensor != null)
|
||||
{
|
||||
val step_counter_listener = object: SensorEventListener {
|
||||
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)
|
||||
{
|
||||
// beeper.startTone(ToneGenerator.TONE_PROP_ACK, 150)
|
||||
vibrator.vibrate(100)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAccuracyChanged(p0: Sensor?, p1: Int) {
|
||||
}
|
||||
}
|
||||
Log.i("VOUSSOIR", "Got step count sensor.")
|
||||
sensor_manager.registerListener(step_counter_listener, step_counter_sensor, 5_000_000, 5_000_000)
|
||||
has_motion_sensor = true
|
||||
}
|
||||
|
||||
handler.post(background_watchdog)
|
||||
}
|
||||
|
||||
|
@ -524,28 +575,6 @@ class TrackerService: Service()
|
|||
{
|
||||
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")
|
||||
last_significant_motion = System.currentTimeMillis()
|
||||
arrived_at_home = 0L
|
||||
if (location_interval != LOCATION_INTERVAL_FULL_POWER)
|
||||
{
|
||||
// beeper.startTone(ToneGenerator.TONE_PROP_ACK, 150)
|
||||
vibrator.vibrate(100)
|
||||
reset_location_listeners(LOCATION_INTERVAL_FULL_POWER)
|
||||
}
|
||||
sensor_manager.requestTriggerSensor(this, significant_motion_sensor)
|
||||
}
|
||||
}
|
||||
sensor_manager.requestTriggerSensor(triggerEventListener, significant_motion_sensor)
|
||||
}
|
||||
|
||||
// SERVICE RESTART (via START_STICKY)
|
||||
if (intent == null)
|
||||
{
|
||||
|
@ -580,7 +609,7 @@ class TrackerService: Service()
|
|||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
notificationManager.cancel(Keys.TRACKER_SERVICE_NOTIFICATION_ID) // this call was not necessary prior to Android 12
|
||||
PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||
reset_location_listeners(LOCATION_INTERVAL_GIVE_UP)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_GIVE_UP)
|
||||
handler.removeCallbacks(background_watchdog)
|
||||
}
|
||||
|
||||
|
@ -588,7 +617,7 @@ class TrackerService: Service()
|
|||
{
|
||||
Log.i("VOUSSOIR", "TrackerService.startTracking")
|
||||
arrived_at_home = 0
|
||||
reset_location_listeners(interval=LOCATION_INTERVAL_FULL_POWER)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
trackingState = Keys.STATE_TRACKING_ACTIVE
|
||||
PreferencesHelper.saveTrackingState(trackingState)
|
||||
recent_displacement_locations.clear()
|
||||
|
@ -600,7 +629,7 @@ class TrackerService: Service()
|
|||
Log.i("VOUSSOIR", "TrackerService.stopTracking")
|
||||
trackbook.database.commit()
|
||||
arrived_at_home = 0
|
||||
reset_location_listeners(interval=LOCATION_INTERVAL_FULL_POWER)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
trackingState = Keys.STATE_TRACKING_STOPPED
|
||||
PreferencesHelper.saveTrackingState(trackingState)
|
||||
recent_displacement_locations.clear()
|
||||
|
@ -614,12 +643,12 @@ class TrackerService: Service()
|
|||
Keys.PREF_LOCATION_GPS ->
|
||||
{
|
||||
use_gps_location = PreferencesHelper.load_location_gps()
|
||||
reset_location_listeners(interval=LOCATION_INTERVAL_FULL_POWER)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
}
|
||||
Keys.PREF_LOCATION_NETWORK ->
|
||||
{
|
||||
use_network_location = PreferencesHelper.load_location_network()
|
||||
reset_location_listeners(interval=LOCATION_INTERVAL_FULL_POWER)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
}
|
||||
Keys.PREF_USE_IMPERIAL_UNITS ->
|
||||
{
|
||||
|
@ -632,9 +661,9 @@ class TrackerService: Service()
|
|||
Keys.PREF_ALLOW_SLEEP ->
|
||||
{
|
||||
allow_sleep = PreferencesHelper.loadAllowSleep()
|
||||
if (! allow_sleep && location_interval != LOCATION_INTERVAL_FULL_POWER)
|
||||
if (! allow_sleep && location_interval != Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
{
|
||||
reset_location_listeners(LOCATION_INTERVAL_FULL_POWER)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
}
|
||||
}
|
||||
Keys.PREF_DEVICE_ID ->
|
||||
|
@ -649,28 +678,19 @@ class TrackerService: Service()
|
|||
override fun run()
|
||||
{
|
||||
Log.i("VOUSSOIR", "TrackerService.background_watchdog")
|
||||
handler.postDelayed(this, 30 * Keys.ONE_SECOND_IN_MILLISECONDS)
|
||||
handler.postDelayed(this, WATCHDOG_INTERVAL)
|
||||
val now = System.currentTimeMillis()
|
||||
val struggletime: Long
|
||||
if (location_interval == LOCATION_INTERVAL_FULL_POWER)
|
||||
{
|
||||
struggletime = 2 * Keys.ONE_MINUTE_IN_MILLISECONDS
|
||||
}
|
||||
else
|
||||
{
|
||||
struggletime = 4 * Keys.ONE_MINUTE_IN_MILLISECONDS
|
||||
}
|
||||
if (
|
||||
allow_sleep &&
|
||||
has_motion_sensor &&
|
||||
trackingState == Keys.STATE_TRACKING_ACTIVE &&
|
||||
location_interval != LOCATION_INTERVAL_GIVE_UP &&
|
||||
significant_motion_sensor != null &&
|
||||
(now - listeners_enabled_at) > struggletime &&
|
||||
(now - currentBestLocation.time) > struggletime &&
|
||||
(now - last_significant_motion) > struggletime
|
||||
location_interval != Keys.LOCATION_INTERVAL_GIVE_UP &&
|
||||
(now - listeners_enabled_at) > TIME_UNTIL_GIVE_UP &&
|
||||
(now - currentBestLocation.time) > TIME_UNTIL_GIVE_UP &&
|
||||
(now - last_significant_motion) > TIME_UNTIL_GIVE_UP
|
||||
)
|
||||
{
|
||||
reset_location_listeners(LOCATION_INTERVAL_GIVE_UP)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_GIVE_UP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,12 +34,12 @@ fun create_start_end_markers(context: Context, map_view: MapView, startpoint: Tr
|
|||
{
|
||||
Log.i("VOUSSOIR", "MapOverlayHelper.create_start_end_markers")
|
||||
val overlayItems: ArrayList<OverlayItem> = ArrayList<OverlayItem>()
|
||||
val startmarker: OverlayItem = createOverlayItem(context, startpoint.latitude, startpoint.longitude, startpoint.accuracy, startpoint.provider, startpoint.time)
|
||||
val startmarker: OverlayItem = createOverlayItem(startpoint.latitude, startpoint.longitude, title="Start", iso8601_local_noms(startpoint.time))
|
||||
startmarker.setMarker(ContextCompat.getDrawable(context, R.drawable.ic_marker_track_start_48dp)!!)
|
||||
overlayItems.add(startmarker)
|
||||
if (startpoint != endpoint)
|
||||
{
|
||||
val endmarker: OverlayItem = createOverlayItem(context, endpoint.latitude, endpoint.longitude, endpoint.accuracy, endpoint.provider, endpoint.time)
|
||||
val endmarker: OverlayItem = createOverlayItem(endpoint.latitude, endpoint.longitude, title="End", description= iso8601_local_noms(endpoint.time))
|
||||
endmarker.setMarker(ContextCompat.getDrawable(context, R.drawable.ic_marker_track_end_48dp)!!)
|
||||
overlayItems.add(endmarker)
|
||||
}
|
||||
|
@ -48,10 +48,8 @@ fun create_start_end_markers(context: Context, map_view: MapView, startpoint: Tr
|
|||
return overlay
|
||||
}
|
||||
|
||||
fun createOverlayItem(context: Context, latitude: Double, longitude: Double, accuracy: Float, provider: String, time: Long): OverlayItem
|
||||
fun createOverlayItem(latitude: Double, longitude: Double, title: String, description: String): OverlayItem
|
||||
{
|
||||
val title = "${context.getString(R.string.marker_description_time)}: ${SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()).format(time)}"
|
||||
val description = "${context.getString(R.string.marker_description_time)}: ${SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()).format(time)} | ${context.getString(R.string.marker_description_accuracy)}: ${DecimalFormat("#0.00").format(accuracy)} (${provider})"
|
||||
val position = GeoPoint(latitude, longitude)
|
||||
val item = OverlayItem(title, description, position)
|
||||
item.markerHotspot = OverlayItem.HotspotPlace.CENTER
|
||||
|
|
|
@ -97,19 +97,6 @@
|
|||
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 -->
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
Loading…
Reference in a new issue