summaryrefslogtreecommitdiff
path: root/fakelocation
diff options
context:
space:
mode:
Diffstat (limited to 'fakelocation')
-rw-r--r--fakelocation/.gitignore1
-rw-r--r--fakelocation/build.gradle54
-rw-r--r--fakelocation/consumer-rules.pro0
-rw-r--r--fakelocation/fakelocationdemo/.gitignore1
-rw-r--r--fakelocation/fakelocationdemo/build.gradle71
-rw-r--r--fakelocation/fakelocationdemo/proguard-rules.pro21
-rw-r--r--fakelocation/fakelocationdemo/src/main/AndroidManifest.xml43
-rw-r--r--fakelocation/fakelocationdemo/src/main/java/foundation/e/privacymodules/fakelocationdemo/MainActivity.kt209
-rw-r--r--fakelocation/fakelocationdemo/src/main/res/layout/activity_main.xml130
-rw-r--r--fakelocation/fakelocationdemo/src/main/res/values/colors.xml27
-rw-r--r--fakelocation/fakelocationdemo/src/main/res/values/strings.xml20
-rw-r--r--fakelocation/fakelocationdemo/src/main/res/values/themes.xml33
-rw-r--r--fakelocation/proguard-rules.pro21
-rw-r--r--fakelocation/src/main/AndroidManifest.xml32
-rw-r--r--fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/FakeLocationModule.kt117
-rw-r--r--fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/FakeLocationService.kt112
16 files changed, 892 insertions, 0 deletions
diff --git a/fakelocation/.gitignore b/fakelocation/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/fakelocation/.gitignore
@@ -0,0 +1 @@
+/build \ No newline at end of file
diff --git a/fakelocation/build.gradle b/fakelocation/build.gradle
new file mode 100644
index 0000000..ea28e44
--- /dev/null
+++ b/fakelocation/build.gradle
@@ -0,0 +1,54 @@
+/*
+ * 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/>.
+ */
+
+plugins {
+ id 'com.android.library'
+ id 'org.jetbrains.kotlin.android'
+}
+
+android {
+ compileSdkVersion buildConfig.compileSdk
+
+ defaultConfig {
+ minSdkVersion buildConfig.minSdk
+ targetSdkVersion buildConfig.targetSdk
+
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+}
+
+dependencies {
+ implementation (
+ Libs.Kotlin.stdlib,
+ Libs.AndroidX.coreKtx,
+ Libs.Coroutines.core
+ )
+}
diff --git a/fakelocation/consumer-rules.pro b/fakelocation/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fakelocation/consumer-rules.pro
diff --git a/fakelocation/fakelocationdemo/.gitignore b/fakelocation/fakelocationdemo/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/fakelocation/fakelocationdemo/.gitignore
@@ -0,0 +1 @@
+/build \ No newline at end of file
diff --git a/fakelocation/fakelocationdemo/build.gradle b/fakelocation/fakelocationdemo/build.gradle
new file mode 100644
index 0000000..12ed2e7
--- /dev/null
+++ b/fakelocation/fakelocationdemo/build.gradle
@@ -0,0 +1,71 @@
+/*
+ * 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/>.
+ */
+
+plugins {
+ id 'com.android.application'
+ id 'org.jetbrains.kotlin.android'
+}
+
+android {
+ compileSdkVersion buildConfig.compileSdk
+
+ defaultConfig {
+ applicationId "foundation.e.privacymodules.fakelocationdemo"
+ minSdkVersion buildConfig.minSdk
+ targetSdkVersion buildConfig.targetSdk
+
+ versionCode buildConfig.version.code
+ versionName buildConfig.version.name
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ allWarningsAsErrors = false
+ }
+ buildFeatures {
+ dataBinding true
+ }
+}
+
+dependencies {
+ implementation project(':api')
+ implementation project(':fakelocation')
+ implementation project(':permissionsstandalone')
+
+
+ implementation (
+ Libs.Kotlin.stdlib,
+ Libs.AndroidX.coreKtx,
+ Libs.AndroidX.appCompat,
+ Libs.material,
+ )
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+} \ No newline at end of file
diff --git a/fakelocation/fakelocationdemo/proguard-rules.pro b/fakelocation/fakelocationdemo/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/fakelocation/fakelocationdemo/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile \ No newline at end of file
diff --git a/fakelocation/fakelocationdemo/src/main/AndroidManifest.xml b/fakelocation/fakelocationdemo/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..202599a
--- /dev/null
+++ b/fakelocation/fakelocationdemo/src/main/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?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"
+ package="foundation.e.privacymodules.fakelocationdemo"
+ >
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+
+ <application
+ android:allowBackup="true"
+ android:label="@string/app_name"
+ android:theme="@style/Theme.PrivacyCentralApp"
+ >
+ <activity
+ android:exported="true"
+ android:name=".MainActivity"
+ >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/fakelocation/fakelocationdemo/src/main/java/foundation/e/privacymodules/fakelocationdemo/MainActivity.kt b/fakelocation/fakelocationdemo/src/main/java/foundation/e/privacymodules/fakelocationdemo/MainActivity.kt
new file mode 100644
index 0000000..1b0a35b
--- /dev/null
+++ b/fakelocation/fakelocationdemo/src/main/java/foundation/e/privacymodules/fakelocationdemo/MainActivity.kt
@@ -0,0 +1,209 @@
+/*
+ * 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.fakelocationdemo
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.content.Context
+import android.content.pm.PackageManager
+import android.location.Location
+import android.location.LocationListener
+import android.location.LocationManager
+import android.os.Bundle
+import android.os.Process.myUid
+import android.util.Log
+import android.view.View
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.databinding.DataBindingUtil
+import foundation.e.privacymodules.fakelocation.FakeLocationModule
+import foundation.e.privacymodules.fakelocationdemo.databinding.ActivityMainBinding
+import foundation.e.privacymodules.permissions.PermissionsPrivacyModule
+import foundation.e.privacymodules.permissions.data.AppOpModes
+import foundation.e.privacymodules.permissions.data.ApplicationDescription
+
+class MainActivity : AppCompatActivity() {
+ companion object {
+ const val TAG = "fakeLoc"
+ }
+
+ private val fakeLocationModule: FakeLocationModule by lazy { FakeLocationModule(this) }
+ private val permissionsModule by lazy { PermissionsPrivacyModule(this) }
+
+ private lateinit var binding: ActivityMainBinding
+
+ private val appDesc by lazy {
+ ApplicationDescription(
+ packageName = packageName,
+ uid = myUid(),
+ label = getString(R.string.app_name),
+ icon = null
+ )
+ }
+
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
+
+ actionBar?.setDisplayHomeAsUpEnabled(true)
+
+ binding.view = this
+ }
+
+ override fun onResume() {
+ super.onResume()
+ updateData("")
+ }
+
+ private fun updateData(mockedLocation: String) {
+ binding.granted = permissionsModule.getAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION) == AppOpModes.ALLOWED
+
+ binding.mockedLocation = mockedLocation
+ }
+
+ private val listener = object: LocationListener {
+ override fun onLocationChanged(location: Location) {
+ binding.currentLocation = "lat: ${location.latitude} - lon: ${location.longitude}"
+ }
+
+ override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
+ TODO("Not yet implemented")
+ }
+
+ override fun onProviderEnabled(provider: String) {
+ binding.providerInfo = "onProdivderEnabled: $provider"
+ }
+
+ override fun onProviderDisabled(provider: String) {
+ binding.providerInfo = "onProdivderDisabled: $provider"
+ }
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onClickToggleListenLocation(view: View?) {
+ val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
+
+ if (binding.toggleListenLocation.isChecked) {
+ requireLocationPermissions()
+ return
+ }
+
+ locationManager.removeUpdates(listener)
+ binding.currentLocation = "no listening"
+ }
+
+ private fun startLocationUpdates() {
+ val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
+
+ try {
+ Log.d(TAG, "requestLocationUpdates")
+ locationManager.requestLocationUpdates(
+ LocationManager.GPS_PROVIDER, // TODO: tight this with fakelocation module.
+ 1000L,
+ 1f,
+ listener
+ )
+ binding.currentLocation = "listening started"
+ } catch (se: SecurityException) {
+ Log.e(TAG, "Missing permission", se)
+ }
+ }
+
+ private val locationPermissionRequest = registerForActivityResult(
+ ActivityResultContracts.RequestMultiplePermissions()
+ ) { permissions ->
+ if (permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false)
+ || permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false)
+ ) {
+ startLocationUpdates()
+ }
+ }
+
+ private fun requireLocationPermissions() {
+ if (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
+ startLocationUpdates()
+ } else {
+ // Before you perform the actual permission request, check whether your app
+ // already has the permissions, and whether your app needs to show a permission
+ // rationale dialog. For more details, see Request permissions.
+ locationPermissionRequest.launch(
+ arrayOf(
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ )
+ )
+ }
+
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onClickPermission(view: View?) {
+ val isGranted = permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION,
+ AppOpModes.ALLOWED)
+
+ if (isGranted) {
+ updateData("")
+ return
+ }
+ //dev mode disabled
+ val alertDialog = AlertDialog.Builder(this)
+ alertDialog
+ .setTitle("Mock location disabled")
+ .setNegativeButton("Cancel") { _, _ ->
+ }
+ alertDialog.create().show()
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onClickReset(view: View?) {
+ try {
+ fakeLocationModule.stopFakeLocation()
+ } catch(e: Exception) {
+ Log.e(TAG, "Can't stop FakeLocation", e)
+ }
+ }
+
+ private fun setFakeLocation(latitude: Double, longitude: Double) {
+ try {
+ fakeLocationModule.startFakeLocation()
+ } catch(e: Exception) {
+ Log.e(TAG, "Can't startFakeLocation", e)
+ }
+ fakeLocationModule.setFakeLocation(latitude, longitude)
+ updateData("lat: ${latitude} - lon: ${longitude}")
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onClickParis(view: View?) {
+ setFakeLocation(48.8502282, 2.3542286)
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onClickLondon(view: View?) {
+ setFakeLocation(51.5287718, -0.2416803)
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onClickAmsterdam(view: View?) {
+ setFakeLocation(52.3547498, 4.8339211)
+ }
+}
diff --git a/fakelocation/fakelocationdemo/src/main/res/layout/activity_main.xml b/fakelocation/fakelocationdemo/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..33fce69
--- /dev/null
+++ b/fakelocation/fakelocationdemo/src/main/res/layout/activity_main.xml
@@ -0,0 +1,130 @@
+<?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/>.
+ -->
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+ <data>
+ <variable name="granted" type="Boolean" />
+ <variable name="mockedLocation" type="String" />
+ <variable name="currentLocation" type="String" />
+ <variable name="providerInfo" type="String" />
+ <variable name="view" type="foundation.e.privacymodules.fakelocationdemo.MainActivity" />
+ </data>
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="24dp">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Fake location requires a specific permissions to work."
+ />
+ <androidx.appcompat.widget.SwitchCompat
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="@{granted}"
+ android:onClick="@{view::onClickPermission}"
+ />
+ </LinearLayout>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="True location"
+ android:onClick="@{view::onClickReset}"
+ />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="Paris"
+ android:onClick="@{view::onClickParis}"
+ />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="London"
+ android:onClick="@{view::onClickLondon}"
+ />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="Amsterdam"
+ android:onClick="@{view::onClickAmsterdam}"
+ />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Listen to location"
+ />
+ <androidx.appcompat.widget.SwitchCompat
+ android:id="@+id/toggle_listen_location"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:onClick="@{view::onClickToggleListenLocation}"
+ />
+ </LinearLayout>
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Mocked location:"
+ android:textStyle="bold"
+ />
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="@{mockedLocation}"
+ />
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Current Location:"
+ android:textStyle="bold"
+ />
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="@{currentLocation}"
+ />
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@{providerInfo}"
+ />
+ </LinearLayout>
+ </androidx.core.widget.NestedScrollView>
+</layout> \ No newline at end of file
diff --git a/fakelocation/fakelocationdemo/src/main/res/values/colors.xml b/fakelocation/fakelocationdemo/src/main/res/values/colors.xml
new file mode 100644
index 0000000..29591a8
--- /dev/null
+++ b/fakelocation/fakelocationdemo/src/main/res/values/colors.xml
@@ -0,0 +1,27 @@
+<?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/>.
+ -->
+
+<resources>
+ <color name="purple_200">#FFBB86FC</color>
+ <color name="purple_500">#FF6200EE</color>
+ <color name="purple_700">#FF3700B3</color>
+ <color name="teal_200">#FF03DAC5</color>
+ <color name="teal_700">#FF018786</color>
+ <color name="black">#FF000000</color>
+ <color name="white">#FFFFFFFF</color>
+</resources> \ No newline at end of file
diff --git a/fakelocation/fakelocationdemo/src/main/res/values/strings.xml b/fakelocation/fakelocationdemo/src/main/res/values/strings.xml
new file mode 100644
index 0000000..17b69db
--- /dev/null
+++ b/fakelocation/fakelocationdemo/src/main/res/values/strings.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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/>.
+ -->
+
+<resources>
+ <string name="app_name">FakeLocationDemo</string>
+</resources> \ No newline at end of file
diff --git a/fakelocation/fakelocationdemo/src/main/res/values/themes.xml b/fakelocation/fakelocationdemo/src/main/res/values/themes.xml
new file mode 100644
index 0000000..9ce6d28
--- /dev/null
+++ b/fakelocation/fakelocationdemo/src/main/res/values/themes.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ 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/>.
+ -->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <!-- Base application theme. -->
+ <style name="Theme.PrivacyCentralApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+ <!-- Primary brand color. -->
+ <item name="colorPrimary">@color/purple_500</item>
+ <item name="colorPrimaryVariant">@color/purple_700</item>
+ <item name="colorOnPrimary">@color/white</item>
+ <!-- Secondary brand color. -->
+ <item name="colorSecondary">@color/teal_200</item>
+ <item name="colorSecondaryVariant">@color/teal_700</item>
+ <item name="colorOnSecondary">@color/black</item>
+ <!-- Status bar color. -->
+ <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
+ <!-- Customize your theme here. -->
+ </style>
+</resources> \ No newline at end of file
diff --git a/fakelocation/proguard-rules.pro b/fakelocation/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/fakelocation/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile \ No newline at end of file
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
+ }
+}