From 5db0bdfdf62ae0915b587399a0ff4ce53bca813b Mon Sep 17 00:00:00 2001 From: Leonard Kugis Date: Tue, 2 Jan 2024 17:53:12 +0100 Subject: Implemented route mode --- .../domain/usecases/FakeLocationModule.kt | 9 ++ .../fakelocation/services/FakeLocationService.kt | 108 ++++++++++++++++++--- 2 files changed, 106 insertions(+), 11 deletions(-) (limited to 'fakelocation/src') diff --git a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/domain/usecases/FakeLocationModule.kt b/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/domain/usecases/FakeLocationModule.kt index 89d5628..7424f38 100644 --- a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/domain/usecases/FakeLocationModule.kt +++ b/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/domain/usecases/FakeLocationModule.kt @@ -29,6 +29,7 @@ import android.os.Build import android.os.SystemClock import android.util.Log import foundation.e.advancedprivacy.fakelocation.services.FakeLocationService +import foundation.e.advancedprivacy.domain.entities.FakeLocationCoordinate /** * Implementation of the functionality of fake location. @@ -86,6 +87,14 @@ class FakeLocationModule(private val context: Context) { } } + fun routeStart(route: List, loopEnabled: Boolean) { + context.startService(FakeLocationService.buildRouteIntent(context, route, loopEnabled)) + } + + fun routeStop() { + context.stopService(FakeLocationService.buildStopIntent(context)) + } + fun setFakeLocation(altitude: Double, speed: Float, jitter: Float, latitude: Double, longitude: Double) { context.startService(FakeLocationService.buildFakeLocationIntent(context, altitude, speed, jitter, latitude, longitude)) } diff --git a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/services/FakeLocationService.kt b/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/services/FakeLocationService.kt index 2d85e6c..c388afc 100644 --- a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/services/FakeLocationService.kt +++ b/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/services/FakeLocationService.kt @@ -25,13 +25,18 @@ import android.os.CountDownTimer import android.os.IBinder import android.util.Log import foundation.e.advancedprivacy.fakelocation.domain.usecases.FakeLocationModule +import foundation.e.advancedprivacy.domain.entities.FakeLocationCoordinate +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import kotlin.math.sqrt import kotlin.random.Random class FakeLocationService : Service() { enum class Actions { - START_FAKE_LOCATION + START_FAKE_LOCATION, + START_ROUTE } companion object { @@ -43,6 +48,8 @@ class FakeLocationService : Service() { private const val PARAM_JITTER = "PARAM_JITTER" private const val PARAM_LATITUDE = "PARAM_LATITUDE" private const val PARAM_LONGITUDE = "PARAM_LONGITUDE" + private const val PARAM_ROUTE = "PARAM_ROUTE" + private const val PARAM_ROUTE_LOOP = "PARAM_ROUTE_LOOP" fun buildFakeLocationIntent(context: Context, altitude: Double, speed: Float, jitter: Float, latitude: Double, longitude: Double): Intent { return Intent(context, FakeLocationService::class.java).apply { @@ -55,12 +62,22 @@ class FakeLocationService : Service() { } } + fun buildRouteIntent(context: Context, route: List, loopRoute: Boolean): Intent { + return Intent(context, FakeLocationService::class.java).apply { + action = Actions.START_ROUTE.name + putExtra(PARAM_ROUTE, Gson().toJson(route)) + putExtra(PARAM_ROUTE_LOOP, loopRoute) + } + } + fun buildStopIntent(context: Context) = Intent(context, FakeLocationService::class.java) } private lateinit var fakeLocationModule: FakeLocationModule - private var countDownTimer: CountDownTimer? = null + private var cdtFakeLocation: CountDownTimer? = null + private var cdtRoute: CountDownTimer? = null + private var routeTime: Float = 0f private var altitude: Double? = null private var speed: Float? = null @@ -68,6 +85,10 @@ class FakeLocationService : Service() { private var fakeLocation: Pair? = null + private var route: List? = null + private var loopRoute: Boolean = false + private var routeReversed: Boolean = false + override fun onCreate() { super.onCreate() fakeLocationModule = FakeLocationModule(applicationContext) @@ -84,7 +105,12 @@ class FakeLocationService : Service() { it.getDoubleExtra(PARAM_LATITUDE, 0.0), it.getDoubleExtra(PARAM_LONGITUDE, 0.0) ) - initTimer() + initTimerFakeLocation() + } + Actions.START_ROUTE -> { + route = Gson().fromJson(it.getStringExtra(PARAM_ROUTE) ?: "[]", object : TypeToken>() {}.type) + loopRoute = it.getBooleanExtra(PARAM_ROUTE_LOOP, false) + initTimerRoute() } else -> {} } @@ -94,13 +120,14 @@ class FakeLocationService : Service() { } override fun onDestroy() { - countDownTimer?.cancel() + cdtFakeLocation?.cancel() + cdtRoute?.cancel() super.onDestroy() } - private fun initTimer() { - countDownTimer?.cancel() - countDownTimer = object : CountDownTimer(PERIOD_UPDATES_SERIE, PERIOD_LOCATION_UPDATE) { + private fun initTimerFakeLocation() { + cdtFakeLocation?.cancel() + cdtFakeLocation = object : CountDownTimer(PERIOD_UPDATES_SERIE, PERIOD_LOCATION_UPDATE) { override fun onTick(millisUntilFinished: Long) { var altitude_buf: Double = altitude ?: return var speed_buf: Float = speed ?: return @@ -109,11 +136,11 @@ class FakeLocationService : Service() { if(fakeLocation != null && altitude != null && speed != null && jitter != null) { try { fakeLocationModule.setTestProviderLocation( - altitude_buf + ((Random.nextFloat() * jitter_buf) - (jitter_buf * 0.5f)), + (altitude_buf + ((Random.nextFloat() * jitter_buf) - (jitter_buf * 0.5f))).toDouble(), speed_buf + ((Random.nextFloat() * jitter_buf) - (jitter_buf * 0.5f)), jitter_buf, - fakeLocation_buf.first + (((Random.nextFloat() * jitter_buf) - (jitter_buf * 0.5f)) / 111139.0f), - fakeLocation_buf.second + (((Random.nextFloat() * jitter_buf) - (jitter_buf * 0.5f)) / 111139.0f) + (fakeLocation_buf.first + (((Random.nextFloat() * jitter_buf) - (jitter_buf * 0.5f)) / 111139.0f)).toDouble(), + (fakeLocation_buf.second + (((Random.nextFloat() * jitter_buf) - (jitter_buf * 0.5f)) / 111139.0f)).toDouble() ) } catch (e: Exception) { Log.d("FakeLocationService", "setting fake location", e) @@ -122,7 +149,66 @@ class FakeLocationService : Service() { } override fun onFinish() { - initTimer() + initTimerFakeLocation() + } + }.start() + } + + private fun calculateRouteSegment(route: List, routeTime: Float): Pair>? { + if(route.size < 2) + return null + var prev = route.first() + var timeCurrent: Float = 0f + do { + var route_current = if(routeReversed) route.reversed() else route + for(coord in route_current) { + var direction = Pair((coord.latitude - prev.latitude) * 111139.0f, (coord.longitude - prev.longitude) * 111139.0f) + if(!(coord.latitude == prev.latitude && coord.longitude == prev.longitude)) { + var distance_target = sqrt((direction.first * direction.first) + (direction.second * direction.second)) + var direction_unit = Pair(direction.first / distance_target, direction.second / distance_target) + var location_meters = Pair(direction_unit.first * (routeTime - timeCurrent) * prev.speed, + direction_unit.second * (routeTime - timeCurrent) * prev.speed) + var distance_current = sqrt((location_meters.first * location_meters.first) + (location_meters.second - location_meters.second)) + var location = Pair(prev.latitude + (location_meters.first / 111139.0f), prev.longitude + (location_meters.second / 111139.0f)) + if(distance_current < distance_target) + return Pair>(prev, location) + timeCurrent += distance_target / prev.speed + prev = coord + } + } + if(loopRoute) + routeReversed = !routeReversed + } while(loopRoute) + return null + } + + private fun initTimerRoute() { + cdtRoute?.cancel() + routeTime = 0f + cdtRoute = object : CountDownTimer(PERIOD_UPDATES_SERIE, PERIOD_LOCATION_UPDATE) { + override fun onTick(millisUntilFinished: Long) { + var route_buf: List = route ?: return + var coord = calculateRouteSegment(route_buf, routeTime) + if(coord == null) { + // done with route + return + } + try { + fakeLocationModule.setTestProviderLocation( + (coord.first.altitude + ((Random.nextFloat() * coord.first.jitter) - (coord.first.jitter * 0.5f))).toDouble(), + coord.first.speed + ((Random.nextFloat() * coord.first.jitter) - (coord.first.jitter * 0.5f)), + coord.first.jitter, + (coord.second.first + (((Random.nextFloat() * coord.first.jitter) - (coord.first.jitter * 0.5f)) / 111139.0f)).toDouble(), + (coord.second.second + (((Random.nextFloat() * coord.first.jitter) - (coord.first.jitter * 0.5f)) / 111139.0f)).toDouble() + ) + } catch (e: Exception) { + Log.d("FakeLocationService", "setting fake location", e) + } + routeTime += (PERIOD_LOCATION_UPDATE / 1000f) + } + + override fun onFinish() { + initTimerRoute() } }.start() } -- cgit v1.2.1