From 4130ef2d753559449467dfde1ccfd8af379154a1 Mon Sep 17 00:00:00 2001 From: William Newman <3382274+newmanw@users.noreply.github.com> Date: Wed, 20 Dec 2023 16:44:57 -0700 Subject: [PATCH] Use channel to ensure only one location push task is running at a given time --- .../repository/location/LocationRepository.kt | 14 ++--- .../mage/location/LocationReportingService.kt | 57 +++++++++++-------- 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/mage/src/main/java/mil/nga/giat/mage/data/repository/location/LocationRepository.kt b/mage/src/main/java/mil/nga/giat/mage/data/repository/location/LocationRepository.kt index 27d214d4..a6dd30e1 100644 --- a/mage/src/main/java/mil/nga/giat/mage/data/repository/location/LocationRepository.kt +++ b/mage/src/main/java/mil/nga/giat/mage/data/repository/location/LocationRepository.kt @@ -152,19 +152,17 @@ class LocationRepository @Inject constructor( try { val response = locationService.pushLocations(event.remoteId, localLocations) if (response.isSuccessful) { - val remoteLocations = response.body() ?: emptyList() + val pushedLocations = response.body() ?: emptyList() // We've sync-ed locations to the server, lets remove the locations we synced from the database - Log.d(LOG_NAME, "Pushed " + remoteLocations.size + " locations.") + Log.d(LOG_NAME, "Pushed " + pushedLocations.size + " locations.") try { localLocations.forEachIndexed { index, localLocation -> - val remoteLocation = remoteLocations.getOrNull(index) - if (remoteLocation == null) { + val remoteId = pushedLocations.getOrNull(index)?.remoteId + if (remoteId == null) { locationLocalDataSource.delete(listOf(localLocation)) } else { - remoteLocation.id = localLocation.id - remoteLocation.user = currentUser - remoteLocation.event = event - locationLocalDataSource.update(remoteLocation) + localLocation.remoteId = remoteId + locationLocalDataSource.update(localLocation) } } diff --git a/mage/src/main/java/mil/nga/giat/mage/location/LocationReportingService.kt b/mage/src/main/java/mil/nga/giat/mage/location/LocationReportingService.kt index 5cbba8b4..3df4d54e 100644 --- a/mage/src/main/java/mil/nga/giat/mage/location/LocationReportingService.kt +++ b/mage/src/main/java/mil/nga/giat/mage/location/LocationReportingService.kt @@ -3,19 +3,19 @@ package mil.nga.giat.mage.location import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent -import android.app.Service import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.location.Location import android.location.LocationManager -import android.os.Build import android.util.Log import androidx.core.app.NotificationCompat import androidx.lifecycle.LifecycleService import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch import mil.nga.giat.mage.MageApplication import mil.nga.giat.mage.R @@ -34,6 +34,7 @@ open class LocationReportingService : LifecycleService(), Observer, Sh private var shouldReportLocation: Boolean = false private var locationPushFrequency: Long = 0 private var oldestLocationTime: Long = 0 + private lateinit var locationChannel: Channel companion object { private val LOG_NAME = LocationReportingService::class.java.name @@ -57,12 +58,10 @@ open class LocationReportingService : LifecycleService(), Observer, Sh locationPushFrequency = getLocationPushFrequency() shouldReportLocation = getShouldReportLocation() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID, "MAGE", NotificationManager.IMPORTANCE_MIN) - channel.setShowBadge(true) - notificationManager.createNotificationChannel(channel) - } + val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val notificationChannel = NotificationChannel(NOTIFICATION_CHANNEL_ID, "MAGE", NotificationManager.IMPORTANCE_MIN) + notificationChannel.setShowBadge(true) + notificationManager.createNotificationChannel(notificationChannel) val intent = Intent(applicationContext, LoginActivity::class.java) intent.putExtra("LOGOUT", true) @@ -77,6 +76,13 @@ open class LocationReportingService : LifecycleService(), Observer, Sh .addAction(R.drawable.ic_power_settings_new_white_24dp, "Logout", pendingIntent) .build() + locationChannel = Channel(Channel.CONFLATED) + lifecycleScope.launch { + locationChannel.receiveAsFlow().collect { location -> + pushLocations(location) + } + } + startForeground(NOTIFICATION_ID, notification) } @@ -85,34 +91,37 @@ open class LocationReportingService : LifecycleService(), Observer, Sh locationProvider.observe(this, this) - return Service.START_STICKY + return START_STICKY } override fun onDestroy() { super.onDestroy() locationProvider.removeObserver(this) - + locationChannel.close() preferences.unregisterOnSharedPreferenceChangeListener(this) } - override fun onChanged(location: Location) { - if (shouldReportLocation && location?.provider == LocationManager.GPS_PROVIDER) { + override fun onChanged(value: Location) { + if (shouldReportLocation && value.provider == LocationManager.GPS_PROVIDER) { Log.v(LOG_NAME, "GPS location changed") lifecycleScope.launch { - locationRepository.saveLocation(location) - - if (oldestLocationTime == 0L) { - oldestLocationTime = location.time - } - - if (!locationAccess.isPreciseLocationGranted() || (location.time - oldestLocationTime > locationPushFrequency)) { - val success = locationRepository.pushLocations() - if (success) { - oldestLocationTime = 0 - } - } + locationRepository.saveLocation(value) + locationChannel.send(value) + } + } + } + + private suspend fun pushLocations(location: Location) { + if (oldestLocationTime == 0L) { + oldestLocationTime = location.time + } + + if (!locationAccess.isPreciseLocationGranted() || (location.time - oldestLocationTime > locationPushFrequency)) { + val success = locationRepository.pushLocations() + if (success) { + oldestLocationTime = 0 } } }