mirror of https://github.com/YTVanced/VancedMicroG
140 lines
5.3 KiB
Kotlin
140 lines
5.3 KiB
Kotlin
package org.microg.gms.location
|
|
|
|
import android.content.Context
|
|
import android.location.Location
|
|
import android.os.Bundle
|
|
import android.util.Log
|
|
import androidx.lifecycle.Lifecycle
|
|
import androidx.lifecycle.LifecycleOwner
|
|
import androidx.lifecycle.lifecycleScope
|
|
import kotlinx.coroutines.sync.Mutex
|
|
import kotlinx.coroutines.sync.withLock
|
|
import org.microg.nlp.client.LocationClient
|
|
import org.microg.nlp.service.api.Constants
|
|
import org.microg.nlp.service.api.ILocationListener
|
|
import org.microg.nlp.service.api.LocationRequest
|
|
import java.io.PrintWriter
|
|
import java.lang.Exception
|
|
import java.util.*
|
|
import kotlin.collections.ArrayList
|
|
|
|
class UnifiedLocationProvider(private val context: Context, private val changeListener: LocationChangeListener, private val lifecycle: Lifecycle): LifecycleOwner {
|
|
private val client: LocationClient = LocationClient(context, lifecycle)
|
|
private var lastLocation: Location? = null
|
|
private val requests: MutableList<LocationRequestHelper> = ArrayList()
|
|
private val activeRequestIds = hashSetOf<String>()
|
|
private val activeRequestMutex = Mutex(false)
|
|
private val listener: ILocationListener = object : ILocationListener.Stub() {
|
|
override fun onLocation(statusCode: Int, location: Location?) {
|
|
if (statusCode == Constants.STATUS_OK && location != null) {
|
|
lastLocation = Location(location)
|
|
try {
|
|
for (key in lastLocation?.extras?.keySet()?.toList().orEmpty()) {
|
|
if (key?.startsWith("org.microg.nlp.") == true) {
|
|
lastLocation?.extras?.remove(key)
|
|
}
|
|
}
|
|
} catch (e:Exception){
|
|
// Sometimes we need to define the correct ClassLoader before unparcel(). Ignore those.
|
|
}
|
|
changeListener.onLocationChanged()
|
|
}
|
|
}
|
|
}
|
|
private var ready = false
|
|
private val invokeOnceReady = hashSetOf<Runnable>()
|
|
|
|
init {
|
|
updateLastLocation()
|
|
}
|
|
|
|
private fun updateLastLocation() {
|
|
lifecycleScope.launchWhenStarted {
|
|
Log.d(TAG, "unified network: requesting last location")
|
|
val lastLocation = client.getLastLocation()
|
|
Log.d(TAG, "unified network: got last location: $lastLocation")
|
|
if (lastLocation != null) {
|
|
this@UnifiedLocationProvider.lastLocation = lastLocation
|
|
}
|
|
synchronized(invokeOnceReady) {
|
|
for (runnable in invokeOnceReady) {
|
|
runnable.run()
|
|
}
|
|
ready = true
|
|
}
|
|
}
|
|
}
|
|
|
|
fun invokeOnceReady(runnable: Runnable) {
|
|
synchronized(invokeOnceReady) {
|
|
if (ready) runnable.run()
|
|
else invokeOnceReady.add(runnable)
|
|
}
|
|
}
|
|
|
|
fun addRequest(request: LocationRequestHelper) {
|
|
Log.d(TAG, "unified network: addRequest $request")
|
|
for (i in 0..requests.size) {
|
|
if (i >= requests.size) break
|
|
val req = requests[i]
|
|
if (req.respondsTo(request.pendingIntent) || req.respondsTo(request.listener) || req.respondsTo(request.callback)) {
|
|
requests.removeAt(i)
|
|
}
|
|
}
|
|
requests.add(request)
|
|
updateConnection()
|
|
}
|
|
|
|
fun removeRequest(request: LocationRequestHelper) {
|
|
Log.d(TAG, "unified network: removeRequest $request")
|
|
requests.remove(request)
|
|
updateConnection()
|
|
}
|
|
|
|
fun getLastLocation(): Location? {
|
|
if (lastLocation == null) {
|
|
Log.d(TAG, "uh-ok: last location for unified network is null!")
|
|
}
|
|
return lastLocation
|
|
}
|
|
|
|
@Synchronized
|
|
private fun updateConnection() {
|
|
lifecycleScope.launchWhenStarted {
|
|
activeRequestMutex.withLock {
|
|
if (activeRequestIds.isNotEmpty() && requests.isEmpty()) {
|
|
Log.d(TAG, "unified network: no longer requesting location update")
|
|
for (id in activeRequestIds) {
|
|
client.cancelLocationRequestById(id)
|
|
}
|
|
activeRequestIds.clear()
|
|
} else if (requests.isNotEmpty()) {
|
|
val requests = ArrayList(requests).filter { it.isActive }
|
|
for (id in activeRequestIds.filter { id -> requests.none { it.id == id } }) {
|
|
client.cancelLocationRequestById(id)
|
|
}
|
|
for (request in requests.filter { it.id !in activeRequestIds }) {
|
|
client.updateLocationRequest(LocationRequest(listener, request.locationRequest.interval, request.locationRequest.numUpdates, request.id), Bundle().apply {
|
|
putString("packageName", request.packageName)
|
|
putString("source", "GoogleLocationManager")
|
|
})
|
|
activeRequestIds.add(request.id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun getLifecycle(): Lifecycle = lifecycle
|
|
|
|
fun dump(writer: PrintWriter) {
|
|
writer.println("network provider (via direct client):")
|
|
writer.println(" last location: $lastLocation")
|
|
writer.println(" ready: $ready")
|
|
}
|
|
|
|
companion object {
|
|
const val TAG = "GmsLocProviderU"
|
|
}
|
|
}
|