diff --git a/play-services-location/core/provider/src/main/AndroidManifest.xml b/play-services-location/core/provider/src/main/AndroidManifest.xml
index 52ec99d3b..ff8cc6dd3 100644
--- a/play-services-location/core/provider/src/main/AndroidManifest.xml
+++ b/play-services-location/core/provider/src/main/AndroidManifest.xml
@@ -61,6 +61,17 @@
android:name="serviceVersion"
android:value="2" />
+
+
+
+
+
+
= 31 && currentRequest != null) {
+ request.setPriority(when(currentRequest.quality) {
+ LocationRequestCompat.QUALITY_LOW_POWER -> Priority.PRIORITY_LOW_POWER
+ LocationRequestCompat.QUALITY_HIGH_ACCURACY -> Priority.PRIORITY_HIGH_ACCURACY
+ else -> Priority.PRIORITY_BALANCED_POWER_ACCURACY
+ })
+ request.setMaxUpdateDelayMillis(currentRequest.maxUpdateDelayMillis)
+ }
+ try {
+ LocationServices.getFusedLocationProviderClient(this).requestLocationUpdates(request.build(), pendingIntent)
+ } catch (e: SecurityException) {
+ Log.d(TAG, "Failed requesting location updated", e)
+ }
+ }
+
+ override fun stopIntentUpdated(pendingIntent: PendingIntent?) {
+ LocationServices.getFusedLocationProviderClient(this).removeLocationUpdates(pendingIntent)
+ }
+
+ override val minIntervalMillis: Long
+ get() = MIN_INTERVAL_MILLIS
+ override val minReportMillis: Long
+ get() = MIN_REPORT_MILLIS
+ override val properties: ProviderPropertiesUnbundled
+ get() = PROPERTIES
+ override val providerName: String
+ get() = "fused"
+
+ companion object {
+ private const val MIN_INTERVAL_MILLIS = 20000L
+ private const val MIN_REPORT_MILLIS = 1000L
+ private val PROPERTIES = ProviderPropertiesUnbundled.create(false, false, false, false, true, true, true, Criteria.POWER_LOW, Criteria.ACCURACY_COARSE)
+ }
+}
\ No newline at end of file
diff --git a/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/NetworkLocationProviderPreTiramisu.kt b/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/IntentLocationProviderPreTiramisu.kt
similarity index 52%
rename from play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/NetworkLocationProviderPreTiramisu.kt
rename to play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/IntentLocationProviderPreTiramisu.kt
index eeec457af..f5bb9c67e 100644
--- a/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/NetworkLocationProviderPreTiramisu.kt
+++ b/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/IntentLocationProviderPreTiramisu.kt
@@ -7,9 +7,7 @@ package org.microg.gms.location.provider
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
-import android.content.Context
import android.content.Intent
-import android.location.Criteria
import android.location.Location
import android.location.LocationManager
import android.os.Build.VERSION.SDK_INT
@@ -17,31 +15,28 @@ import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.os.WorkSource
-import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.PendingIntentCompat
import androidx.core.content.getSystemService
import com.android.location.provider.ProviderPropertiesUnbundled
import com.android.location.provider.ProviderRequestUnbundled
-import org.microg.gms.location.*
-import org.microg.gms.location.network.LOCATION_EXTRA_PRECISION
-import org.microg.gms.location.network.NetworkLocationService
-import org.microg.gms.location.provider.NetworkLocationProviderService.Companion.ACTION_REPORT_LOCATION
+import org.microg.gms.location.elapsedMillis
+import org.microg.gms.location.formatRealtime
import java.io.PrintWriter
import kotlin.math.max
-class NetworkLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {
+class IntentLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {
@Deprecated("Use only with SDK < 31")
- constructor(context: Context, legacy: Unit) : super(properties) {
- this.context = context
+ constructor(service: IntentLocationProviderService, properties: ProviderPropertiesUnbundled, legacy: Unit) : super(properties) {
+ this.service = service
}
@RequiresApi(31)
- constructor(context: Context) : super(context, properties) {
- this.context = context
+ constructor(service: IntentLocationProviderService, properties: ProviderPropertiesUnbundled) : super(service, properties) {
+ this.service = service
}
- private val context: Context
+ private val service: IntentLocationProviderService
private var enabled = false
private var currentRequest: ProviderRequestUnbundled? = null
private var pendingIntent: PendingIntent? = null
@@ -52,29 +47,7 @@ class NetworkLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {
private fun updateRequest() {
if (enabled) {
- val forceNow: Boolean
- val intervalMillis: Long
- if (currentRequest?.reportLocation == true) {
- forceNow = true
- intervalMillis = max(currentRequest?.interval ?: Long.MAX_VALUE, MIN_INTERVAL_MILLIS)
- } else {
- forceNow = false
- intervalMillis = Long.MAX_VALUE
- }
- val intent = Intent(ACTION_NETWORK_LOCATION_SERVICE)
- intent.`package` = context.packageName
- intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent)
- intent.putExtra(EXTRA_ENABLE, true)
- intent.putExtra(EXTRA_INTERVAL_MILLIS, intervalMillis)
- intent.putExtra(EXTRA_FORCE_NOW, forceNow)
- if (SDK_INT >= 31) {
- intent.putExtra(EXTRA_LOW_POWER, currentRequest?.isLowPower ?: false)
- intent.putExtra(EXTRA_WORK_SOURCE, currentRequest?.workSource)
- }
- if (SDK_INT >= 29) {
- intent.putExtra(EXTRA_BYPASS, currentRequest?.isLocationSettingsIgnored ?: false)
- }
- context.startService(intent)
+ service.requestIntentUpdated(currentRequest, pendingIntent)
reportAgain()
}
}
@@ -96,9 +69,9 @@ class NetworkLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {
override fun enable() {
synchronized(this) {
if (enabled) throw IllegalStateException()
- val intent = Intent(context, NetworkLocationProviderService::class.java)
+ val intent = Intent(service, service.javaClass)
intent.action = ACTION_REPORT_LOCATION
- pendingIntent = PendingIntentCompat.getService(context, 0, intent, FLAG_UPDATE_CURRENT, true)
+ pendingIntent = PendingIntentCompat.getService(service, 0, intent, FLAG_UPDATE_CURRENT, true)
currentRequest = null
enabled = true
when {
@@ -107,7 +80,7 @@ class NetworkLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {
}
try {
if (lastReportedLocation == null) {
- lastReportedLocation = context.getSystemService()?.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
+ lastReportedLocation = service.getSystemService()?.getLastKnownLocation(service.providerName)
}
} catch (_: SecurityException) {
} catch (_: Exception) {
@@ -118,10 +91,7 @@ class NetworkLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {
override fun disable() {
synchronized(this) {
if (!enabled) throw IllegalStateException()
- val intent = Intent(context, NetworkLocationService::class.java)
- intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent)
- intent.putExtra(EXTRA_ENABLE, false)
- context.startService(intent)
+ service.stopIntentUpdated(pendingIntent)
pendingIntent?.cancel()
pendingIntent = null
currentRequest = null
@@ -133,7 +103,7 @@ class NetworkLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {
private fun reportAgain() {
// Report location again if it's recent enough
lastReportedLocation?.let {
- if (it.elapsedMillis + max(currentRequest?.interval ?: 0, MIN_INTERVAL_MILLIS) > SystemClock.elapsedRealtime()) {
+ if (it.elapsedMillis + max(currentRequest?.interval ?: 0, service.minIntervalMillis) > SystemClock.elapsedRealtime()) {
reportLocationToSystem(it)
}
}
@@ -141,20 +111,13 @@ class NetworkLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {
override fun reportLocationToSystem(location: Location) {
handler.removeCallbacks(reportAgainRunnable)
- location.provider = LocationManager.NETWORK_PROVIDER
- location.extras?.remove(LOCATION_EXTRA_PRECISION)
+ location.provider = service.providerName
lastReportedLocation = location
lastReportTime = SystemClock.elapsedRealtime()
super.reportLocation(location)
- val repeatInterval = max(MIN_REPORT_MILLIS, currentRequest?.interval ?: Long.MAX_VALUE)
- if (repeatInterval < MIN_INTERVAL_MILLIS) {
+ val repeatInterval = max(service.minReportMillis, currentRequest?.interval ?: Long.MAX_VALUE)
+ if (repeatInterval < service.minIntervalMillis) {
handler.postDelayed(reportAgainRunnable, repeatInterval)
}
}
-
- companion object {
- private const val MIN_INTERVAL_MILLIS = 20000L
- private const val MIN_REPORT_MILLIS = 1000L
- private val properties = ProviderPropertiesUnbundled.create(false, false, false, false, true, true, true, Criteria.POWER_LOW, Criteria.ACCURACY_COARSE)
- }
}
\ No newline at end of file
diff --git a/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/IntentLocationProviderService.kt b/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/IntentLocationProviderService.kt
new file mode 100644
index 000000000..2761b9aa4
--- /dev/null
+++ b/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/IntentLocationProviderService.kt
@@ -0,0 +1,91 @@
+/*
+ * SPDX-FileCopyrightText: 2024 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.location.provider
+
+import android.app.PendingIntent
+import android.app.Service
+import android.content.Intent
+import android.location.Location
+import android.os.Binder
+import android.os.Build.VERSION.SDK_INT
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.IBinder
+import android.os.Process
+import android.util.Log
+import com.android.location.provider.ProviderPropertiesUnbundled
+import com.android.location.provider.ProviderRequestUnbundled
+import java.io.FileDescriptor
+import java.io.PrintWriter
+
+abstract class IntentLocationProviderService : Service() {
+ private lateinit var handlerThread: HandlerThread
+ private lateinit var handler: Handler
+ private var bound: Boolean = false
+ private var provider: GenericLocationProvider? = null
+
+ override fun onCreate() {
+ super.onCreate()
+ handlerThread = HandlerThread(this.javaClass.simpleName)
+ handlerThread.start()
+ handler = Handler(handlerThread.looper)
+ }
+
+ abstract fun requestIntentUpdated(currentRequest: ProviderRequestUnbundled?, pendingIntent: PendingIntent?)
+
+ abstract fun stopIntentUpdated(pendingIntent: PendingIntent?)
+
+ abstract fun extractLocation(intent: Intent): Location?
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ if (Binder.getCallingUid() == Process.myUid() && intent?.action == ACTION_REPORT_LOCATION) {
+ handler.post {
+ val location = extractLocation(intent)
+ if (location != null) {
+ provider?.reportLocationToSystem(location)
+ }
+ }
+ }
+ return START_NOT_STICKY
+ }
+
+ override fun onBind(intent: Intent?): IBinder? {
+ bound = true
+ if (provider == null) {
+ provider = when {
+ // TODO: Migrate to Tiramisu provider. Not yet required thanks to backwards compat
+ // SDK_INT >= 33 ->
+ SDK_INT >= 31 ->
+ IntentLocationProviderPreTiramisu(this, properties)
+
+ else ->
+ @Suppress("DEPRECATION")
+ (IntentLocationProviderPreTiramisu(this, properties, Unit))
+ }
+ provider?.enable()
+ }
+ return provider?.getBinder()
+ }
+
+ override fun dump(fd: FileDescriptor, writer: PrintWriter, args: Array) {
+ writer.println("Bound: $bound")
+ provider?.dump(writer)
+ }
+
+ override fun onDestroy() {
+ if (SDK_INT >= 18) handlerThread.looper.quitSafely()
+ else handlerThread.looper.quit()
+ provider?.disable()
+ provider = null
+ bound = false
+ super.onDestroy()
+ }
+
+ abstract val minIntervalMillis: Long
+ abstract val minReportMillis: Long
+ abstract val properties: ProviderPropertiesUnbundled
+ abstract val providerName: String
+}
\ No newline at end of file
diff --git a/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/NetworkLocationProviderService.kt b/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/NetworkLocationProviderService.kt
index fb2cd9e27..2c96eeb79 100644
--- a/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/NetworkLocationProviderService.kt
+++ b/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/NetworkLocationProviderService.kt
@@ -5,73 +5,70 @@
package org.microg.gms.location.provider
-import android.app.Service
+import android.app.PendingIntent
import android.content.Intent
+import android.location.Criteria
import android.location.Location
-import android.os.*
+import android.location.LocationManager
import android.os.Build.VERSION.SDK_INT
-import org.microg.gms.location.EXTRA_LOCATION
-import java.io.FileDescriptor
-import java.io.PrintWriter
+import com.android.location.provider.ProviderPropertiesUnbundled
+import com.android.location.provider.ProviderRequestUnbundled
+import org.microg.gms.location.*
+import org.microg.gms.location.network.LOCATION_EXTRA_PRECISION
+import kotlin.math.max
-class NetworkLocationProviderService : Service() {
- private lateinit var handlerThread: HandlerThread
- private lateinit var handler: Handler
- private var bound: Boolean = false
- private var provider: GenericLocationProvider? = null
-
- override fun onCreate() {
- super.onCreate()
- handlerThread = HandlerThread(NetworkLocationProviderService::class.java.simpleName)
- handlerThread.start()
- handler = Handler(handlerThread.looper)
+class NetworkLocationProviderService : IntentLocationProviderService() {
+ override fun extractLocation(intent: Intent): Location? = intent.getParcelableExtra(EXTRA_LOCATION)?.apply {
+ extras?.remove(LOCATION_EXTRA_PRECISION)
}
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- if (Binder.getCallingUid() == Process.myUid() && intent?.action == ACTION_REPORT_LOCATION) {
- handler.post {
- val location = intent.getParcelableExtra(EXTRA_LOCATION)
- if (location != null) {
- provider?.reportLocationToSystem(location)
- }
- }
+ override fun requestIntentUpdated(currentRequest: ProviderRequestUnbundled?, pendingIntent: PendingIntent?) {
+ val forceNow: Boolean
+ val intervalMillis: Long
+ if (currentRequest?.reportLocation == true) {
+ forceNow = true
+ intervalMillis = max(currentRequest.interval ?: Long.MAX_VALUE, minIntervalMillis)
+ } else {
+ forceNow = false
+ intervalMillis = Long.MAX_VALUE
}
- return START_NOT_STICKY
- }
-
- override fun onBind(intent: Intent?): IBinder? {
- bound = true
- if (provider == null) {
- provider = when {
- // TODO: Migrate to Tiramisu provider. Not yet required thanks to backwards compat
- // SDK_INT >= 33 ->
- SDK_INT >= 31 ->
- NetworkLocationProviderPreTiramisu(this)
-
- else ->
- @Suppress("DEPRECATION")
- (NetworkLocationProviderPreTiramisu(this, Unit))
- }
- provider?.enable()
+ val intent = Intent(ACTION_NETWORK_LOCATION_SERVICE)
+ intent.`package` = packageName
+ intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent)
+ intent.putExtra(EXTRA_ENABLE, true)
+ intent.putExtra(EXTRA_INTERVAL_MILLIS, intervalMillis)
+ intent.putExtra(EXTRA_FORCE_NOW, forceNow)
+ if (SDK_INT >= 31) {
+ intent.putExtra(EXTRA_LOW_POWER, currentRequest?.isLowPower ?: false)
+ intent.putExtra(EXTRA_WORK_SOURCE, currentRequest?.workSource)
}
- return provider?.getBinder()
+ if (SDK_INT >= 29) {
+ intent.putExtra(EXTRA_BYPASS, currentRequest?.isLocationSettingsIgnored ?: false)
+ }
+ startService(intent)
}
- override fun dump(fd: FileDescriptor, writer: PrintWriter, args: Array) {
- writer.println("Bound: $bound")
- provider?.dump(writer)
+ override fun stopIntentUpdated(pendingIntent: PendingIntent?) {
+ val intent = Intent(ACTION_NETWORK_LOCATION_SERVICE)
+ intent.`package` = packageName
+ intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent)
+ intent.putExtra(EXTRA_ENABLE, false)
+ startService(intent)
}
- override fun onDestroy() {
- if (SDK_INT >= 18) handlerThread.looper.quitSafely()
- else handlerThread.looper.quit()
- provider?.disable()
- provider = null
- bound = false
- super.onDestroy()
- }
+ override val minIntervalMillis: Long
+ get() = MIN_INTERVAL_MILLIS
+ override val minReportMillis: Long
+ get() = MIN_REPORT_MILLIS
+ override val properties: ProviderPropertiesUnbundled
+ get() = PROPERTIES
+ override val providerName: String
+ get() = LocationManager.NETWORK_PROVIDER
+
companion object {
- const val ACTION_REPORT_LOCATION = "org.microg.gms.location.provider.ACTION_REPORT_LOCATION"
+ private const val MIN_INTERVAL_MILLIS = 20000L
+ private const val MIN_REPORT_MILLIS = 1000L
+ private val PROPERTIES = ProviderPropertiesUnbundled.create(false, false, false, false, true, true, true, Criteria.POWER_LOW, Criteria.ACCURACY_COARSE)
}
}
\ No newline at end of file
diff --git a/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/extensions.kt b/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/extensions.kt
index a99592a81..bc9c54c1f 100644
--- a/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/extensions.kt
+++ b/play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/extensions.kt
@@ -12,6 +12,8 @@ import com.google.android.gms.location.internal.ClientIdentity
const val TAG = "LocationProvider"
+const val ACTION_REPORT_LOCATION = "org.microg.gms.location.provider.ACTION_REPORT_LOCATION"
+
val GeocoderParams.clientIdentity: ClientIdentity?
get() = clientPackage?.let {
ClientIdentity(it).apply {