package no.naiv.tiltshift.util import android.Manifest import android.content.Context import android.content.pm.PackageManager import android.location.Location import android.os.Looper import android.util.Log import androidx.core.content.ContextCompat import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.LocationCallback import com.google.android.gms.location.LocationRequest import com.google.android.gms.location.LocationResult import com.google.android.gms.location.LocationServices import com.google.android.gms.location.Priority import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow /** * Provides location updates for EXIF GPS tagging. */ class LocationProvider(private val context: Context) { companion object { private const val TAG = "LocationProvider" } private val fusedLocationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context) /** * Returns a Flow of location updates. * Updates are throttled to conserve battery - we only need periodic updates for photo tagging. */ fun locationFlow(): Flow = callbackFlow { if (!hasLocationPermission()) { trySend(null) awaitClose() return@callbackFlow } val locationRequest = LocationRequest.Builder( Priority.PRIORITY_BALANCED_POWER_ACCURACY, 30_000L // Update every 30 seconds ).apply { setMinUpdateIntervalMillis(10_000L) setMaxUpdateDelayMillis(60_000L) }.build() val callback = object : LocationCallback() { override fun onLocationResult(result: LocationResult) { result.lastLocation?.let { trySend(it) } } } try { fusedLocationClient.requestLocationUpdates( locationRequest, callback, Looper.getMainLooper() ) // Also try to get last known location immediately fusedLocationClient.lastLocation.addOnSuccessListener { location -> location?.let { trySend(it) } } } catch (e: SecurityException) { Log.w(TAG, "Location permission revoked at runtime", e) trySend(null) } awaitClose { fusedLocationClient.removeLocationUpdates(callback) } } private fun hasLocationPermission(): Boolean { return ContextCompat.checkSelfPermission( context, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED } }