summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt222
-rw-r--r--app/src/main/res/drawable/ic_valid.xml10
-rw-r--r--app/src/main/res/layout/fragment_fake_location.xml78
-rw-r--r--app/src/main/res/values/colors.xml1
-rw-r--r--app/src/main/res/values/strings.xml18
6 files changed, 174 insertions, 159 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4babd46..58b6dfd 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -19,7 +19,9 @@
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
- android:theme="@style/Theme.PrivacyCentralApp">
+ android:theme="@style/Theme.PrivacyCentralApp"
+ android:windowSoftInputMode="adjustResize"
+ >
<activity android:name=".main.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt
index bb9bd26..bdc405e 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt
@@ -26,16 +26,19 @@ import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
-import android.widget.EditText
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.RadioButton
import android.widget.Toast
import androidx.annotation.NonNull
+import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
+import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
+import com.google.android.material.textfield.TextInputLayout.END_ICON_CUSTOM
+import com.google.android.material.textfield.TextInputLayout.END_ICON_NONE
import com.mapbox.android.core.location.LocationEngineCallback
import com.mapbox.android.core.location.LocationEngineRequest
import com.mapbox.android.core.location.LocationEngineResult
@@ -56,6 +59,7 @@ import foundation.e.privacycentralapp.DependencyContainer
import foundation.e.privacycentralapp.PrivacyCentralApplication
import foundation.e.privacycentralapp.R
import foundation.e.privacycentralapp.common.NavToolbarFragment
+import foundation.e.privacycentralapp.databinding.FragmentFakeLocationBinding
import foundation.e.privacycentralapp.domain.entities.LocationMode
import foundation.e.privacycentralapp.extensions.viewModelProviderFactoryOf
import kotlinx.coroutines.Job
@@ -81,13 +85,9 @@ class FakeLocationFragment :
viewModelProviderFactoryOf { dependencyContainer.fakeLocationViewModelFactory.create() }
}
- private lateinit var mapView: FakeLocationMapView
+ private lateinit var binding: FragmentFakeLocationBinding
+
private lateinit var mapboxMap: MapboxMap
- private lateinit var useRealLocationRadioBtn: RadioButton
- private lateinit var useRandomLocationRadioBtn: RadioButton
- private lateinit var useSpecificLocationRadioBtn: RadioButton
- private lateinit var latEditText: EditText
- private lateinit var longEditText: EditText
private var hoveringMarker: ImageView? = null
@@ -178,7 +178,7 @@ class FakeLocationFragment :
Mapbox.getInstance(requireContext(), getString(R.string.mapbox_key))
}
- override fun getTitle(): String = getString(R.string.dashboard_location_title)
+ override fun getTitle(): String = getString(R.string.location_title)
private fun displayToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT)
@@ -187,101 +187,112 @@ class FakeLocationFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+ binding = FragmentFakeLocationBinding.bind(view)
- setupViews(view)
- mapView = view.findViewById<FakeLocationMapView>(R.id.mapView)
- .setup(savedInstanceState) { mapboxMap ->
- this.mapboxMap = mapboxMap
- mapboxMap.setStyle(Style.MAPBOX_STREETS) { style ->
- enableLocationPlugin(style)
- hoveringMarker = ImageView(requireContext())
- .apply {
- setImageResource(R.drawable.mapbox_marker_icon_default)
- val params = FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER
- )
- layoutParams = params
- }
- mapView.addView(hoveringMarker)
- hoveringMarker?.visibility = View.GONE // Keep hovering marker hidden by default
-
- mapboxMap.addOnCameraMoveStartedListener {
- // Show marker when user starts to move across the map.
- hoveringMarker?.visibility = if (mapView.isEnabled) {
- View.VISIBLE
- } else {
- View.GONE
- }
- isCameraMoved = true
+ binding.mapView.setup(savedInstanceState) { mapboxMap ->
+ this.mapboxMap = mapboxMap
+ mapboxMap.getUiSettings().isRotateGesturesEnabled = false
+ mapboxMap.setStyle(Style.MAPBOX_STREETS) { style ->
+ enableLocationPlugin(style)
+ hoveringMarker = ImageView(requireContext())
+ .apply {
+ setImageResource(R.drawable.mapbox_marker_icon_default)
+ val params = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER
+ )
+ layoutParams = params
+ }
+ binding.mapView.addView(hoveringMarker)
+ hoveringMarker?.visibility = View.GONE // Keep hovering marker hidden by default
+
+ mapboxMap.addOnCameraMoveStartedListener {
+ // Show marker when user starts to move across the map.
+ hoveringMarker?.visibility = if (binding.mapView.isEnabled) {
+ View.VISIBLE
+ } else {
+ View.GONE
}
+ isCameraMoved = true
+ }
- mapboxMap.addOnCameraMoveListener {
- if (mapView.isEnabled) {
- viewModel.submitAction(
- FakeLocationFeature.Action.UpdateLocationAction(
- mapboxMap.cameraPosition.target
- )
+ mapboxMap.addOnCameraMoveListener {
+ if (binding.mapView.isEnabled) {
+ viewModel.submitAction(
+ FakeLocationFeature.Action.UpdateLocationAction(
+ mapboxMap.cameraPosition.target
)
- }
+ )
}
- // Bind click listeners once map is ready.
- bindClickListeners()
}
+ // Bind click listeners once map is ready.
+ bindClickListeners()
}
+ }
}
- private fun setupViews(view: View) {
- useRealLocationRadioBtn = view.findViewById(R.id.radio_use_real_location)
- useRandomLocationRadioBtn = view.findViewById(R.id.radio_use_random_location)
- useSpecificLocationRadioBtn = view.findViewById(R.id.radio_use_specific_location)
- latEditText = view.findViewById<TextInputLayout>(R.id.edittext_latitude).editText!!
- longEditText = view.findViewById<TextInputLayout>(R.id.edittext_longitude).editText!!
- }
+ private fun getCoordinatesAfterTextChanged(inputLayout: TextInputLayout, editText: TextInputEditText, isLat: Boolean) = { editable: Editable? ->
+ inputJob?.cancel()
+ if (editable != null && editable.length > 0 && editText.isEnabled) {
+ inputJob = lifecycleScope.launch {
+ delay(DEBOUNCE_PERIOD)
+ ensureActive()
+ try {
+ val value = editable.toString().toDouble()
+ val maxValue = if (isLat) 90.0 else 180.0
+
+ if (value > maxValue || value < -maxValue) {
+ throw NumberFormatException("value $value is out of bounds")
+ }
+ inputLayout.error = null
- private fun bindClickListeners() {
- useRealLocationRadioBtn
- .setOnClickListener { radioButton ->
- toggleLocationType(radioButton)
- }
- useRandomLocationRadioBtn
- .setOnClickListener { radioButton ->
- toggleLocationType(radioButton)
- }
- useSpecificLocationRadioBtn
- .setOnClickListener { radioButton ->
- toggleLocationType(radioButton)
- }
+ inputLayout.setEndIconDrawable(R.drawable.ic_valid)
+ inputLayout.endIconMode = END_ICON_CUSTOM
- arrayOf(latEditText, longEditText).forEach { editText ->
- editText.addTextChangedListener(
- afterTextChanged = {
- inputJob?.cancel()
- if (it?.length ?: 0 > 0 && editText.isEnabled) {
- inputJob = lifecycleScope.launch {
- delay(DEBOUNCE_PERIOD)
- ensureActive()
- try {
- val lat = latEditText.text.toString().toDouble()
- val long = longEditText.text.toString().toDouble()
- viewModel.submitAction(
- FakeLocationFeature.Action.SetCustomFakeLocationAction(
- lat,
- long
- )
- )
- } catch (e: NumberFormatException) {
- Toast.makeText(
- requireContext(),
- getString(R.string.please_enter_valid_lat_long),
- Toast.LENGTH_SHORT
- ).show()
- }
+ // Here, value is valid, try to send the values
+ try {
+ val lat = binding.edittextLatitude.text.toString().toDouble()
+ val lon = binding.edittextLongitude.text.toString().toDouble()
+ if (lat <= 90.0 && lat >= -90.0 && lon <= 180.0 && lon >= -180.0) {
+ viewModel.submitAction(
+ FakeLocationFeature.Action.SetCustomFakeLocationAction(lat, lon)
+ )
}
- }
+ } catch (e: NumberFormatException) {}
+ } catch (e: NumberFormatException) {
+ inputLayout.endIconMode = END_ICON_NONE
+ inputLayout.error = getString(R.string.location_input_error)
}
- )
+ }
+ }
+ }
+
+ private fun bindClickListeners() {
+ binding.radioUseRealLocation.setOnClickListener { radioButton ->
+ toggleLocationType(radioButton)
+ }
+ binding.radioUseRandomLocation.setOnClickListener { radioButton ->
+ toggleLocationType(radioButton)
+ }
+ binding.radioUseSpecificLocation.setOnClickListener { radioButton ->
+ toggleLocationType(radioButton)
}
+
+ binding.edittextLatitude.addTextChangedListener(
+ afterTextChanged = getCoordinatesAfterTextChanged(
+ binding.textlayoutLatitude,
+ binding.edittextLatitude,
+ true
+ )
+ )
+
+ binding.edittextLongitude.addTextChangedListener(
+ afterTextChanged = getCoordinatesAfterTextChanged(
+ binding.textlayoutLongitude,
+ binding.edittextLongitude,
+ false
+ )
+ )
}
private fun toggleLocationType(radioButton: View?) {
@@ -313,17 +324,18 @@ class FakeLocationFragment :
}
override fun render(state: FakeLocationFeature.State) {
- latEditText.text =
- Editable.Factory.getInstance().newEditable(state.location.latitude.toString())
- longEditText.text =
- Editable.Factory.getInstance().newEditable(state.location.longitude.toString())
- useRandomLocationRadioBtn.isChecked = (state.location.mode == LocationMode.RANDOM_LOCATION)
- useSpecificLocationRadioBtn.isChecked =
+ binding.radioUseRandomLocation.isChecked = (state.location.mode == LocationMode.RANDOM_LOCATION)
+ binding.radioUseSpecificLocation.isChecked =
(state.location.mode == LocationMode.CUSTOM_LOCATION)
- useRealLocationRadioBtn.isChecked = (state.location.mode == LocationMode.REAL_LOCATION)
- latEditText.isEnabled = (state.location.mode == LocationMode.CUSTOM_LOCATION)
- longEditText.isEnabled = (state.location.mode == LocationMode.CUSTOM_LOCATION)
- mapView.isEnabled = (state.location.mode == LocationMode.CUSTOM_LOCATION)
+ binding.radioUseRealLocation.isChecked = (state.location.mode == LocationMode.REAL_LOCATION)
+
+ binding.mapView.isEnabled = (state.location.mode == LocationMode.CUSTOM_LOCATION)
+
+ binding.textlayoutLatitude.isVisible = (state.location.mode == LocationMode.CUSTOM_LOCATION)
+ binding.textlayoutLongitude.isVisible = (state.location.mode == LocationMode.CUSTOM_LOCATION)
+
+ binding.edittextLatitude.setText(state.location.latitude.toString())
+ binding.edittextLongitude.setText(state.location.longitude.toString())
}
override fun actions(): Flow<FakeLocationFeature.Action> = viewModel.actions
@@ -359,32 +371,32 @@ class FakeLocationFragment :
override fun onStart() {
super.onStart()
- mapView.onStart()
+ binding.mapView.onStart()
}
override fun onResume() {
super.onResume()
- mapView.onResume()
+ binding.mapView.onResume()
}
override fun onPause() {
super.onPause()
- mapView.onPause()
+ binding.mapView.onPause()
}
override fun onStop() {
super.onStop()
- mapView.onStop()
+ binding.mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
- mapView.onLowMemory()
+ binding.mapView.onLowMemory()
}
override fun onDestroyView() {
super.onDestroyView()
- mapView.onDestroy()
+ binding.mapView.onDestroy()
}
override fun onExplanationNeeded(permissionsToExplain: MutableList<String>?) {
diff --git a/app/src/main/res/drawable/ic_valid.xml b/app/src/main/res/drawable/ic_valid.xml
new file mode 100644
index 0000000..e81474e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_valid.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M9,16.2001L4.8,12.0001L3.4,13.4001L9,19.0001L21,7.0001L19.6,5.6001L9,16.2001Z"
+ android:fillColor="#2CC766"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/app/src/main/res/layout/fragment_fake_location.xml b/app/src/main/res/layout/fragment_fake_location.xml
index d60513b..558fde0 100644
--- a/app/src/main/res/layout/fragment_fake_location.xml
+++ b/app/src/main/res/layout/fragment_fake_location.xml
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
+<layout>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
@@ -18,7 +19,7 @@
<LinearLayout
android:layout_height="match_parent"
- android:layout_marginBottom="32dp"
+ android:padding="16dp"
android:layout_width="match_parent"
android:orientation="vertical"
tools:context=".main.MainActivity"
@@ -29,25 +30,8 @@
android:layout_gravity="center_horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:paddingLeft="32dp"
- android:paddingRight="32dp"
- android:paddingTop="16dp"
- android:text="@string/fake_location_info"
- android:textColor="@color/black"
- android:textSize="14sp"
- />
-
- <TextView
- android:fontFamily="sans-serif-medium"
- android:gravity="center_vertical"
- android:id="@+id/learn_more_fake_location"
- android:layout_height="48dp"
- android:layout_width="wrap_content"
- android:paddingLeft="32dp"
- android:paddingRight="32dp"
- android:text="@string/learn_more"
- android:textColor="#007fff"
- android:textSize="14sp"
+ android:text="@string/location_info"
+ android:lineSpacingExtra="5sp"
/>
<RadioGroup
@@ -55,56 +39,56 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
- android:paddingLeft="32dp"
- android:paddingRight="32dp"
+ android:layout_marginTop="16dp"
>
<foundation.e.privacycentralapp.common.RightRadioButton
android:id="@+id/radio_use_real_location"
- android:layout_height="wrap_content"
+ android:layout_height="52dp"
android:layout_width="match_parent"
- android:text="@string/use_real_location"
- android:textSize="16sp"
+ android:text="@string/location_use_real_location"
+ android:textSize="14sp"
/>
<foundation.e.privacycentralapp.common.RightRadioButton
android:id="@+id/radio_use_random_location"
- android:layout_height="wrap_content"
+ android:layout_height="52dp"
android:layout_width="match_parent"
- android:text="@string/use_random_location"
- android:textSize="16sp"
+ android:text="@string/location_use_random_location"
+ android:textSize="14sp"
/>
<foundation.e.privacycentralapp.common.RightRadioButton
android:id="@+id/radio_use_specific_location"
- android:layout_height="wrap_content"
+ android:layout_height="52dp"
android:layout_width="match_parent"
- android:text="@string/use_specific_location"
- android:textSize="16sp"
+ android:text="@string/location_use_specific_location"
+ android:textSize="14sp"
/>
</RadioGroup>
<foundation.e.privacycentralapp.features.location.FakeLocationMapView
android:id="@+id/mapView"
- android:layout_height="240dp"
- android:layout_marginBottom="16dp"
- android:layout_marginTop="32dp"
+ android:layout_height="220dp"
+ android:layout_marginTop="16dp"
android:layout_width="match_parent"
mapbox:mapbox_cameraZoom="8"
/>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
- android:hint="@string/longitude"
- android:id="@+id/edittext_longitude"
+ android:hint="@string/location_hint_longitude"
+ android:id="@+id/textlayout_longitude"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:paddingLeft="32dp"
- android:paddingRight="32dp"
+ android:layout_marginTop="16dp"
+ app:endIconDrawable="@drawable/ic_valid"
+ app:endIconMode="custom"
+ app:endIconTint="@color/green_valid"
>
-
<com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/edittext_longitude"
android:inputType="numberDecimal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
@@ -113,16 +97,17 @@
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
- android:hint="@string/latitude"
- android:id="@+id/edittext_latitude"
+ android:id="@+id/textlayout_latitude"
+ android:hint="@string/location_hint_latitude"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
android:layout_width="match_parent"
- android:paddingLeft="32dp"
- android:paddingRight="32dp"
+ android:layout_marginTop="16dp"
+ app:endIconDrawable="@drawable/ic_valid"
+ app:endIconMode="custom"
+ app:endIconTint="@color/green_valid"
>
-
<com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/edittext_latitude"
android:inputType="numberDecimal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
@@ -131,4 +116,5 @@
</LinearLayout>
</androidx.core.widget.NestedScrollView>
-</androidx.coordinatorlayout.widget.CoordinatorLayout> \ No newline at end of file
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
+</layout>
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 5f4bcb4..a3ebbeb 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -19,6 +19,7 @@
<color name="orange_off">#FC7222</color>
<color name="green_on">#169659</color>
+ <color name="green_valid">#2CC766</color>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 35987ea..d675a79 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -40,19 +40,23 @@
<string name="ipscrambling_tor_disclaimer"><b>Note:</b> when active, this setting will slow down your Internet connectivity speed (uses Thor network).</string>
<string name="ipscrambling_location_label">Force a country of origin:</string>
<string name="ipscrambling_any_location">Any country</string>
-
<string name="ipscrambling_select_app">Apply this setting to all selected apps:</string>
+ <!-- Location -->
+ <string name="location_title">Fake my location</string>
+ <string name="location_info">Choose if you want to use your real location when Quick Privacy is enabled.</string>
+ <string name="location_use_real_location">Use real location</string>
+ <string name="location_use_random_location">Use random plausible location</string>
+ <string name="location_use_specific_location">Use specific location</string>
+ <string name="location_hint_longitude">Longitude</string>
+ <string name="location_hint_latitude">Latitude</string>
+ <string name="location_input_error">Invalid coordinates</string>
+
<!-- -->
<string name="quick_protection_info">Quick protection enables these settings when turned on</string>
<string name="quick_protection_settings_list"> - All trackers are turned off.\n- Your geolocation will be faked.\n- Your real IP address will be hidden.</string>
<string name="learn_more">Learn more</string>
- <string name="fake_location_info">Choose if you want to fake your real location when app asks for your geolocation tracking.</string>
- <string name="use_real_location">Use real location</string>
- <string name="use_random_location">Use random plausible location</string>
- <string name="use_specific_location">Use specific location</string>
- <string name="longitude">Longitude</string>
- <string name="latitude">Latitude</string>
+
<string name="add_location">Add location</string>
<string name="i_am_exposing">I am exposing my real IP address</string>
<string name="ipscrambling_all_apps_scrambled">All apps use hidden IP</string>