diff options
Diffstat (limited to 'fakelocation/src')
3 files changed, 261 insertions, 0 deletions
diff --git a/fakelocation/src/main/AndroidManifest.xml b/fakelocation/src/main/AndroidManifest.xml new file mode 100644 index 0000000..5077c24 --- /dev/null +++ b/fakelocation/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 E FOUNDATION + ~ + ~ This program is free software: you can redistribute it and/or modify + ~ it under the terms of the GNU General Public License as published by + ~ the Free Software Foundation, either version 3 of the License, or + ~ (at your option) any later version. + ~ + ~ This program is distributed in the hope that it will be useful, + ~ but WITHOUT ANY WARRANTY; without even the implied warranty of + ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ~ GNU General Public License for more details. + ~ + ~ You should have received a copy of the GNU General Public License + ~ along with this program. If not, see <https://www.gnu.org/licenses/>. + --> + +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="foundation.e.privacymodules.fakelocation" + > + + <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" + tools:ignore="MockLocation,ProtectedPermissions" /> + + <application> + <service android:name="foundation.e.privacymodules.fakelocation.FakeLocationService" + android:enabled="true" /> + </application> +</manifest>
\ No newline at end of file diff --git a/fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/FakeLocationModule.kt b/fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/FakeLocationModule.kt new file mode 100644 index 0000000..43a4545 --- /dev/null +++ b/fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/FakeLocationModule.kt @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2022 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package foundation.e.privacymodules.fakelocation + +import android.content.Context +import android.content.Context.LOCATION_SERVICE +import android.location.Criteria +import android.location.Location +import android.location.LocationManager +import android.os.Build +import android.os.SystemClock +import android.util.Log + +/** + * Implementation of the functionality of fake location. + * All of them are available for normal application, so just one version is enough. + * + * @param context an Android context, to retrieve system services for example. + */ +class FakeLocationModule(protected val context: Context) { + + /** + * List of all the Location provider that will be mocked. + */ + private val providers = listOf(LocationManager.NETWORK_PROVIDER, LocationManager.GPS_PROVIDER) + + /** + * Handy accessor to the locationManager service. + * We avoid getting it on module initialization to wait for the context to be ready. + */ + private val locationManager: LocationManager get() = + context.getSystemService(LOCATION_SERVICE) as LocationManager + + /** + * @see IFakeLocationModule.startFakeLocation + */ + @Synchronized + fun startFakeLocation() { + providers.forEach { provider -> + try { + locationManager.removeTestProvider(provider) + } catch(e: Exception) { + Log.d("FakeLocationModule", "Test provider $provider already removed.") + } + + locationManager.addTestProvider( + provider, + false, + false, + false, + false, + false, + true, + true, + Criteria.POWER_LOW, Criteria.ACCURACY_FINE) + locationManager.setTestProviderEnabled(provider, true) + } + } + + fun setFakeLocation(latitude: Double, longitude: Double) { + context.startService(FakeLocationService.buildFakeLocationIntent(context, latitude, longitude)) + } + + internal fun setTestProviderLocation(latitude: Double, longitude: Double) { + providers.forEach { provider -> + val location = Location(provider) + location.latitude = latitude + location.longitude = longitude + + // Set default value for all the other required fields. + location.altitude = 3.0 + location.time = System.currentTimeMillis() + location.speed = 0.01f + location.bearing = 1f + location.accuracy = 3f + 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 + } + + locationManager.setTestProviderLocation(provider, location) + } + } + + /** + * @see IFakeLocationModule.stopFakeLocation + */ + fun stopFakeLocation() { + context.stopService(FakeLocationService.buildStopIntent(context)) + providers.forEach { provider -> + try { + locationManager.setTestProviderEnabled(provider, false) + locationManager.removeTestProvider(provider) + } catch (e: Exception) { + Log.d("FakeLocationModule", "Test provider $provider already removed.") + } + } + } +} diff --git a/fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/FakeLocationService.kt b/fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/FakeLocationService.kt new file mode 100644 index 0000000..1337ddd --- /dev/null +++ b/fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/FakeLocationService.kt @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2022 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package foundation.e.privacymodules.fakelocation + + +import android.app.Service +import android.content.Context +import android.content.Intent +import android.os.CountDownTimer +import android.os.IBinder +import android.util.Log + +class FakeLocationService: Service() { + + enum class Actions { + START_FAKE_LOCATION + } + + companion object { + private const val PERIOD_LOCATION_UPDATE = 1000L + private const val PERIOD_UPDATES_SERIE = 2 * 60 * 1000L + + private const val PARAM_LATITUDE = "PARAM_LATITUDE" + private const val PARAM_LONGITUDE = "PARAM_LONGITUDE" + + fun buildFakeLocationIntent(context: Context, latitude: Double, longitude: Double): Intent { + return Intent(context, FakeLocationService::class.java).apply { + action = Actions.START_FAKE_LOCATION.name + putExtra(PARAM_LATITUDE, latitude) + putExtra(PARAM_LONGITUDE, longitude) + } + } + + fun buildStopIntent(context: Context) = Intent(context, FakeLocationService::class.java) + } + + private lateinit var fakeLocationModule: FakeLocationModule + + private var countDownTimer: CountDownTimer? = null + + private var fakeLocation: Pair<Double, Double>? = null + + override fun onCreate() { + super.onCreate() + fakeLocationModule = FakeLocationModule(applicationContext) + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + intent?.let { + when (it.action?.let { str -> Actions.valueOf(str) }) { + Actions.START_FAKE_LOCATION -> { + + fakeLocation = Pair( + it.getDoubleExtra(PARAM_LATITUDE, 0.0), + it.getDoubleExtra(PARAM_LONGITUDE, 0.0) + ) + initTimer() + } + else -> {} + } + } + + return START_STICKY + } + + override fun onDestroy() { + countDownTimer?.cancel() + super.onDestroy() + } + + + private fun initTimer() { + countDownTimer?.cancel() + countDownTimer = object: CountDownTimer(PERIOD_UPDATES_SERIE, PERIOD_LOCATION_UPDATE) { + override fun onTick(millisUntilFinished: Long) { + fakeLocation?.let { + try { + fakeLocationModule.setTestProviderLocation( + it.first, + it.second + ) + } catch (e: Exception) { + Log.d("FakeLocationService", "setting fake location", e) + } + } + } + + override fun onFinish() { + initTimer() + } + }.start() + } + + override fun onBind(intent: Intent?): IBinder? { + return null + } +} |