From 7c0e9f44f58575102db1cd3ccdb6315e9e0dce5f Mon Sep 17 00:00:00 2001 From: wir3z Date: Mon, 3 Nov 2025 18:27:21 -0700 Subject: [PATCH 1/7] Added an address field to the returned location packet. Contains the geocoded address, if available, or the lat/lon if not. --- .../org/owntracks/android/model/messages/MessageLocation.kt | 2 ++ .../java/org/owntracks/android/services/BackgroundService.kt | 5 +++++ .../java/org/owntracks/android/services/LocationProcessor.kt | 2 ++ 3 files changed, 9 insertions(+) diff --git a/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt b/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt index 58e71d394d..b003f18c0c 100644 --- a/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt +++ b/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt @@ -70,6 +70,8 @@ open class MessageLocation( @JsonInclude(JsonInclude.Include.NON_NULL) @JsonProperty("tid") var trackerId: String? = null + @JsonProperty("address") var address: String? = null + override fun isValidMessage(): Boolean { return timestamp > 0 } diff --git a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt index 8da1f30998..805024f9e7 100644 --- a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt +++ b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt @@ -594,6 +594,11 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList if (latLng == lastLocation?.toLatLng()) { Timber.v("New reverse geocode for $latLng: $reverseGeocodedText") + if (lastLocation != null) { + reverseGeocodedText.ifBlank { lastLocation!!.toLatLng().toDisplayString() } + locationProcessor.lastAddress = reverseGeocodedText + } + if (lastLocation != null && preferences.notificationLocation) { reverseGeocodedText.ifBlank { lastLocation!!.toLatLng().toDisplayString() } } else { diff --git a/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt b/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt index 3578dbf36f..205d8adac3 100644 --- a/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt +++ b/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt @@ -51,6 +51,7 @@ constructor( @Named("mockLocationIdlingResource") private val mockLocationIdlingResource: SimpleIdlingResource ) { + var lastAddress: String? = null private fun locationIsWithAccuracyThreshold(l: Location): Boolean = preferences.ignoreInaccurateLocations .run { preferences.ignoreInaccurateLocations == 0 || l.accuracy < this } @@ -139,6 +140,7 @@ constructor( this.trigger = trigger trackerId = preferences.tid.toString() inregions = calculateInRegions(loadedWaypoints) + address = lastAddress } Timber.v("Actually publishing location $location triggered by $trigger as message=$message") messageProcessor.queueMessageForSending(message) From dfa299859b9646f4340bc14793136dd5268e3eb8 Mon Sep 17 00:00:00 2001 From: wir3z Date: Tue, 4 Nov 2025 06:29:51 -0700 Subject: [PATCH 2/7] Updated formatting. --- .../android/model/messages/MessageLocation.kt | 11 +- .../android/services/BackgroundService.kt | 147 ++++++++++++------ .../android/services/LocationProcessor.kt | 92 +++++++---- 3 files changed, 168 insertions(+), 82 deletions(-) diff --git a/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt b/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt index b003f18c0c..a8132b31a2 100644 --- a/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt +++ b/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt @@ -19,12 +19,15 @@ import org.owntracks.android.preferences.Preferences import org.owntracks.android.preferences.types.MonitoringMode @JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "_type") + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXTERNAL_PROPERTY, + property = "_type", +) @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_EMPTY) open class MessageLocation( private val messageWithCreatedAtImpl: MessageWithCreatedAt = MessageCreatedAtNow(RealClock()), - private val messageWithId: MessageWithId = MessageWithRandomId() + private val messageWithId: MessageWithId = MessageWithRandomId(), ) : MessageBase(), MessageWithCreatedAt by messageWithCreatedAtImpl, @@ -110,7 +113,7 @@ open class MessageLocation( @JvmStatic fun fromLocationAndWifiInfo( location: @NotNull Location, - wifiInfoProvider: WifiInfoProvider + wifiInfoProvider: WifiInfoProvider, ): @NotNull MessageLocation = if (wifiInfoProvider.isConnected()) { fromLocation(location).apply { @@ -136,6 +139,6 @@ open class MessageLocation( BEACON("b"), // Generated by iOS beacons IOS_FREQUENT_LOCATIONS("v"), // Generated by iOS frequent locations IOS_FOLLOW_CIRCULAR("C"), // Generated by iOS follow circular region - DEFAULT("") + DEFAULT(""), } } diff --git a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt index 805024f9e7..d141a396dd 100644 --- a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt +++ b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt @@ -157,15 +157,19 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList endpointStateRepo = entrypoint.endpointStateRepo() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { Timber.v( - "Permissions. ACCESS_BACKGROUND_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)==PERMISSION_GRANTED}") + "Permissions. ACCESS_BACKGROUND_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)==PERMISSION_GRANTED}" + ) } Timber.v( - "Permissions. ACCESS_COARSE_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)==PERMISSION_GRANTED}") + "Permissions. ACCESS_COARSE_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)==PERMISSION_GRANTED}" + ) Timber.v( - "Permissions. ACCESS_FINE_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)==PERMISSION_GRANTED}") + "Permissions. ACCESS_FINE_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)==PERMISSION_GRANTED}" + ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { Timber.v( - "Permissions. POST_NOTIFICATIONS: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)==PERMISSION_GRANTED}") + "Permissions. POST_NOTIFICATIONS: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)==PERMISSION_GRANTED}" + ) } super.onCreate() @@ -182,7 +186,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList } addAction(Intent.ACTION_SCREEN_ON) addAction(Intent.ACTION_SCREEN_OFF) - }) + }, + ) powerStateLogger.logPowerState("serviceOnCreate") lifecycleScope.launch { @@ -222,7 +227,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList ongoingNotification.setEndpointState( it, if (preferences.mode == ConnectionMode.MQTT) preferences.host - else preferences.url.toHttpUrlOrNull()?.host ?: "") + else preferences.url.toHttpUrlOrNull()?.host ?: "", + ) } } endpointStateRepo.setServiceStartedNow() @@ -262,7 +268,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList if (requirementsChecker.hasLocationPermissions()) { locationProviderClient.singleHighAccuracyLocation( callbackForReportType[MessageLocation.ReportType.USER]!!.value, - runThingsOnOtherThreads.getBackgroundLooper()) + runThingsOnOtherThreads.getBackgroundLooper(), + ) } } return @@ -301,8 +308,9 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList INTENT_ACTION_BOOT_COMPLETED, INTENT_ACTION_PACKAGE_REPLACED -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - if (!requirementsChecker.hasBackgroundLocationPermission() && - !hasBeenStartedExplicitly) { + if ( + !requirementsChecker.hasBackgroundLocationPermission() && !hasBeenStartedExplicitly + ) { notifyUserOfBackgroundLocationRestriction() } } @@ -317,7 +325,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList } } else { Timber.d( - "no intent or action provided, setting up location request and scheduling location ping.") + "no intent or action provided, setting up location request and scheduling location ping." + ) hasBeenStartedExplicitly = true setupAndStartService() } @@ -329,18 +338,21 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList startForeground( NOTIFICATION_ID_ONGOING, ongoingNotification.getNotification(), - FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE) + FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, + ) } catch (e: ForegroundServiceStartNotAllowedException) { Timber.e( e, - "Foreground service start not allowed. backgroundRestricted=${activityManager.isBackgroundRestricted}") + "Foreground service start not allowed. backgroundRestricted=${activityManager.isBackgroundRestricted}", + ) return } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { startForeground( NOTIFICATION_ID_ONGOING, ongoingNotification.getNotification(), - FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE) + FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, + ) } else { startForeground(NOTIFICATION_ID_ONGOING, ongoingNotification.getNotification()) } @@ -362,8 +374,10 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList } private fun notifyUserOfBackgroundLocationRestriction() { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != - PackageManager.PERMISSION_GRANTED) { + if ( + ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != + PackageManager.PERMISSION_GRANTED + ) { return } val activityLaunchIntent = @@ -375,7 +389,9 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList val notificationTitle = getString(R.string.backgroundLocationRestrictionNotificationTitle) val notification = NotificationCompat.Builder( - applicationContext, GeocoderProvider.ERROR_NOTIFICATION_CHANNEL_ID) + applicationContext, + GeocoderProvider.ERROR_NOTIFICATION_CHANNEL_ID, + ) .setContentTitle(notificationTitle) .setContentText(notificationText) .setAutoCancel(true) @@ -383,19 +399,29 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList .setStyle(NotificationCompat.BigTextStyle().bigText(notificationText)) .setContentIntent( PendingIntent.getActivity( - applicationContext, 0, activityLaunchIntent, UPDATE_CURRENT_INTENT_FLAGS)) + applicationContext, + 0, + activityLaunchIntent, + UPDATE_CURRENT_INTENT_FLAGS, + ) + ) .setPriority(NotificationCompat.PRIORITY_LOW) .setSilent(true) .build() notificationManagerCompat.notify( - BACKGROUND_LOCATION_RESTRICTION_NOTIFICATION_TAG, 0, notification) + BACKGROUND_LOCATION_RESTRICTION_NOTIFICATION_TAG, + 0, + notification, + ) } fun sendEventNotification(message: MessageTransition) { Timber.d("Sending event notification for $message") - if (!preferences.notificationEvents || - ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != - PackageManager.PERMISSION_GRANTED) { + if ( + !preferences.notificationEvents || + ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != + PackageManager.PERMISSION_GRANTED + ) { return } val contact = contactsRepo.getById(message.getContactId()) @@ -408,7 +434,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList R.string.transitionEntering } else { R.string.transitionLeaving - }) + } + ) val eventText = "$transitionText $location" val whenStr = formatDate(timestampInMs) // Need to lock to prevent "clear()" being called while we're adding to it @@ -420,14 +447,17 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList StyleSpan(Typeface.BOLD), 0, whenStr.length + 1, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - }) + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE, + ) + } + ) Timber.v("groupedNotifications: ${activeNotifications.size}") val summary = resources.getQuantityString( R.plurals.notificationEventsTitle, activeNotifications.size, - activeNotifications.size) + activeNotifications.size, + ) val inbox = NotificationCompat.InboxStyle().setSummaryText(summary) activeNotifications.forEach { inbox.addLine(it) } Pair(summary, inbox) @@ -453,14 +483,18 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList this, System.currentTimeMillis().toInt() / 1000, Intent(this, MapActivity::class.java), - UPDATE_CURRENT_INTENT_FLAGS)) + UPDATE_CURRENT_INTENT_FLAGS, + ) + ) .setDeleteIntent( PendingIntent.getService( this, 1, Intent(this, BackgroundService::class.java) .setAction(INTENT_ACTION_CLEAR_NOTIFICATIONS), - UPDATE_CURRENT_INTENT_FLAGS)) + UPDATE_CURRENT_INTENT_FLAGS, + ) + ) .build() .run { notificationManagerCompat @@ -479,9 +513,11 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList Timber.e("geofencingEvent hasError: ${event.errorCode}") return } - if (event.geofenceTransition == null || - event.triggeringGeofences == null || - event.triggeringLocation == null) { + if ( + event.geofenceTransition == null || + event.triggeringGeofences == null || + event.triggeringLocation == null + ) { Timber.e("geofencingEvent has no transition or trigger") return } @@ -493,7 +529,11 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList waypointsRepo.get(requestId.toLong())?.run { Timber.d("onWaypointTransition triggered by geofencing event") locationProcessor.onWaypointTransition( - this, event.triggeringLocation, transition, MessageTransition.TRIGGER_CIRCULAR) + this, + event.triggeringLocation, + transition, + MessageTransition.TRIGGER_CIRCULAR, + ) } ?: run { Timber.e("waypoint id $requestId not found for geofence event") } } catch (e: NumberFormatException) { Timber.e("$requestId from Geofencing event is not a valid request id") @@ -506,7 +546,9 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList if (requirementsChecker.hasLocationPermissions()) { Timber.d("On demand location request") locationProviderClient.singleHighAccuracyLocation( - callbackForReportType[reportType]!!.value, runThingsOnOtherThreads.getBackgroundLooper()) + callbackForReportType[reportType]!!.value, + runThingsOnOtherThreads.getBackgroundLooper(), + ) } else { Timber.e("missing location permission") } @@ -546,13 +588,21 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList } val request = LocationRequest( - fastestInterval, smallestDisplacement, null, null, priority, interval, null) + fastestInterval, + smallestDisplacement, + null, + null, + priority, + interval, + null, + ) Timber.d("location update request params: $request") locationProviderClient.flushLocations() locationProviderClient.requestLocationUpdates( request, callbackForReportType[MessageLocation.ReportType.DEFAULT]!!.value, - runThingsOnOtherThreads.getBackgroundLooper()) + runThingsOnOtherThreads.getBackgroundLooper(), + ) return Result.success(Unit) } else { return Result.failure(Exception("Missing location permission")) @@ -576,7 +626,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList it.geofenceLongitude, it.geofenceRadius.toFloat(), Geofence.NEVER_EXPIRE, - null) + null, + ) } .toList() geofencingClient.removeGeofences(this@BackgroundService) @@ -607,7 +658,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList .run(ongoingNotification::setTitle) } else { Timber.v( - "Ignoring reverse geocode for $latLng: $reverseGeocodedText, because my lastPublished location is ${lastLocation?.toLatLng()}") + "Ignoring reverse geocode for $latLng: $reverseGeocodedText, because my lastPublished location is ${lastLocation?.toLatLng()}" + ) } } @@ -619,12 +671,15 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList Preferences::moveModeLocatorInterval.name, Preferences::pegLocatorFastestIntervalToInterval.name, Preferences::notificationHigherPriority.name, - Preferences::locatorPriority.name) - if (propertiesWeCareAbout - .stream() - .filter { o: String -> properties.contains(o) } - .collect(Collectors.toSet()) - .isNotEmpty()) { + Preferences::locatorPriority.name, + ) + if ( + propertiesWeCareAbout + .stream() + .filter { o: String -> properties.contains(o) } + .collect(Collectors.toSet()) + .isNotEmpty() + ) { Timber.d("locator preferences changed. Resetting location request.") setupLocationRequest() } @@ -650,7 +705,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList } } }, - 0) + 0, + ) } private val localServiceBinder: IBinder = LocalBinder() @@ -686,7 +742,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList class LocationCallbackWithReportType( private val reportType: MessageLocation.ReportType, private val locationProcessor: LocationProcessor, - private val lifecycleCoroutineScope: LifecycleCoroutineScope + private val lifecycleCoroutineScope: LifecycleCoroutineScope, ) : LocationCallback { override fun onLocationAvailability(locationAvailability: LocationAvailability) { @@ -729,7 +785,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList "" } + "isInteractive=${powerManager.isInteractive} " + - "isIgnoringBatteryOptimizations=${powerManager.isIgnoringBatteryOptimizations(applicationContext.packageName)}") + "isIgnoringBatteryOptimizations=${powerManager.isIgnoringBatteryOptimizations(applicationContext.packageName)}" + ) } } } diff --git a/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt b/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt index 205d8adac3..9258d9578f 100644 --- a/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt +++ b/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt @@ -49,16 +49,18 @@ constructor( @Named("publishResponseMessageIdlingResource") private val publishResponseMessageIdlingResource: SimpleIdlingResource, @Named("mockLocationIdlingResource") - private val mockLocationIdlingResource: SimpleIdlingResource + private val mockLocationIdlingResource: SimpleIdlingResource, ) { var lastAddress: String? = null + private fun locationIsWithAccuracyThreshold(l: Location): Boolean = preferences.ignoreInaccurateLocations .run { preferences.ignoreInaccurateLocations == 0 || l.accuracy < this } .also { if (!it) { Timber.v( - "Location accuracy ${l.accuracy} is outside accuracy threshold of ${preferences.ignoreInaccurateLocations}") + "Location accuracy ${l.accuracy} is outside accuracy threshold of ${preferences.ignoreInaccurateLocations}" + ) } } @@ -69,7 +71,7 @@ constructor( private suspend fun publishLocationMessage( trigger: MessageLocation.ReportType, - location: Location + location: Location, ): Result { Timber.v("Maybe publishing $location with trigger $trigger") if (!locationIsWithAccuracyThreshold(location)) @@ -78,14 +80,18 @@ constructor( // If this location has come from the network *and* the most recent location was both recent and // high-accuracy, then it's probably not usefully accurate. Drop it. locationRepo.currentPublishedLocation.value?.let { lastLocation -> - if (highAccuracyProviders.contains(location.provider) && - lastLocation.provider == "network" && - location.time - lastLocation.time < - preferences.discardNetworkLocationThresholdSeconds * 1000) { + if ( + highAccuracyProviders.contains(location.provider) && + lastLocation.provider == "network" && + location.time - lastLocation.time < + preferences.discardNetworkLocationThresholdSeconds * 1000 + ) { Timber.d( - "Ignoring location from ${location.provider}, last was from gps, and time difference is less than 1s") + "Ignoring location from ${location.provider}, last was from gps, and time difference is less than 1s" + ) return Result.failure( - Exception("Ignoring location from ${location.provider}, last was recent and from gps")) + Exception("Ignoring location from ${location.provider}, last was recent and from gps") + ) } } @@ -94,32 +100,42 @@ constructor( // Check if publish would trigger a region if fusedRegionDetection is enabled Timber.v( - "Checking if location triggers waypoint transitions. waypoints: $loadedWaypoints, trigger=$trigger, fusedRegionDetection: ${preferences.fusedRegionDetection}") - if (loadedWaypoints.isNotEmpty() && - preferences.fusedRegionDetection && - trigger != MessageLocation.ReportType.CIRCULAR) { + "Checking if location triggers waypoint transitions. waypoints: $loadedWaypoints, trigger=$trigger, fusedRegionDetection: ${preferences.fusedRegionDetection}" + ) + if ( + loadedWaypoints.isNotEmpty() && + preferences.fusedRegionDetection && + trigger != MessageLocation.ReportType.CIRCULAR + ) { loadedWaypoints.forEach { waypoint -> Timber.d("onWaypointTransition triggered by location waypoint intersection event") onWaypointTransition( waypoint, location, - if (location.distanceTo(waypoint.getLocation()) <= - waypoint.geofenceRadius + location.accuracy) { + if ( + location.distanceTo(waypoint.getLocation()) <= + waypoint.geofenceRadius + location.accuracy + ) { Geofence.GEOFENCE_TRANSITION_ENTER } else { Geofence.GEOFENCE_TRANSITION_EXIT }, - MessageTransition.TRIGGER_LOCATION) + MessageTransition.TRIGGER_LOCATION, + ) } } - if (preferences.monitoring === MonitoringMode.Quiet && - MessageLocation.ReportType.USER != trigger) { + if ( + preferences.monitoring === MonitoringMode.Quiet && + MessageLocation.ReportType.USER != trigger + ) { Timber.v("message suppressed by monitoring settings: quiet") return Result.failure(Exception("message suppressed by monitoring settings: quiet")) } - if (preferences.monitoring === MonitoringMode.Manual && - MessageLocation.ReportType.USER != trigger && - MessageLocation.ReportType.CIRCULAR != trigger) { + if ( + preferences.monitoring === MonitoringMode.Manual && + MessageLocation.ReportType.USER != trigger && + MessageLocation.ReportType.CIRCULAR != trigger + ) { Timber.v("message suppressed by monitoring settings: manual") return Result.failure(Exception("message suppressed by monitoring settings: manual")) } @@ -154,7 +170,8 @@ constructor( listOf( MessageLocation.ReportType.RESPONSE, MessageLocation.ReportType.USER, - MessageLocation.ReportType.CIRCULAR) + MessageLocation.ReportType.CIRCULAR, + ) private fun calculateInRegions(loadedWaypoints: List): List = loadedWaypoints @@ -170,8 +187,10 @@ constructor( */ suspend fun onLocationChanged(location: Location, reportType: MessageLocation.ReportType) { Timber.v("OnLocationChanged $location $reportType") - if (location.time > locationRepo.currentLocationTime || - reportType != MessageLocation.ReportType.DEFAULT) { + if ( + location.time > locationRepo.currentLocationTime || + reportType != MessageLocation.ReportType.DEFAULT + ) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || location.isMock) { Timber.v("Idling location") mockLocationIdlingResource.setIdleState(true) @@ -192,18 +211,21 @@ constructor( waypointModel: WaypointModel, location: Location, transition: Int, - trigger: String + trigger: String, ) { if (!locationIsWithAccuracyThreshold(location)) { Timber.d( - "ignoring transition for $location, transition=$transition, trigger=$trigger: low accuracy") + "ignoring transition for $location, transition=$transition, trigger=$trigger: low accuracy" + ) return } Timber.d("OnWaypointTransition $waypointModel $location $transition $trigger") scope.launch { // If the transition hasn't changed, or has moved from unknown to exit, don't notify. - if (transition == waypointModel.lastTransition || - (waypointModel.isUnknown() && transition == Geofence.GEOFENCE_TRANSITION_EXIT)) { + if ( + transition == waypointModel.lastTransition || + (waypointModel.isUnknown() && transition == Geofence.GEOFENCE_TRANSITION_EXIT) + ) { waypointModel.lastTransition = transition waypointsRepo.update(waypointModel, false) } else { @@ -230,7 +252,7 @@ constructor( waypointModel: WaypointModel, triggeringLocation: Location, transition: Int, - trigger: String + trigger: String, ) { messageProcessor.queueMessageForSending( MessageTransition().apply { @@ -243,7 +265,8 @@ constructor( timestamp = TimeUnit.MILLISECONDS.toSeconds(triggeringLocation.time) waypointTimestamp = waypointModel.tst.epochSecond description = waypointModel.description - }) + } + ) } suspend fun publishWaypointsMessage() { @@ -261,10 +284,12 @@ constructor( radius = it.geofenceRadius timestamp = it.tst.epochSecond } - }) + } + ) } } - }) + } + ) publishResponseMessageIdlingResource.setIdleState(true) } @@ -281,7 +306,8 @@ constructor( appHibernation = deviceMetricsProvider.appHibernation locationPermission = deviceMetricsProvider.locationPermission } - }) + } + ) publishResponseMessageIdlingResource.setIdleState(true) } } From 9ed6d2f3e027cdf446b855226b98399bed2f6b8d Mon Sep 17 00:00:00 2001 From: wir3z Date: Tue, 18 Nov 2025 07:40:11 -0700 Subject: [PATCH 3/7] Moved address attribute to extended data. --- .../java/org/owntracks/android/services/LocationProcessor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt b/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt index 9258d9578f..44daee3106 100644 --- a/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt +++ b/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt @@ -148,6 +148,7 @@ constructor( conn = deviceMetricsProvider.connectionType monitoringMode = preferences.monitoring source = location.provider + address = lastAddress } } else { fromLocation(location, Build.VERSION.SDK_INT) @@ -156,7 +157,6 @@ constructor( this.trigger = trigger trackerId = preferences.tid.toString() inregions = calculateInRegions(loadedWaypoints) - address = lastAddress } Timber.v("Actually publishing location $location triggered by $trigger as message=$message") messageProcessor.queueMessageForSending(message) From 962151b684427763a704dfd9ab35e22a9c00e09f Mon Sep 17 00:00:00 2001 From: wir3z Date: Thu, 4 Dec 2025 16:12:44 -0700 Subject: [PATCH 4/7] kfmt --- .../android/services/BackgroundService.kt | 4 +- .../android/services/MessageProcessor.kt | 80 ++++++++++++------- 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt index d141a396dd..9ec803bff4 100644 --- a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt +++ b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt @@ -132,7 +132,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList private val ongoingNotification by lazy { OngoingNotification(this, preferences.monitoring) } private val notificationManagerCompat by lazy { NotificationManagerCompat.from(this) } private val activityManager by lazy { - this.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + this.getSystemService(ACTIVITY_SERVICE) as ActivityManager } private val powerStateLogger by lazy { PowerStateLogger(this.applicationContext) } private val powerBroadcastReceiver = @@ -770,7 +770,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList class PowerStateLogger(private val applicationContext: Context) { private val powerManager = - applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager + applicationContext.getSystemService(POWER_SERVICE) as PowerManager fun logPowerState(action: String) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { diff --git a/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt b/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt index cfba6b2a39..955558d5f9 100644 --- a/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt +++ b/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt @@ -77,12 +77,15 @@ constructor( @IoDispatcher private val ioDispatcher: CoroutineDispatcher, @ApplicationScope private val scope: CoroutineScope, @Named("mqttConnectionIdlingResource") - private val mqttConnectionIdlingResource: SimpleIdlingResource + private val mqttConnectionIdlingResource: SimpleIdlingResource, ) : Preferences.OnPreferenceChangeListener { private var endpoint: MessageProcessorEndpoint? = null private val outgoingQueue: BlockingDeque = BlockingDequeThatAlsoSometimesPersistsThingsToDiskMaybe( - 100_000, applicationContext.filesDir, parser) + 100_000, + applicationContext.filesDir, + parser, + ) private var dequeueAndSenderJob: Job? = null private var retryDelayJob: Job? = null private var initialized = false @@ -122,7 +125,8 @@ constructor( applicationContext.bindService( Intent(applicationContext, BackgroundService::class.java), serviceConnection, - Context.BIND_AUTO_CREATE) + Context.BIND_AUTO_CREATE, + ) endpointStateRepo.setState(EndpointState.INITIAL) reconnect() initialized = true @@ -191,7 +195,8 @@ constructor( scope, ioDispatcher, applicationContext, - mqttConnectionIdlingResource) + mqttConnectionIdlingResource, + ) ConnectionMode.HTTP -> HttpMessageProcessorEndpoint( this, @@ -201,7 +206,8 @@ constructor( endpointStateRepo, caKeyStore, scope, - ioDispatcher) + ioDispatcher, + ) } } @@ -254,8 +260,10 @@ constructor( Timber.d("Taken message off queue: $message") endpointStateRepo.setQueueLength(outgoingQueue.size + 1) // reset the retry logic if the last message succeeded - if (lastMessageStatus is LastMessageStatus.Success || - lastMessageStatus is LastMessageStatus.PermanentFailure) { + if ( + lastMessageStatus is LastMessageStatus.Success || + lastMessageStatus is LastMessageStatus.PermanentFailure + ) { retriesToGo = message.numberOfRetries retryWait = SEND_FAILURE_BACKOFF_INITIAL_WAIT } else { @@ -270,7 +278,9 @@ constructor( resendDelayWait(SEND_FAILURE_NOT_READY_WAIT) lastMessageStatus = LastMessageStatus.RetryableFailure( - message.numberOfRetries, SEND_FAILURE_BACKOFF_INITIAL_WAIT) + message.numberOfRetries, + SEND_FAILURE_BACKOFF_INITIAL_WAIT, + ) } else { it.sendMessage(message).exceptionOrNull()?.run { when (this) { @@ -280,7 +290,9 @@ constructor( resendDelayWait(SEND_FAILURE_NOT_READY_WAIT) lastMessageStatus = LastMessageStatus.RetryableFailure( - message.numberOfRetries, SEND_FAILURE_BACKOFF_INITIAL_WAIT) + message.numberOfRetries, + SEND_FAILURE_BACKOFF_INITIAL_WAIT, + ) } is MessageProcessorEndpoint.OutgoingMessageSendingException, @@ -306,7 +318,8 @@ constructor( retriesToGo - 1, (retryWait * 2).coerceAtMost(SEND_FAILURE_BACKOFF_MAX_WAIT).also { Timber.v("Increasing failure retry wait to $it") - }) + }, + ) } } @@ -331,8 +344,10 @@ constructor( lastMessageStatus = LastMessageStatus.PermanentFailure } - if (lastMessageStatus is LastMessageStatus.Success || - lastMessageStatus is LastMessageStatus.PermanentFailure) { + if ( + lastMessageStatus is LastMessageStatus.Success || + lastMessageStatus is LastMessageStatus.PermanentFailure + ) { try { if (!outgoingQueueIdlingResource.isIdleNow) { Timber.v("Decrementing outgoingQueueIdlingResource") @@ -422,7 +437,8 @@ constructor( fun processIncomingMessage(message: MessageBase) { Timber.d( - "Received incoming message: ${message.javaClass.simpleName} on ${message.topic} with id=${message.messageId}") + "Received incoming message: ${message.javaClass.simpleName} on ${message.topic} with id=${message.messageId}" + ) when (message) { is MessageClear -> { processIncomingMessage(message) @@ -456,19 +472,23 @@ constructor( private fun processIncomingMessage(message: MessageLocation) { // do not use TimeUnit.DAYS.toMillis to avoid long/double conversion issues... - if (preferences.ignoreStaleLocations > 0 && - System.currentTimeMillis() - message.timestamp * 1000 > - preferences.ignoreStaleLocations.toDouble().days.inWholeMilliseconds) { + if ( + preferences.ignoreStaleLocations > 0 && + System.currentTimeMillis() - message.timestamp * 1000 > + preferences.ignoreStaleLocations.toDouble().days.inWholeMilliseconds + ) { Timber.d("discarding stale location from ${message.getContactId()} at ${message.timestamp}") messageReceivedIdlingResource.remove(message) } else { scope.launch { if (message.topic == preferences.pubTopicLocations) { Timber.d( - "Received our own location update ${message.latitude},${message.longitude} at ${message.timestamp}") + "Received our own location update ${message.latitude},${message.longitude} at ${message.timestamp}" + ) } else { Timber.i( - "Contact ${message.getContactId()} moved to ${message.latitude},${message.longitude} at ${message.timestamp}") + "Contact ${message.getContactId()} moved to ${message.latitude},${message.longitude} at ${message.timestamp}" + ) } contactsRepo.update(message.getContactId(), message) /* @@ -483,15 +503,18 @@ constructor( } private fun processIncomingMessage(message: MessageTransition) { - if (preferences.ignoreStaleLocations > 0 && - System.currentTimeMillis() - message.timestamp * 1000 > - preferences.ignoreStaleLocations.toDouble().days.inWholeMilliseconds) { + if ( + preferences.ignoreStaleLocations > 0 && + System.currentTimeMillis() - message.timestamp * 1000 > + preferences.ignoreStaleLocations.toDouble().days.inWholeMilliseconds + ) { Timber.d("discarding stale transition from $message.topic at $message.timestamp") messageReceivedIdlingResource.remove(message) } else { scope.launch { Timber.i( - "Contact ${message.getContactId()} transitioned waypoint ${message.description} (${message.event}) at ${message.timestamp}") + "Contact ${message.getContactId()} transitioned waypoint ${message.description} (${message.event}) at ${message.timestamp}" + ) contactsRepo.update(message.getContactId(), message) service?.sendEventNotification(message) messageReceivedIdlingResource.remove(message) @@ -511,10 +534,12 @@ constructor( if (!preferences.cmd) { Timber.w("remote commands are disabled") messageReceivedIdlingResource.remove(message) - } else if (message.modeId !== ConnectionMode.HTTP && - preferences.receivedCommandsTopic != message.topic && - preferences.subTopic == - DEFAULT_SUB_TOPIC // If we're not using the default subtopic, we receive commands from + } else if ( + message.modeId !== ConnectionMode.HTTP && + preferences.receivedCommandsTopic != message.topic && + preferences.subTopic == + DEFAULT_SUB_TOPIC // If we're not using the default subtopic, we receive commands + // from // anywhere ) { Timber.e("cmd message received on wrong topic") @@ -534,7 +559,8 @@ constructor( CommandAction.SET_CONFIGURATION -> { if (!preferences.remoteConfiguration) { Timber.w( - "Received a remote configuration command but remote config setting is disabled") + "Received a remote configuration command but remote config setting is disabled" + ) } else { if (message.configuration != null) { preferences.importConfiguration(message.configuration!!) From 784d7e11ef6c5a439a1c68a2c26e74aa410c3d59 Mon Sep 17 00:00:00 2001 From: wir3z Date: Sun, 11 Jan 2026 11:20:21 -0700 Subject: [PATCH 5/7] kfmt --- .../org/owntracks/android/services/BackgroundService.kt | 7 ++----- .../org/owntracks/android/services/MessageProcessor.kt | 7 +++++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt index 9ec803bff4..26681f7f64 100644 --- a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt +++ b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt @@ -131,9 +131,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList private val ongoingNotification by lazy { OngoingNotification(this, preferences.monitoring) } private val notificationManagerCompat by lazy { NotificationManagerCompat.from(this) } - private val activityManager by lazy { - this.getSystemService(ACTIVITY_SERVICE) as ActivityManager - } + private val activityManager by lazy { this.getSystemService(ACTIVITY_SERVICE) as ActivityManager } private val powerStateLogger by lazy { PowerStateLogger(this.applicationContext) } private val powerBroadcastReceiver = object : BroadcastReceiver() { @@ -769,8 +767,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList } class PowerStateLogger(private val applicationContext: Context) { - private val powerManager = - applicationContext.getSystemService(POWER_SERVICE) as PowerManager + private val powerManager = applicationContext.getSystemService(POWER_SERVICE) as PowerManager fun logPowerState(action: String) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { diff --git a/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt b/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt index fa60f8de70..878b5fe75c 100644 --- a/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt +++ b/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt @@ -86,7 +86,10 @@ constructor( scope.launch(ioDispatcher) { outgoingQueue = BlockingDequeThatAlsoSometimesPersistsThingsToDiskMaybe( - 100_000, applicationContext.filesDir, parser) + 100_000, + applicationContext.filesDir, + parser, + ) .apply { repeat(indices.count()) { outgoingQueueIdlingResource.increment() } Timber.d("Initialized outgoingQueue with size: $size") @@ -541,7 +544,7 @@ constructor( preferences.receivedCommandsTopic != message.topic && preferences.subTopic == DEFAULT_SUB_TOPIC // If we're not using the default subtopic, we receive commands - // from + // from // anywhere ) { Timber.e("cmd message received on wrong topic") From 5161e34666f3c01a0e9d409767b95dddb6ff27f2 Mon Sep 17 00:00:00 2001 From: wir3z Date: Fri, 16 Jan 2026 19:23:30 -0700 Subject: [PATCH 6/7] ktfmt --- .../android/services/BackgroundService.kt | 75 +++++++----------- .../android/services/LocationProcessor.kt | 77 +++++++------------ .../android/services/MessageProcessor.kt | 52 +++++-------- 3 files changed, 73 insertions(+), 131 deletions(-) diff --git a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt index 26681f7f64..009dd02884 100644 --- a/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt +++ b/project/app/src/main/java/org/owntracks/android/services/BackgroundService.kt @@ -155,19 +155,15 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList endpointStateRepo = entrypoint.endpointStateRepo() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { Timber.v( - "Permissions. ACCESS_BACKGROUND_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)==PERMISSION_GRANTED}" - ) + "Permissions. ACCESS_BACKGROUND_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)==PERMISSION_GRANTED}") } Timber.v( - "Permissions. ACCESS_COARSE_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)==PERMISSION_GRANTED}" - ) + "Permissions. ACCESS_COARSE_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)==PERMISSION_GRANTED}") Timber.v( - "Permissions. ACCESS_FINE_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)==PERMISSION_GRANTED}" - ) + "Permissions. ACCESS_FINE_LOCATION: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)==PERMISSION_GRANTED}") if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { Timber.v( - "Permissions. POST_NOTIFICATIONS: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)==PERMISSION_GRANTED}" - ) + "Permissions. POST_NOTIFICATIONS: ${ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)==PERMISSION_GRANTED}") } super.onCreate() @@ -306,9 +302,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList INTENT_ACTION_BOOT_COMPLETED, INTENT_ACTION_PACKAGE_REPLACED -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - if ( - !requirementsChecker.hasBackgroundLocationPermission() && !hasBeenStartedExplicitly - ) { + if (!requirementsChecker.hasBackgroundLocationPermission() && + !hasBeenStartedExplicitly) { notifyUserOfBackgroundLocationRestriction() } } @@ -323,8 +318,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList } } else { Timber.d( - "no intent or action provided, setting up location request and scheduling location ping." - ) + "no intent or action provided, setting up location request and scheduling location ping.") hasBeenStartedExplicitly = true setupAndStartService() } @@ -372,10 +366,8 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList } private fun notifyUserOfBackgroundLocationRestriction() { - if ( - ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != - PackageManager.PERMISSION_GRANTED - ) { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != + PackageManager.PERMISSION_GRANTED) { return } val activityLaunchIntent = @@ -401,8 +393,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList 0, activityLaunchIntent, UPDATE_CURRENT_INTENT_FLAGS, - ) - ) + )) .setPriority(NotificationCompat.PRIORITY_LOW) .setSilent(true) .build() @@ -415,11 +406,9 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList fun sendEventNotification(message: MessageTransition) { Timber.d("Sending event notification for $message") - if ( - !preferences.notificationEvents || - ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != - PackageManager.PERMISSION_GRANTED - ) { + if (!preferences.notificationEvents || + ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != + PackageManager.PERMISSION_GRANTED) { return } val contact = contactsRepo.getById(message.getContactId()) @@ -432,8 +421,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList R.string.transitionEntering } else { R.string.transitionLeaving - } - ) + }) val eventText = "$transitionText $location" val whenStr = formatDate(timestampInMs) // Need to lock to prevent "clear()" being called while we're adding to it @@ -447,8 +435,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList whenStr.length + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE, ) - } - ) + }) Timber.v("groupedNotifications: ${activeNotifications.size}") val summary = resources.getQuantityString( @@ -482,8 +469,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList System.currentTimeMillis().toInt() / 1000, Intent(this, MapActivity::class.java), UPDATE_CURRENT_INTENT_FLAGS, - ) - ) + )) .setDeleteIntent( PendingIntent.getService( this, @@ -491,8 +477,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList Intent(this, BackgroundService::class.java) .setAction(INTENT_ACTION_CLEAR_NOTIFICATIONS), UPDATE_CURRENT_INTENT_FLAGS, - ) - ) + )) .build() .run { notificationManagerCompat @@ -511,11 +496,9 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList Timber.e("geofencingEvent hasError: ${event.errorCode}") return } - if ( - event.geofenceTransition == null || - event.triggeringGeofences == null || - event.triggeringLocation == null - ) { + if (event.geofenceTransition == null || + event.triggeringGeofences == null || + event.triggeringLocation == null) { Timber.e("geofencingEvent has no transition or trigger") return } @@ -656,8 +639,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList .run(ongoingNotification::setTitle) } else { Timber.v( - "Ignoring reverse geocode for $latLng: $reverseGeocodedText, because my lastPublished location is ${lastLocation?.toLatLng()}" - ) + "Ignoring reverse geocode for $latLng: $reverseGeocodedText, because my lastPublished location is ${lastLocation?.toLatLng()}") } } @@ -671,13 +653,11 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList Preferences::notificationHigherPriority.name, Preferences::locatorPriority.name, ) - if ( - propertiesWeCareAbout - .stream() - .filter { o: String -> properties.contains(o) } - .collect(Collectors.toSet()) - .isNotEmpty() - ) { + if (propertiesWeCareAbout + .stream() + .filter { o: String -> properties.contains(o) } + .collect(Collectors.toSet()) + .isNotEmpty()) { Timber.d("locator preferences changed. Resetting location request.") setupLocationRequest() } @@ -782,8 +762,7 @@ class BackgroundService : LifecycleService(), Preferences.OnPreferenceChangeList "" } + "isInteractive=${powerManager.isInteractive} " + - "isIgnoringBatteryOptimizations=${powerManager.isIgnoringBatteryOptimizations(applicationContext.packageName)}" - ) + "isIgnoringBatteryOptimizations=${powerManager.isIgnoringBatteryOptimizations(applicationContext.packageName)}") } } } diff --git a/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt b/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt index 44daee3106..51b08c39c2 100644 --- a/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt +++ b/project/app/src/main/java/org/owntracks/android/services/LocationProcessor.kt @@ -59,8 +59,7 @@ constructor( .also { if (!it) { Timber.v( - "Location accuracy ${l.accuracy} is outside accuracy threshold of ${preferences.ignoreInaccurateLocations}" - ) + "Location accuracy ${l.accuracy} is outside accuracy threshold of ${preferences.ignoreInaccurateLocations}") } } @@ -80,18 +79,14 @@ constructor( // If this location has come from the network *and* the most recent location was both recent and // high-accuracy, then it's probably not usefully accurate. Drop it. locationRepo.currentPublishedLocation.value?.let { lastLocation -> - if ( - highAccuracyProviders.contains(location.provider) && - lastLocation.provider == "network" && - location.time - lastLocation.time < - preferences.discardNetworkLocationThresholdSeconds * 1000 - ) { + if (highAccuracyProviders.contains(location.provider) && + lastLocation.provider == "network" && + location.time - lastLocation.time < + preferences.discardNetworkLocationThresholdSeconds * 1000) { Timber.d( - "Ignoring location from ${location.provider}, last was from gps, and time difference is less than 1s" - ) + "Ignoring location from ${location.provider}, last was from gps, and time difference is less than 1s") return Result.failure( - Exception("Ignoring location from ${location.provider}, last was recent and from gps") - ) + Exception("Ignoring location from ${location.provider}, last was recent and from gps")) } } @@ -100,22 +95,17 @@ constructor( // Check if publish would trigger a region if fusedRegionDetection is enabled Timber.v( - "Checking if location triggers waypoint transitions. waypoints: $loadedWaypoints, trigger=$trigger, fusedRegionDetection: ${preferences.fusedRegionDetection}" - ) - if ( - loadedWaypoints.isNotEmpty() && - preferences.fusedRegionDetection && - trigger != MessageLocation.ReportType.CIRCULAR - ) { + "Checking if location triggers waypoint transitions. waypoints: $loadedWaypoints, trigger=$trigger, fusedRegionDetection: ${preferences.fusedRegionDetection}") + if (loadedWaypoints.isNotEmpty() && + preferences.fusedRegionDetection && + trigger != MessageLocation.ReportType.CIRCULAR) { loadedWaypoints.forEach { waypoint -> Timber.d("onWaypointTransition triggered by location waypoint intersection event") onWaypointTransition( waypoint, location, - if ( - location.distanceTo(waypoint.getLocation()) <= - waypoint.geofenceRadius + location.accuracy - ) { + if (location.distanceTo(waypoint.getLocation()) <= + waypoint.geofenceRadius + location.accuracy) { Geofence.GEOFENCE_TRANSITION_ENTER } else { Geofence.GEOFENCE_TRANSITION_EXIT @@ -124,18 +114,14 @@ constructor( ) } } - if ( - preferences.monitoring === MonitoringMode.Quiet && - MessageLocation.ReportType.USER != trigger - ) { + if (preferences.monitoring === MonitoringMode.Quiet && + MessageLocation.ReportType.USER != trigger) { Timber.v("message suppressed by monitoring settings: quiet") return Result.failure(Exception("message suppressed by monitoring settings: quiet")) } - if ( - preferences.monitoring === MonitoringMode.Manual && - MessageLocation.ReportType.USER != trigger && - MessageLocation.ReportType.CIRCULAR != trigger - ) { + if (preferences.monitoring === MonitoringMode.Manual && + MessageLocation.ReportType.USER != trigger && + MessageLocation.ReportType.CIRCULAR != trigger) { Timber.v("message suppressed by monitoring settings: manual") return Result.failure(Exception("message suppressed by monitoring settings: manual")) } @@ -187,10 +173,8 @@ constructor( */ suspend fun onLocationChanged(location: Location, reportType: MessageLocation.ReportType) { Timber.v("OnLocationChanged $location $reportType") - if ( - location.time > locationRepo.currentLocationTime || - reportType != MessageLocation.ReportType.DEFAULT - ) { + if (location.time > locationRepo.currentLocationTime || + reportType != MessageLocation.ReportType.DEFAULT) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || location.isMock) { Timber.v("Idling location") mockLocationIdlingResource.setIdleState(true) @@ -215,17 +199,14 @@ constructor( ) { if (!locationIsWithAccuracyThreshold(location)) { Timber.d( - "ignoring transition for $location, transition=$transition, trigger=$trigger: low accuracy" - ) + "ignoring transition for $location, transition=$transition, trigger=$trigger: low accuracy") return } Timber.d("OnWaypointTransition $waypointModel $location $transition $trigger") scope.launch { // If the transition hasn't changed, or has moved from unknown to exit, don't notify. - if ( - transition == waypointModel.lastTransition || - (waypointModel.isUnknown() && transition == Geofence.GEOFENCE_TRANSITION_EXIT) - ) { + if (transition == waypointModel.lastTransition || + (waypointModel.isUnknown() && transition == Geofence.GEOFENCE_TRANSITION_EXIT)) { waypointModel.lastTransition = transition waypointsRepo.update(waypointModel, false) } else { @@ -265,8 +246,7 @@ constructor( timestamp = TimeUnit.MILLISECONDS.toSeconds(triggeringLocation.time) waypointTimestamp = waypointModel.tst.epochSecond description = waypointModel.description - } - ) + }) } suspend fun publishWaypointsMessage() { @@ -284,12 +264,10 @@ constructor( radius = it.geofenceRadius timestamp = it.tst.epochSecond } - } - ) + }) } } - } - ) + }) publishResponseMessageIdlingResource.setIdleState(true) } @@ -306,8 +284,7 @@ constructor( appHibernation = deviceMetricsProvider.appHibernation locationPermission = deviceMetricsProvider.locationPermission } - } - ) + }) publishResponseMessageIdlingResource.setIdleState(true) } } diff --git a/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt b/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt index 878b5fe75c..84b77be275 100644 --- a/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt +++ b/project/app/src/main/java/org/owntracks/android/services/MessageProcessor.kt @@ -265,10 +265,8 @@ constructor( Timber.d("Taken message off queue: $message") endpointStateRepo.setQueueLength(outgoingQueue.size + 1) // reset the retry logic if the last message succeeded - if ( - lastMessageStatus is LastMessageStatus.Success || - lastMessageStatus is LastMessageStatus.PermanentFailure - ) { + if (lastMessageStatus is LastMessageStatus.Success || + lastMessageStatus is LastMessageStatus.PermanentFailure) { retriesToGo = message.numberOfRetries retryWait = SEND_FAILURE_BACKOFF_INITIAL_WAIT } else { @@ -349,10 +347,8 @@ constructor( lastMessageStatus = LastMessageStatus.PermanentFailure } - if ( - lastMessageStatus is LastMessageStatus.Success || - lastMessageStatus is LastMessageStatus.PermanentFailure - ) { + if (lastMessageStatus is LastMessageStatus.Success || + lastMessageStatus is LastMessageStatus.PermanentFailure) { try { if (!outgoingQueueIdlingResource.isIdleNow) { Timber.v("Decrementing outgoingQueueIdlingResource") @@ -442,8 +438,7 @@ constructor( fun processIncomingMessage(message: MessageBase) { Timber.d( - "Received incoming message: ${message.javaClass.simpleName} on ${message.topic} with id=${message.messageId}" - ) + "Received incoming message: ${message.javaClass.simpleName} on ${message.topic} with id=${message.messageId}") when (message) { is MessageClear -> { processIncomingMessage(message) @@ -477,23 +472,19 @@ constructor( private fun processIncomingMessage(message: MessageLocation) { // do not use TimeUnit.DAYS.toMillis to avoid long/double conversion issues... - if ( - preferences.ignoreStaleLocations > 0 && - System.currentTimeMillis() - message.timestamp * 1000 > - preferences.ignoreStaleLocations.toDouble().days.inWholeMilliseconds - ) { + if (preferences.ignoreStaleLocations > 0 && + System.currentTimeMillis() - message.timestamp * 1000 > + preferences.ignoreStaleLocations.toDouble().days.inWholeMilliseconds) { Timber.d("discarding stale location from ${message.getContactId()} at ${message.timestamp}") messageReceivedIdlingResource.remove(message) } else { scope.launch { if (message.topic == preferences.pubTopicLocations) { Timber.d( - "Received our own location update ${message.latitude},${message.longitude} at ${message.timestamp}" - ) + "Received our own location update ${message.latitude},${message.longitude} at ${message.timestamp}") } else { Timber.i( - "Contact ${message.getContactId()} moved to ${message.latitude},${message.longitude} at ${message.timestamp}" - ) + "Contact ${message.getContactId()} moved to ${message.latitude},${message.longitude} at ${message.timestamp}") } contactsRepo.update(message.getContactId(), message) /* @@ -508,18 +499,15 @@ constructor( } private fun processIncomingMessage(message: MessageTransition) { - if ( - preferences.ignoreStaleLocations > 0 && - System.currentTimeMillis() - message.timestamp * 1000 > - preferences.ignoreStaleLocations.toDouble().days.inWholeMilliseconds - ) { + if (preferences.ignoreStaleLocations > 0 && + System.currentTimeMillis() - message.timestamp * 1000 > + preferences.ignoreStaleLocations.toDouble().days.inWholeMilliseconds) { Timber.d("discarding stale transition from $message.topic at $message.timestamp") messageReceivedIdlingResource.remove(message) } else { scope.launch { Timber.i( - "Contact ${message.getContactId()} transitioned waypoint ${message.description} (${message.event}) at ${message.timestamp}" - ) + "Contact ${message.getContactId()} transitioned waypoint ${message.description} (${message.event}) at ${message.timestamp}") contactsRepo.update(message.getContactId(), message) service?.sendEventNotification(message) messageReceivedIdlingResource.remove(message) @@ -539,11 +527,10 @@ constructor( if (!preferences.cmd) { Timber.w("remote commands are disabled") messageReceivedIdlingResource.remove(message) - } else if ( - message.modeId !== ConnectionMode.HTTP && - preferences.receivedCommandsTopic != message.topic && - preferences.subTopic == - DEFAULT_SUB_TOPIC // If we're not using the default subtopic, we receive commands + } else if (message.modeId !== ConnectionMode.HTTP && + preferences.receivedCommandsTopic != message.topic && + preferences.subTopic == + DEFAULT_SUB_TOPIC // If we're not using the default subtopic, we receive commands // from // anywhere ) { @@ -564,8 +551,7 @@ constructor( CommandAction.SET_CONFIGURATION -> { if (!preferences.remoteConfiguration) { Timber.w( - "Received a remote configuration command but remote config setting is disabled" - ) + "Received a remote configuration command but remote config setting is disabled") } else { if (message.configuration != null) { preferences.importConfiguration(message.configuration!!) From ef5a98bb9c2372a569acb6fc7b80175a06f1afed Mon Sep 17 00:00:00 2001 From: wir3z Date: Tue, 28 Apr 2026 18:15:14 -0600 Subject: [PATCH 7/7] Fixed pullup propertyissue --- .../org/owntracks/android/model/messages/MessageLocation.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt b/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt index 6ee53ea00b..b3053bc897 100644 --- a/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt +++ b/project/app/src/main/java/org/owntracks/android/model/messages/MessageLocation.kt @@ -85,7 +85,7 @@ open class MessageLocation( @SerialName("tid") var trackerId: String? = null - @JsonProperty("address") var address: String? = null + @SerialName("address") var address: String? = null override fun isValidMessage(): Boolean { return timestamp > 0