From 80d1077dabec3d9f75f02e9667a3782d8fc99ebc Mon Sep 17 00:00:00 2001 From: Azuo Date: Thu, 12 Aug 2021 14:12:30 +0800 Subject: [PATCH 1/3] Make LocationService work in case GMS is not available. --- .../anotherwidget/services/LocationService.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt index 906b438..8fd9bcb 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt @@ -42,7 +42,27 @@ class LocationService : Service() { Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { - LocationServices.getFusedLocationProviderClient(this@LocationService).lastLocation.addOnCompleteListener { task -> + if (com.google.android.gms.common.GoogleApiAvailability.getInstance() + .isGooglePlayServicesAvailable(this@LocationService) + == com.google.android.gms.common.ConnectionResult.SUCCESS + ) { + LocationServices.getFusedLocationProviderClient(this@LocationService).lastLocation + } else { + val lm = getSystemService(LOCATION_SERVICE) as android.location.LocationManager + var location: android.location.Location? = null + for (provider in arrayOf( + "fused", // LocationManager.FUSED_PROVIDER, + android.location.LocationManager.GPS_PROVIDER, + android.location.LocationManager.NETWORK_PROVIDER, + android.location.LocationManager.PASSIVE_PROVIDER + )) { + if (lm.isProviderEnabled(provider)) { + location = lm.getLastKnownLocation(provider); + if (location != null) break + } + } + com.google.android.gms.tasks.Tasks.forResult(location) + }.addOnCompleteListener { task -> val networkApi = WeatherNetworkApi(this@LocationService) if (task.isSuccessful) { val location = task.result From 8c84913cd8c94dd779806071b4288a8400df5394 Mon Sep 17 00:00:00 2001 From: azuo Date: Fri, 3 Sep 2021 20:54:02 +0800 Subject: [PATCH 2/3] Remove trailing semicolons in code. --- .../tommasoberlose/anotherwidget/services/LocationService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt index 8fd9bcb..73bb497 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt @@ -57,7 +57,7 @@ class LocationService : Service() { android.location.LocationManager.PASSIVE_PROVIDER )) { if (lm.isProviderEnabled(provider)) { - location = lm.getLastKnownLocation(provider); + location = lm.getLastKnownLocation(provider) if (location != null) break } } From d3b623cf13bff5fb2af4dc7b51cb6a7e93df6095 Mon Sep 17 00:00:00 2001 From: azuo Date: Mon, 13 Sep 2021 19:28:47 +0800 Subject: [PATCH 3/3] Add ACCESS_BACKGROUND_LOCATION permission required by Android 11. --- app/src/main/AndroidManifest.xml | 26 +++++---- .../anotherwidget/helpers/WeatherHelper.kt | 15 ++++- .../network/WeatherNetworkApi.kt | 7 +++ .../anotherwidget/services/LocationService.kt | 8 +-- .../activities/tabs/CustomLocationActivity.kt | 47 ++++------------ .../tabs/WeatherProviderActivity.kt | 4 +- .../ui/fragments/tabs/WeatherFragment.kt | 55 +++++++++++++------ 7 files changed, 87 insertions(+), 75 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 65950db..f6aaa1e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + @@ -13,6 +14,7 @@ + - + - - - - - - - - - - - + + + + + + + + + + + diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt index 26b3ce7..f0ac243 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt @@ -21,11 +21,20 @@ object WeatherHelper { suspend fun updateWeather(context: Context) { Kotpref.init(context) - val networkApi = WeatherNetworkApi(context) if (Preferences.customLocationAdd != "") { - networkApi.updateWeather() - } else if (context.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) { + WeatherNetworkApi(context).updateWeather() + } else if (context.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) && + (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R || + context.checkGrantedPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) + ) { LocationService.requestNewLocation(context) + } else { + Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_missing_location) + Preferences.weatherProviderError = "" + removeWeather(context) + org.greenrobot.eventbus.EventBus.getDefault().post( + com.tommasoberlose.anotherwidget.ui.fragments.MainFragment.UpdateUiMessageEvent() + ) } } diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/WeatherNetworkApi.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/WeatherNetworkApi.kt index 436944f..3b2c513 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/network/WeatherNetworkApi.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/network/WeatherNetworkApi.kt @@ -42,6 +42,13 @@ class WeatherNetworkApi(val context: Context) { Constants.WeatherProvider.YR -> useYrProvider(context) } } else { + if (!Preferences.showWeather) + Preferences.weatherProviderError = context.getString(R.string.show_weather_not_visible) + else { + Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_missing_location) + Preferences.weatherProviderError = "" + } + WeatherHelper.removeWeather( context ) diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt index 73bb497..44a1f2d 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/services/LocationService.kt @@ -18,6 +18,7 @@ import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi import com.tommasoberlose.anotherwidget.ui.activities.MainActivity import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment +import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission import kotlinx.coroutines.* import org.greenrobot.eventbus.EventBus import java.lang.Exception @@ -37,10 +38,9 @@ class LocationService : Service() { startForeground(LOCATION_ACCESS_NOTIFICATION_ID, getLocationAccessNotification()) job?.cancel() job = GlobalScope.launch(Dispatchers.IO) { - if (ActivityCompat.checkSelfPermission( - this@LocationService, - Manifest.permission.ACCESS_FINE_LOCATION - ) == PackageManager.PERMISSION_GRANTED + if (checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) && + (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R || + checkGrantedPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) ) { if (com.google.android.gms.common.GoogleApiAvailability.getInstance() .isGooglePlayServicesAvailable(this@LocationService) diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/tabs/CustomLocationActivity.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/tabs/CustomLocationActivity.kt index 3e510ff..77ec9a0 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/tabs/CustomLocationActivity.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/tabs/CustomLocationActivity.kt @@ -46,11 +46,16 @@ class CustomLocationActivity : AppCompatActivity() { adapter = SlimAdapter.create() adapter .register(R.layout.custom_location_item) { _, injector -> - injector - .text(R.id.text, getString(R.string.custom_location_gps)) - .clicked(R.id.text) { - requirePermission() + injector.text(R.id.text, getString(R.string.custom_location_gps)) + injector.clicked(R.id.text) { + Preferences.bulk { + remove(Preferences::customLocationLat) + remove(Preferences::customLocationLon) + remove(Preferences::customLocationAdd) } + setResult(Activity.RESULT_OK) + finish() + } } .register
(R.layout.custom_location_item) { item, injector -> injector.text(R.id.text, item.getAddressLine(0) ?: "") @@ -59,9 +64,9 @@ class CustomLocationActivity : AppCompatActivity() { customLocationLat = item.latitude.toString() customLocationLon = item.longitude.toString() customLocationAdd = item.getAddressLine(0) ?: "" - setResult(Activity.RESULT_OK) - finish() } + setResult(Activity.RESULT_OK) + finish() } } .attachTo(binding.listView) @@ -115,36 +120,6 @@ class CustomLocationActivity : AppCompatActivity() { }) } - private fun requirePermission() { - Dexter.withContext(this) - .withPermissions( - Manifest.permission.ACCESS_FINE_LOCATION - ).withListener(object: MultiplePermissionsListener { - override fun onPermissionsChecked(report: MultiplePermissionsReport?) { - report?.let { - if (report.areAllPermissionsGranted()){ - Preferences.bulk { - remove(Preferences::customLocationLat) - remove(Preferences::customLocationLon) - remove(Preferences::customLocationAdd) - } - setResult(Activity.RESULT_OK) - finish() - } - } - } - override fun onPermissionRationaleShouldBeShown( - permissions: MutableList?, - token: PermissionToken? - ) { - // Remember to invoke this method when the custom rationale is closed - // or just by default if you don't want to use any custom rationale. - token?.continuePermissionRequest() - } - }) - .check() - } - private fun setupListener() { binding.actionBack.setOnClickListener { onBackPressed() diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/tabs/WeatherProviderActivity.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/tabs/WeatherProviderActivity.kt index ec5297a..4773cf8 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/tabs/WeatherProviderActivity.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/tabs/WeatherProviderActivity.kt @@ -127,11 +127,11 @@ class WeatherProviderActivity : AppCompatActivity() { private fun subscribeUi(viewModel: WeatherProviderViewModel) { viewModel.weatherProviderError.observe(this) { - updateListItem() + binding.listView.postDelayed({ updateListItem() }, 300) } viewModel.weatherProviderLocationError.observe(this) { - updateListItem() + binding.listView.postDelayed({ updateListItem() }, 300) } } diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/WeatherFragment.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/WeatherFragment.kt index fd4a3a9..4fc5644 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/WeatherFragment.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/WeatherFragment.kt @@ -91,16 +91,17 @@ class WeatherFragment : Fragment() { viewModel.weatherProvider.observe(viewLifecycleOwner) { maintainScrollPosition { binding.labelWeatherProvider.text = WeatherHelper.getProviderName(requireContext(), Constants.WeatherProvider.fromInt(it)!!) - checkWeatherProviderConfig() } } viewModel.weatherProviderError.observe(viewLifecycleOwner) { checkWeatherProviderConfig() + checkLocationPermission() } viewModel.weatherProviderLocationError.observe(viewLifecycleOwner) { checkWeatherProviderConfig() + checkLocationPermission() } viewModel.customLocationAdd.observe(viewLifecycleOwner) { @@ -108,6 +109,7 @@ class WeatherFragment : Fragment() { binding.labelCustomLocation.text = if (it == "") getString(R.string.custom_location_gps) else it } + checkWeatherProviderConfig() checkLocationPermission() } @@ -116,43 +118,50 @@ class WeatherFragment : Fragment() { binding.tempUnit.text = if (it == "F") getString(R.string.fahrenheit) else getString(R.string.celsius) } - checkLocationPermission() } viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner) { maintainScrollPosition { binding.labelWeatherRefreshPeriod.text = getString(SettingsStringHelper.getRefreshPeriodString(it)) } - checkLocationPermission() } viewModel.weatherIconPack.observe(viewLifecycleOwner) { maintainScrollPosition { binding.labelWeatherIconPack.text = getString(R.string.settings_weather_icon_pack_default).format((it + 1)) } - checkLocationPermission() } } private fun checkLocationPermission() { - if (requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) { + if (requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) && + (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R || + requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) + ) { binding.locationPermissionAlert.isVisible = false - WeatherReceiver.setUpdates(requireContext()) - } else if (Preferences.showWeather && Preferences.customLocationAdd == "") { + } else if (Preferences.customLocationAdd == "") { binding.locationPermissionAlert.isVisible = true binding.locationPermissionAlert.setOnClickListener { requirePermission() } + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R && + requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) + ) { + val text = getString(R.string.action_grant_permission) + " - " + + requireContext().packageManager.backgroundPermissionOptionLabel + binding.locationPermissionAlert.text = text + } + binding.weatherProviderLocationError.isVisible = false } else { binding.locationPermissionAlert.isVisible = false } } private fun checkWeatherProviderConfig() { - binding.weatherProviderError.isVisible = Preferences.showWeather && Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-" + binding.weatherProviderError.isVisible = Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-" binding.weatherProviderError.text = Preferences.weatherProviderError - binding.weatherProviderLocationError.isVisible = Preferences.showWeather && Preferences.weatherProviderLocationError != "" + binding.weatherProviderLocationError.isVisible = Preferences.weatherProviderLocationError != "" binding.weatherProviderLocationError.text = Preferences.weatherProviderLocationError } @@ -177,11 +186,11 @@ class WeatherFragment : Fragment() { .addItem(getString(R.string.celsius), "C") .addOnSelectItemListener { value -> if (value != Preferences.weatherTempUnit) { + Preferences.weatherTempUnit = value viewLifecycleOwner.lifecycleScope.launch { WeatherHelper.updateWeather(requireContext()) } } - Preferences.weatherTempUnit = value }.show() } @@ -193,7 +202,10 @@ class WeatherFragment : Fragment() { } dialog .addOnSelectItemListener { value -> - Preferences.weatherRefreshPeriod = value + if (value != Preferences.weatherRefreshPeriod) { + Preferences.weatherRefreshPeriod = value + WeatherReceiver.setUpdates(requireContext()) + } }.show() } @@ -206,12 +218,12 @@ class WeatherFragment : Fragment() { if (resultCode == Activity.RESULT_OK) { when (requestCode) { Constants.RESULT_CODE_CUSTOM_LOCATION -> { - WeatherReceiver.setUpdates(requireContext()) - checkLocationPermission() - } - RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> { - checkLocationPermission() + viewLifecycleOwner.lifecycleScope.launch { + WeatherHelper.updateWeather(requireContext()) + } } + //RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> { + //} } } super.onActivityResult(requestCode, resultCode, data) @@ -220,12 +232,19 @@ class WeatherFragment : Fragment() { private fun requirePermission() { Dexter.withContext(requireContext()) .withPermissions( - Manifest.permission.ACCESS_FINE_LOCATION + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R && + requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) + Manifest.permission.ACCESS_BACKGROUND_LOCATION + else + Manifest.permission.ACCESS_FINE_LOCATION ).withListener(object: MultiplePermissionsListener { override fun onPermissionsChecked(report: MultiplePermissionsReport?) { report?.let { - if (report.areAllPermissionsGranted()){ + if (report.areAllPermissionsGranted()) { checkLocationPermission() + viewLifecycleOwner.lifecycleScope.launch { + WeatherHelper.updateWeather(requireContext()) + } } } }