Skip to content

Commit

Permalink
Location: Remove passive location listener
Browse files Browse the repository at this point in the history
Fetching the last location once we get a request is already a good start and
won't trigger any location indicators
  • Loading branch information
mar-v-in committed Nov 19, 2024
1 parent c938921 commit 10a5259
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ object SettingsContract {
const val GEOCODER_NOMINATIM = "location_geocoder_nominatim"
const val ICHNAEA_ENDPOINT = "location_ichnaea_endpoint"
const val ONLINE_SOURCE = "location_online_source"
const val ICHNAEA_CONTRIBUTE = "location_ichnaea_contribute"

val PROJECTION = arrayOf(
WIFI_ICHNAEA,
Expand All @@ -185,6 +186,7 @@ object SettingsContract {
GEOCODER_NOMINATIM,
ICHNAEA_ENDPOINT,
ONLINE_SOURCE,
ICHNAEA_CONTRIBUTE,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,26 @@ import android.content.ContentValues
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import android.content.pm.ApplicationInfo
import android.database.Cursor
import android.database.MatrixCursor
import android.net.Uri
import android.os.Build.VERSION.SDK_INT
import android.preference.PreferenceManager
import org.microg.gms.base.core.BuildConfig
import org.microg.gms.common.PackageUtils.warnIfNotMainProcess
import org.microg.gms.settings.SettingsContract.Auth
import org.microg.gms.settings.SettingsContract.CheckIn
import org.microg.gms.settings.SettingsContract.DroidGuard
import org.microg.gms.settings.SettingsContract.Exposure
import org.microg.gms.settings.SettingsContract.Gcm
import org.microg.gms.settings.SettingsContract.Location
import org.microg.gms.settings.SettingsContract.Vending
import org.microg.gms.settings.SettingsContract.Profile
import org.microg.gms.settings.SettingsContract.SafetyNet
import org.microg.gms.settings.SettingsContract.Vending
import org.microg.gms.settings.SettingsContract.getAuthority
import java.io.File


private const val SETTINGS_PREFIX = "org.microg.gms.settings."

/**
Expand Down Expand Up @@ -321,6 +322,7 @@ class SettingsProvider : ContentProvider() {
Location.GEOCODER_NOMINATIM -> getSettingsBoolean(key, hasUnifiedNlpGeocoderBackend("org.microg.nlp.backend.nominatim") )
Location.ICHNAEA_ENDPOINT -> getSettingsString(key, null)
Location.ONLINE_SOURCE -> getSettingsString(key, null)
Location.ICHNAEA_CONTRIBUTE -> getSettingsBoolean(key, false)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
Expand All @@ -341,6 +343,7 @@ class SettingsProvider : ContentProvider() {
Location.GEOCODER_NOMINATIM -> editor.putBoolean(key, value as Boolean)
Location.ICHNAEA_ENDPOINT -> (value as String).let { if (it.isBlank()) editor.remove(key) else editor.putString(key, it) }
Location.ONLINE_SOURCE -> (value as? String?).let { if (it.isNullOrBlank()) editor.remove(key) else editor.putString(key, it) }
Location.ICHNAEA_CONTRIBUTE -> editor.putBoolean(key, value as Boolean)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package org.microg.gms.location
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import org.microg.gms.location.base.BuildConfig
import org.microg.gms.settings.SettingsContract

private const val PATH_GEOLOCATE = "/v1/geolocate"
Expand Down Expand Up @@ -96,6 +97,6 @@ class LocationSettings(private val context: Context) {
set(value) = setSettings { put(SettingsContract.Location.ONLINE_SOURCE, value) }

var ichnaeaContribute: Boolean
get() = false
set(value) = Unit
get() = getSettings(SettingsContract.Location.ICHNAEA_CONTRIBUTE) { c -> c.getInt(0) != 0 }
set(value) = setSettings { put(SettingsContract.Location.ICHNAEA_CONTRIBUTE, value) }
}
3 changes: 0 additions & 3 deletions play-services-location/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ android {
targetSdkVersion androidTargetSdk
buildConfigField "String", "FORCE_SHOW_BACKGROUND_PERMISSION", "\"\""
buildConfigField "boolean", "SHOW_NOTIFICATION_WHEN_NOT_PERMITTED", "false"
buildConfigField "boolean", "ALWAYS_LISTEN_GPS_PASSIVE", "true"
}

lintOptions {
Expand All @@ -59,13 +58,11 @@ android {
dimension 'target'
buildConfigField "String", "FORCE_SHOW_BACKGROUND_PERMISSION", "\"com.huawei.permission.sec.MDM.v2\""
buildConfigField "boolean", "SHOW_NOTIFICATION_WHEN_NOT_PERMITTED", "true"
buildConfigField "boolean", "ALWAYS_LISTEN_GPS_PASSIVE", "false"
}
"huaweilh" {
dimension 'target'
buildConfigField "String", "FORCE_SHOW_BACKGROUND_PERMISSION", "\"com.huawei.permission.sec.MDM.v2\""
buildConfigField "boolean", "SHOW_NOTIFICATION_WHEN_NOT_PERMITTED", "true"
buildConfigField "boolean", "ALWAYS_LISTEN_GPS_PASSIVE", "false"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
private var lastCellLocation: Location? = null
private var lastLocation: Location? = null

private val gpsLocationListener by lazy { LocationListenerCompat { onNewGpsLocation(it) } }
private val passiveLocationListener by lazy { LocationListenerCompat { onNewPassiveLocation(it) } }

@GuardedBy("gpsLocationBuffer")
private val gpsLocationBuffer = LinkedList<Location>()
private var passiveListenerActive = false

private var currentLocalMovingWifi: WifiDetails? = null
private var lastLocalMovingWifiLocationCandidate: Location? = null
Expand All @@ -88,15 +89,31 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
putExtra(EXTRA_CONFIGURATION, CONFIGURATION_FIELD_ONLINE_SOURCE)
})
}
}

private fun updatePassiveGpsListenerRegistration() {
try {
getSystemService<LocationManager>()?.let { locationManager ->
LocationManagerCompat.requestLocationUpdates(
locationManager,
LocationManager.GPS_PROVIDER,
LocationRequestCompat.Builder(LocationRequestCompat.PASSIVE_INTERVAL).setMinUpdateIntervalMillis(GPS_PASSIVE_INTERVAL).build(),
gpsLocationListener,
handlerThread.looper
)
if ((settings.cellLearning || settings.wifiLearning) && (highPowerIntervalMillis != Long.MAX_VALUE)) {
if (!passiveListenerActive) {
LocationManagerCompat.requestLocationUpdates(
locationManager,
LocationManager.PASSIVE_PROVIDER,
LocationRequestCompat.Builder(LocationRequestCompat.PASSIVE_INTERVAL)
.setQuality(LocationRequestCompat.QUALITY_LOW_POWER)
.setMinUpdateIntervalMillis(GPS_PASSIVE_INTERVAL)
.build(),
passiveLocationListener,
handlerThread.looper
)
passiveListenerActive = true
}
} else {
if (passiveListenerActive) {
LocationManagerCompat.removeUpdates(locationManager, passiveLocationListener)
passiveListenerActive = false
}
}
}
} catch (e: SecurityException) {
Log.d(TAG, "GPS location retriever not initialized due to lack of permission")
Expand Down Expand Up @@ -181,6 +198,8 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
handler.postDelayed(highPowerScanRunnable, nextHighPowerRequestIn)
}
}

updatePassiveGpsListenerRegistration()
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Expand Down Expand Up @@ -539,8 +558,8 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
}
}

private fun onNewGpsLocation(location: Location) {
if (location.accuracy > GPS_PASSIVE_MIN_ACCURACY) return
private fun onNewPassiveLocation(location: Location) {
if (location.provider != LocationManager.GPS_PROVIDER || location.accuracy > GPS_PASSIVE_MIN_ACCURACY) return
synchronized(gpsLocationBuffer) {
if (gpsLocationBuffer.isNotEmpty() && gpsLocationBuffer.last.elapsedMillis < SystemClock.elapsedRealtime() - GPS_BUFFER_SIZE * GPS_PASSIVE_INTERVAL) {
gpsLocationBuffer.clear()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class FusedLocationProviderService : IntentLocationProviderService() {

@SuppressLint("MissingPermission")
override fun requestIntentUpdated(currentRequest: ProviderRequestUnbundled?, pendingIntent: PendingIntent) {
val intervalMillis = currentRequest?.interval ?: Long.MAX_VALUE
val intervalMillis = max(currentRequest?.interval ?: Long.MAX_VALUE, minIntervalMillis)
val request = LocationRequest.Builder(intervalMillis)
if (SDK_INT >= 31 && currentRequest != null) {
request.setPriority(when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class DeviceOrientationManager(private val context: Context, override val lifecy
synchronized(appOpsLock) {
val newAppOps = mutableSetOf<ClientIdentity>()
for (request in requests.values) {
if (request.clientIdentity.isSelfUser()) continue
newAppOps.add(request.clientIdentity)
}
Log.d(TAG, "Updating app ops for device orientation, change attribution to: ${newAppOps.map { it.packageName }.joinToString().takeIf { it.isNotEmpty() } ?: "none"}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager.GPS_PROVIDER
import android.location.LocationManager.NETWORK_PROVIDER
import android.location.LocationManager.*
import android.os.*
import android.os.Build.VERSION.SDK_INT
import android.util.Log
Expand Down Expand Up @@ -53,10 +52,12 @@ class LocationManager(private val context: Context, override val lifecycle: Life
private val requestManager by lazy { LocationRequestManager(context, lifecycle, postProcessor, database) { updateLocationRequests() } }
private val gpsLocationListener by lazy { LocationListenerCompat { updateGpsLocation(it) } }
private val networkLocationListener by lazy { LocationListenerCompat { updateNetworkLocation(it) } }
private val settings by lazy { LocationSettings(context) }
private var boundToSystemNetworkLocation: Boolean = false
private val activePermissionRequestLock = Mutex()
private var activePermissionRequest: Deferred<Boolean>? = null
private var lastGpsLocation: Location? = null
private var lastNetworkLocation: Location? = null

private var currentGpsInterval: Long = -1
private var currentNetworkInterval: Long = -1
Expand Down Expand Up @@ -194,7 +195,7 @@ class LocationManager(private val context: Context, override val lifecycle: Life

private fun updateLocationRequests() {
val gpsInterval = when {
!BuildConfig.ALWAYS_LISTEN_GPS_PASSIVE && deviceOrientationManager.isActive -> min(requestManager.intervalMillis, DEVICE_ORIENTATION_INTERVAL)
deviceOrientationManager.isActive -> min(requestManager.intervalMillis, DEVICE_ORIENTATION_INTERVAL)
requestManager.priority == PRIORITY_HIGH_ACCURACY && requestManager.granularity == GRANULARITY_FINE -> requestManager.intervalMillis
else -> Long.MAX_VALUE
}
Expand All @@ -207,7 +208,7 @@ class LocationManager(private val context: Context, override val lifecycle: Life
deviceOrientationManager.isActive -> DEVICE_ORIENTATION_INTERVAL
else -> Long.MAX_VALUE
}
val lowPower = requestManager.granularity <= GRANULARITY_COARSE || requestManager.priority >= Priority.PRIORITY_LOW_POWER
val lowPower = requestManager.granularity <= GRANULARITY_COARSE || requestManager.priority >= Priority.PRIORITY_LOW_POWER || (requestManager.priority >= Priority.PRIORITY_BALANCED_POWER_ACCURACY && requestManager.intervalMillis >= BALANCE_LOW_POWER_INTERVAL)

if (context.hasNetworkLocationServiceBuiltIn() && currentNetworkInterval != networkInterval) {
val intent = Intent(ACTION_NETWORK_LOCATION_SERVICE)
Expand Down Expand Up @@ -243,6 +244,14 @@ class LocationManager(private val context: Context, override val lifecycle: Life
}
if (!context.hasNetworkLocationServiceBuiltIn() && LocationManagerCompat.hasProvider(locationManager, NETWORK_PROVIDER) && currentNetworkInterval != networkInterval) {
boundToSystemNetworkLocation = true
if (networkInterval == Long.MAX_VALUE) {
// Fetch last location from GPS, just to make sure we already considered it
try {
locationManager.getLastKnownLocation(NETWORK_PROVIDER)?.let { updateNetworkLocation(it) }
} catch (e: SecurityException) {
// Ignore
}
}
try {
val quality = if (lowPower) QUALITY_LOW_POWER else QUALITY_BALANCED_POWER_ACCURACY
locationManager.requestSystemProviderUpdates(NETWORK_PROVIDER, networkInterval, quality, networkLocationListener)
Expand All @@ -258,9 +267,6 @@ class LocationManager(private val context: Context, override val lifecycle: Life
if (interval != Long.MAX_VALUE) {
Log.d(TAG, "Request updates for $provider at interval ${interval}ms")
LocationManagerCompat.requestLocationUpdates(this, provider, Builder(interval).setQuality(quality).build(), listener, context.mainLooper)
} else if (BuildConfig.ALWAYS_LISTEN_GPS_PASSIVE && provider == GPS_PROVIDER) {
Log.d(TAG, "Request updates for $provider passively")
LocationManagerCompat.requestLocationUpdates(this, provider, Builder(PASSIVE_INTERVAL).setQuality(QUALITY_LOW_POWER).setMinUpdateIntervalMillis(MAX_FINE_UPDATE_INTERVAL).build(), listener, context.mainLooper)
} else {
Log.d(TAG, "Remove updates for $provider")
LocationManagerCompat.removeUpdates(this, listener)
Expand Down Expand Up @@ -288,14 +294,15 @@ class LocationManager(private val context: Context, override val lifecycle: Life
}
}

fun updateGpsLocation(location: Location) {
private fun updateGpsLocation(location: Location) {
if (location.provider != GPS_PROVIDER) return
lastGpsLocation = location
lastLocationCapsule.updateFineLocation(location)
sendNewLocation()
updateLocationRequests()
}

fun sendNewLocation() {
private fun sendNewLocation() {
lifecycleScope.launchWhenStarted {
requestManager.processNewLocation(lastLocationCapsule)
}
Expand Down Expand Up @@ -382,5 +389,6 @@ class LocationManager(private val context: Context, override val lifecycle: Life
const val DEVICE_ORIENTATION_INTERVAL = 10_000L
const val NETWORK_OFF_GPS_AGE = 5000L
const val NETWORK_OFF_GPS_ACCURACY = 10f
const val BALANCE_LOW_POWER_INTERVAL = 30_000L
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class LocationRequestManager(private val context: Context, override val lifecycl
val newAppOps = mutableMapOf<ClientIdentity, Boolean>()
val merged = binderRequests.values + pendingIntentRequests.values
for (request in merged) {
if (request.effectivePriority >= PRIORITY_PASSIVE) continue
if (request.effectivePriority >= PRIORITY_PASSIVE || request.clientIdentity.isSelfUser()) continue
if (!newAppOps.containsKey(request.clientIdentity)) {
newAppOps[request.clientIdentity] = request.effectiveHighPower
} else if (request.effectiveHighPower) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import org.microg.gms.location.core.R
import org.microg.gms.location.manager.LocationAppsDatabase
import org.microg.gms.location.network.OnlineSource
import org.microg.gms.location.network.effectiveEndpoint
import org.microg.gms.location.network.onlineSource
import org.microg.gms.ui.AppIconPreference
import org.microg.gms.ui.buildAlertDialog
import org.microg.gms.ui.getApplicationInfoIfExists
Expand Down Expand Up @@ -189,7 +190,7 @@ class LocationPreferencesFragment : PreferenceFragmentCompat() {
view.setPadding(0, 16.dp, 0, 0)
view.orientation = LinearLayout.VERTICAL
val settings = LocationSettings(requireContext())
val currentSourceId = settings.onlineSourceId
val currentSourceId = settings.onlineSource?.id
val unselectHandlerMap = mutableMapOf<String, () -> Unit>()
var selectedSourceId = currentSourceId
val customView = layoutInflater.inflate(R.layout.preference_location_custom_url, null)
Expand Down

0 comments on commit 10a5259

Please sign in to comment.