diff --git a/app/src/generic/res/values/keys.xml b/app/src/generic/res/values/keys.xml
index 3fd676e37..f9ff39e9e 100644
--- a/app/src/generic/res/values/keys.xml
+++ b/app/src/generic/res/values/keys.xml
@@ -8,4 +8,5 @@
support@tasks.org
1
1
+ 1
\ No newline at end of file
diff --git a/app/src/googleplay/res/values/keys.xml b/app/src/googleplay/res/values/keys.xml
index c05fcdd8b..acb7556c6 100644
--- a/app/src/googleplay/res/values/keys.xml
+++ b/app/src/googleplay/res/values/keys.xml
@@ -8,4 +8,5 @@
play-support@tasks.org
0
0
+ 0
\ No newline at end of file
diff --git a/app/src/main/java/org/tasks/location/GeofenceApi.kt b/app/src/main/java/org/tasks/location/GeofenceApi.kt
index bfb4f624b..3a7ab1644 100644
--- a/app/src/main/java/org/tasks/location/GeofenceApi.kt
+++ b/app/src/main/java/org/tasks/location/GeofenceApi.kt
@@ -13,6 +13,8 @@ class GeofenceApi @Inject constructor(
) {
suspend fun registerAll() = locationDao.getPlacesWithGeofences().forEach { update(it) }
+ suspend fun cancelAll() = locationDao.getPlacesWithGeofences().forEach { cancel(it) }
+
suspend fun update(taskId: Long) = update(locationDao.getPlaceForTask(taskId))
suspend fun update(place: String) = update(locationDao.getPlace(place))
@@ -26,9 +28,11 @@ class GeofenceApi @Inject constructor(
Timber.d("Adding geofence for %s", it)
client.addGeofences(it)
}
- ?: place.let {
- Timber.d("Removing geofence for %s", it)
- client.removeGeofences(it)
- }
+ ?: cancel(place)
+ }
+
+ private fun cancel(place: Place?) = place?.let {
+ Timber.d("Removing geofence for %s", place)
+ client.removeGeofences(place)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/tasks/location/LocationPermissionDialog.kt b/app/src/main/java/org/tasks/location/LocationPermissionDialog.kt
index b4ac5662a..e814b6f45 100644
--- a/app/src/main/java/org/tasks/location/LocationPermissionDialog.kt
+++ b/app/src/main/java/org/tasks/location/LocationPermissionDialog.kt
@@ -1,7 +1,9 @@
package org.tasks.location
+import android.app.Activity.RESULT_CANCELED
import android.app.Activity.RESULT_OK
import android.app.Dialog
+import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
@@ -52,9 +54,7 @@ class LocationPermissionDialog : DialogFragment() {
return dialogBuilder.newDialog(R.string.missing_permissions)
.setView(binding.root)
- .setNegativeButton(R.string.cancel) { _, _ ->
- dismiss()
- }
+ .setNegativeButton(R.string.cancel) { dialog, _ -> dialog.cancel() }
.setNeutralButton(R.string.TLA_menu_settings) { _, _ ->
startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
addCategory(Intent.CATEGORY_DEFAULT)
@@ -88,6 +88,10 @@ class LocationPermissionDialog : DialogFragment() {
}
}
+ override fun onCancel(dialog: DialogInterface) {
+ targetFragment?.onActivityResult(targetRequestCode, RESULT_CANCELED, null)
+ }
+
companion object {
fun newLocationPermissionDialog(
targetFragment: Fragment,
diff --git a/app/src/main/java/org/tasks/preferences/fragments/LocationPreferences.kt b/app/src/main/java/org/tasks/preferences/fragments/LocationPreferences.kt
index 38b83d36a..539d6d028 100644
--- a/app/src/main/java/org/tasks/preferences/fragments/LocationPreferences.kt
+++ b/app/src/main/java/org/tasks/preferences/fragments/LocationPreferences.kt
@@ -1,13 +1,23 @@
package org.tasks.preferences.fragments
+import android.content.Intent
import android.os.Bundle
+import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
+import androidx.preference.SwitchPreference
import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.NonCancellable
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.tasks.R
import org.tasks.Tasks.Companion.IS_GOOGLE_PLAY
import org.tasks.billing.Inventory
import org.tasks.gtasks.PlayServices
import org.tasks.injection.InjectingPreferenceFragment
+import org.tasks.location.GeofenceApi
+import org.tasks.location.LocationPermissionDialog.Companion.newLocationPermissionDialog
+import org.tasks.preferences.PermissionChecker
+import org.tasks.preferences.Preferences
import org.tasks.ui.Toaster
import javax.inject.Inject
@@ -17,6 +27,9 @@ class LocationPreferences : InjectingPreferenceFragment() {
@Inject lateinit var playServices: PlayServices
@Inject lateinit var inventory: Inventory
@Inject lateinit var toaster: Toaster
+ @Inject lateinit var geofenceApi: GeofenceApi
+ @Inject lateinit var permissionChecker: PermissionChecker
+ @Inject lateinit var preferences: Preferences
override fun getPreferenceXml() = R.xml.preferences_location
@@ -24,14 +37,40 @@ class LocationPreferences : InjectingPreferenceFragment() {
if (IS_GOOGLE_PLAY) {
findPreference(R.string.p_place_provider)
.setOnPreferenceChangeListener(this::onPlaceSearchChanged)
+ findPreference(R.string.p_geofence_service)
+ .setOnPreferenceChangeListener(this::onGeofenceServiceChanged)
} else {
disable(
R.string.p_map_tiles,
R.string.p_place_provider,
+ R.string.p_geofence_service
)
}
}
+ override fun onResume() {
+ super.onResume()
+
+ updatePermissions()
+ }
+
+ private fun updatePermissions() {
+ val hasPermissions = permissionChecker.canAccessBackgroundLocation()
+ preferences.setBoolean(R.string.p_location_based_reminders, hasPermissions)
+ with((findPreference(R.string.p_location_based_reminders) as SwitchPreference)) {
+ isChecked = hasPermissions
+ isEnabled = !hasPermissions
+ setOnPreferenceClickListener {
+ if (!permissionChecker.canAccessBackgroundLocation()) {
+ newLocationPermissionDialog(this@LocationPreferences, REQUEST_BACKGROUND_LOCATION)
+ .show(parentFragmentManager, FRAG_TAG_LOCATION_PERMISSION)
+ }
+ false
+ }
+ }
+ findPreference(R.string.p_geofence_service).isEnabled = hasPermissions && IS_GOOGLE_PLAY
+ }
+
private fun onPlaceSearchChanged(preference: Preference, newValue: Any): Boolean =
if (newValue.toString().toIntOrNull() ?: 0 == 1) {
if (!playServices.refreshAndCheck()) {
@@ -46,4 +85,37 @@ class LocationPreferences : InjectingPreferenceFragment() {
} else {
true
}
+
+ private fun onGeofenceServiceChanged(preference: Preference, newValue: Any): Boolean =
+ if (newValue.toString().toIntOrNull() ?: 0 == 1) {
+ if (!playServices.refreshAndCheck()) {
+ playServices.resolve(activity)
+ false
+ } else {
+ geofenceChanged()
+ }
+ } else {
+ geofenceChanged()
+ }
+
+ private fun geofenceChanged(): Boolean {
+ lifecycleScope.launch {
+ withContext(NonCancellable) {
+ geofenceApi.cancelAll()
+ }
+ showRestartDialog()
+ }
+ return true
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) =
+ when (requestCode) {
+ REQUEST_BACKGROUND_LOCATION -> updatePermissions()
+ else -> super.onActivityResult(requestCode, resultCode, data)
+ }
+
+ companion object {
+ private const val FRAG_TAG_LOCATION_PERMISSION = "frag_tag_location_permissions"
+ private const val REQUEST_BACKGROUND_LOCATION = 10101
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 0801ef310..f5d25522b 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -301,4 +301,14 @@
- 0
- 1
+
+
+ - @string/google_play_location_service
+ - @string/android_location_services
+
+
+
+ - 0
+ - 1
+
\ No newline at end of file
diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml
index e01953eda..6d3c1beee 100644
--- a/app/src/main/res/values/keys.xml
+++ b/app/src/main/res/values/keys.xml
@@ -403,6 +403,8 @@
OpenStreetMap
Android
place_provider_v2
+ location_based_reminders
+ geofence_service
preference_screen
google_tasks_add_to_top
google_tasks_position_hack
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 74477aba2..86fff8e01 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -703,4 +703,8 @@ File %1$s contained %2$s.\n\n
Maps
Map tiles
Use app theme
+ Location-based reminders
+ Geofence service
+ Google Play location service
+ Android location service
diff --git a/app/src/main/res/xml/preferences_location.xml b/app/src/main/res/xml/preferences_location.xml
index 2e94e7203..b2f258bca 100644
--- a/app/src/main/res/xml/preferences_location.xml
+++ b/app/src/main/res/xml/preferences_location.xml
@@ -2,6 +2,24 @@
+
+
+
+
+
+
+
+