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 @@ + + + + + + + +