Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f21765d authored by Guillaume Jacquart's avatar Guillaume Jacquart
Browse files

feat:8489: Quickly return fake location.

parent 049740ca
Loading
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -3,7 +3,9 @@ package org.microg.gms.location.manager
import android.content.Context
import android.location.Location
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.SystemClock
import com.google.android.gms.location.internal.ClientIdentity

object FakeLocationResolver {
@@ -13,6 +15,8 @@ object FakeLocationResolver {
    private val PARAM_LATITUDE = "latitude"
    private val PARAM_LONGITUDE = "longitude"

    private val FAKE_LOCATION_PROVIDER = "fused"

    private data class FakeLocation(var latitude: Double, var longitude: Double)

    fun fakeLocation(
@@ -26,6 +30,34 @@ object FakeLocationResolver {
        return overrideLatLon(baseLocation, latLon)
    }

    fun buildFakeLocation(
        context: Context,
        identity: ClientIdentity,
    ): Location? {
        val latLon = getFakeLocation(context, identity.packageName, identity.uid)
            ?: return null

        val location = Location(FAKE_LOCATION_PROVIDER)
        location.latitude = latLon.latitude
        location.longitude = latLon.longitude

        // Set default value for all the other required fields.
        location.accuracy = 3f
        location.altitude = 3.0
        location.bearing = 1f
        location.speed = 0.01f
        location.time = System.currentTimeMillis()
        location.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            location.bearingAccuracyDegrees = 0.1f
            location.verticalAccuracyMeters = 0.1f
            location.speedAccuracyMetersPerSecond = 0.01f
        }

        return location
    }

    private fun getFakeLocation(context: Context, packageName: String, uid: Int): FakeLocation? {
        return runCatching {
            context.contentResolver.call(
+1 −6
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ class LocationManager(private val context: Context, override val lifecycle: Life
        val permissionGranularity = context.granularityFromPermission(clientIdentity)
        var effectiveGranularity = getEffectiveGranularity(request.granularity, permissionGranularity)
        if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(clientIdentity.packageName) && !clientIdentity.isSelfUser()) effectiveGranularity = GRANULARITY_COARSE
        val baseLocation = if (effectiveGranularity > permissionGranularity) {
        val returnedLocation = if (effectiveGranularity > permissionGranularity) {
            // No last location available at requested granularity due to lack of permission
            null
        } else {
@@ -99,11 +99,6 @@ class LocationManager(private val context: Context, override val lifecycle: Life
                processedLocation
            }
        }

        val returnedLocation = baseLocation?.let {
            FakeLocationResolver.fakeLocation(context, clientIdentity, it)
        }

        if (!clientIdentity.isSelfUser()) database.noteAppLocation(clientIdentity.packageName, returnedLocation)
        return returnedLocation?.let { Location(it).apply { provider = "fused" } }
    }
+48 −14
Original line number Diff line number Diff line
@@ -164,6 +164,13 @@ class LocationManagerInstance(
                        scope.cancel()
                    }
                }

                val fakeLocation = FakeLocationResolver.buildFakeLocation(context, clientIdentity)
                if (fakeLocation != null) {
                    launch {
                        callbackForRequest.onLocationResult(LocationResult.create(listOf(fakeLocation)))
                    }
                } else {
                    val currentLocationRequest = LocationRequest.Builder(request.priority, 1000)
                        .setGranularity(request.granularity)
                        .setMaxUpdateAgeMillis(request.maxUpdateAgeMillis)
@@ -173,6 +180,7 @@ class LocationManagerInstance(
                        .setThrottleBehavior(request.throttleBehavior)
                        .build()
                    locationManager.addBinderRequest(clientIdentity, binderIdentity, callbackForRequest, currentLocationRequest)
                }
                awaitCancellation()
            } catch (e: CancellationException) {
                // Don't send result. Either this was cancelled from the CancelToken or because a location was retrieved.
@@ -204,7 +212,12 @@ class LocationManagerInstance(
        val clientIdentity = getClientIdentity()
        lifecycleScope.launchWhenStarted {
            try {
                val fakeLocation = FakeLocationResolver.buildFakeLocation(context, clientIdentity)
                if (fakeLocation != null) {
                    callback.onLocationStatus(Status.SUCCESS, fakeLocation)
                } else {
                    callback.onLocationStatus(Status.SUCCESS, locationManager.getLastLocation(clientIdentity, request))
                }
            } catch (e: Exception) {
                try {
                    callback.onLocationStatus(Status(CommonStatusCodes.ERROR, e.message), null)
@@ -303,8 +316,16 @@ class LocationManagerInstance(
        val clientIdentity = getClientIdentity()
        lifecycleScope.launchWhenStarted {
            try {
                val fakeLocation = FakeLocationResolver.buildFakeLocation(context, clientIdentity)
                if (fakeLocation != null) {
                    statusCallback.onResult(Status.SUCCESS)
                    launch {
                        callback.onLocationResult(LocationResult.create(listOf(fakeLocation)))
                    }
                } else {
                    locationManager.updateBinderRequest(clientIdentity, oldBinder, binder, callback, request)
                    statusCallback.onResult(Status.SUCCESS)
                }
            } catch (e: Exception) {
                try {
                    statusCallback.onResult(Status(CommonStatusCodes.ERROR, e.message))
@@ -321,8 +342,21 @@ class LocationManagerInstance(
        val clientIdentity = getClientIdentity()
        lifecycleScope.launchWhenStarted {
            try {
                val fakeLocation = FakeLocationResolver.buildFakeLocation(context, clientIdentity)
                if (fakeLocation != null) {
                    statusCallback.onResult(Status.SUCCESS)
                    launch {
                        pendingIntent.send(context, 0, Intent().apply {
                            putExtra(
                                LocationResult.EXTRA_LOCATION_RESULT,
                                LocationResult.create(listOf(fakeLocation))
                            )
                        })
                    }
                } else {
                    locationManager.addIntentRequest(clientIdentity, pendingIntent, request)
                    statusCallback.onResult(Status.SUCCESS)
                }
            } catch (e: Exception) {
                try {
                    statusCallback.onResult(Status(CommonStatusCodes.ERROR, e.message))