From a808476b7df4b652fe955e3f46437f1d89a8eb0c Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 13 Oct 2021 14:44:01 -0300 Subject: [PATCH] Work around rare crashes that can happen when fragments are not attached to a context while co-routines are still executing but requiring a context Change-Id: Ie6c7cee50014b59c25384d3bf9a122081b9917fc --- .../gms/ui/DeviceRegistrationFragment.kt | 8 +++++--- .../DeviceRegistrationPreferencesFragment.kt | 3 ++- .../gms/ui/PushNotificationAdvancedFragment.kt | 18 ++++++++++++------ .../gms/ui/PushNotificationAllAppsFragment.kt | 2 +- .../gms/ui/PushNotificationAppFragment.kt | 5 +++-- .../microg/gms/ui/PushNotificationFragment.kt | 10 ++++++---- .../org/microg/gms/ui/SafetyNetFragment.kt | 10 ++++++---- .../org/microg/gms/ui/SettingsFragment.kt | 8 +++++--- .../ui/ExposureNotificationsAppFragment.kt | 5 +++-- .../core/ui/ExposureNotificationsFragment.kt | 8 +++++--- ...ExposureNotificationsPreferencesFragment.kt | 11 ++++++----- .../ui/ExposureNotificationsRpisFragment.kt | 3 ++- 12 files changed, 56 insertions(+), 35 deletions(-) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt index 4a59ffb4..88938f7b 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt @@ -31,10 +31,11 @@ class DeviceRegistrationFragment : Fragment(R.layout.device_registration_fragmen } fun setEnabled(newStatus: Boolean) { + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val info = getCheckinServiceInfo(requireContext()) + val info = getCheckinServiceInfo(appContext) val newConfiguration = info.configuration.copy(enabled = newStatus) - setCheckinServiceConfiguration(requireContext(), newConfiguration) + setCheckinServiceConfiguration(appContext, newConfiguration) displayServiceInfo(info.copy(configuration = newConfiguration)) } } @@ -45,8 +46,9 @@ class DeviceRegistrationFragment : Fragment(R.layout.device_registration_fragmen override fun onResume() { super.onResume() + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - displayServiceInfo(getCheckinServiceInfo(requireContext())) + displayServiceInfo(getCheckinServiceInfo(appContext)) } } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt index a9aa42ed..6d27eed6 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt @@ -44,8 +44,9 @@ class DeviceRegistrationPreferencesFragment : PreferenceFragmentCompat() { private fun updateStatus() { handler.postDelayed(updateRunnable, UPDATE_INTERVAL) + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val serviceInfo = getCheckinServiceInfo(requireContext()) + val serviceInfo = getCheckinServiceInfo(appContext) statusCategory.isVisible = serviceInfo.configuration.enabled if (serviceInfo.lastCheckin > 0) { status.summary = getString(R.string.checkin_last_registration, DateUtils.getRelativeTimeSpanString(serviceInfo.lastCheckin, System.currentTimeMillis(), 0)) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAdvancedFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAdvancedFragment.kt index f248e97b..80fe48d7 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAdvancedFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAdvancedFragment.kt @@ -32,45 +32,50 @@ class PushNotificationAdvancedFragment : PreferenceFragmentCompat() { networkOther = preferenceScreen.findPreference(GcmPrefs.PREF_NETWORK_OTHER) ?: networkOther confirmNewApps.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { if (newValue is Boolean) { - setGcmServiceConfiguration(requireContext(), getGcmServiceInfo(requireContext()).configuration.copy(confirmNewApps = newValue)) + setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(confirmNewApps = newValue)) } updateContent() } true } networkMobile.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { (newValue as? String)?.toIntOrNull()?.let { - setGcmServiceConfiguration(requireContext(), getGcmServiceInfo(requireContext()).configuration.copy(mobile = it)) + setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(mobile = it)) } updateContent() } true } networkWifi.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { (newValue as? String)?.toIntOrNull()?.let { - setGcmServiceConfiguration(requireContext(), getGcmServiceInfo(requireContext()).configuration.copy(wifi = it)) + setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(wifi = it)) } updateContent() } true } networkRoaming.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { (newValue as? String)?.toIntOrNull()?.let { - setGcmServiceConfiguration(requireContext(), getGcmServiceInfo(requireContext()).configuration.copy(roaming = it)) + setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(roaming = it)) } updateContent() } true } networkOther.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { (newValue as? String)?.toIntOrNull()?.let { - setGcmServiceConfiguration(requireContext(), getGcmServiceInfo(requireContext()).configuration.copy(other = it)) + setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(other = it)) } updateContent() } @@ -84,8 +89,9 @@ class PushNotificationAdvancedFragment : PreferenceFragmentCompat() { } private fun updateContent() { + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val serviceInfo = getGcmServiceInfo(requireContext()) + val serviceInfo = getGcmServiceInfo(appContext) confirmNewApps.isChecked = serviceInfo.configuration.confirmNewApps networkMobile.value = serviceInfo.configuration.mobile.toString() networkMobile.summary = getSummaryString(serviceInfo.configuration.mobile, serviceInfo.learntMobileInterval) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAllAppsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAllAppsFragment.kt index 94095117..91cac572 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAllAppsFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAllAppsFragment.kt @@ -52,8 +52,8 @@ class PushNotificationAllAppsFragment : PreferenceFragmentCompat() { } private fun updateContent() { + val context = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val context = requireContext() val apps = withContext(Dispatchers.IO) { val res = database.appList.map { app -> app to context.packageManager.getApplicationInfoIfExists(app.packageName) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt index 464b5806..28cd3b55 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt @@ -46,12 +46,13 @@ class PushNotificationAppFragment : Fragment(R.layout.push_notification_fragment override fun onResume() { super.onResume() + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val pm = requireContext().packageManager + val pm = appContext.packageManager val applicationInfo = pm.getApplicationInfoIfExists(packageName) binding.appName = applicationInfo?.loadLabel(pm)?.toString() ?: packageName binding.appIcon = applicationInfo?.loadIcon(pm) - ?: AppCompatResources.getDrawable(requireContext(), android.R.mipmap.sym_def_app_icon) + ?: AppCompatResources.getDrawable(appContext, android.R.mipmap.sym_def_app_icon) } } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt index d0cb577e..95127689 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt @@ -30,10 +30,11 @@ class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) { } fun setEnabled(newStatus: Boolean) { + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val info = getGcmServiceInfo(requireContext()) + val info = getGcmServiceInfo(appContext) val newConfiguration = info.configuration.copy(enabled = newStatus) - setGcmServiceConfiguration(requireContext(), newConfiguration) + setGcmServiceConfiguration(appContext, newConfiguration) displayServiceInfo(info.copy(configuration = newConfiguration)) } } @@ -44,9 +45,10 @@ class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) { override fun onResume() { super.onResume() + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - displayServiceInfo(getGcmServiceInfo(requireContext())) - binding.checkinEnabled = getCheckinServiceInfo(requireContext()).configuration.enabled + displayServiceInfo(getGcmServiceInfo(appContext)) + binding.checkinEnabled = getCheckinServiceInfo(appContext).configuration.enabled } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetFragment.kt index bb83826c..bae598e8 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetFragment.kt @@ -32,10 +32,11 @@ class SafetyNetFragment : Fragment(R.layout.safety_net_fragment) { } fun setEnabled(newStatus: Boolean) { + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val info = getSafetyNetServiceInfo(requireContext()) + val info = getSafetyNetServiceInfo(appContext) val newConfiguration = info.configuration.copy(enabled = newStatus) - displayServiceInfo(setSafetyNetServiceConfiguration(requireContext(), newConfiguration)) + displayServiceInfo(setSafetyNetServiceConfiguration(appContext, newConfiguration)) } } @@ -45,9 +46,10 @@ class SafetyNetFragment : Fragment(R.layout.safety_net_fragment) { override fun onResume() { super.onResume() + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - binding.checkinEnabled = getCheckinServiceInfo(requireContext()).configuration.enabled - displayServiceInfo(getSafetyNetServiceInfo(requireContext())) + binding.checkinEnabled = getCheckinServiceInfo(appContext).configuration.enabled + displayServiceInfo(getSafetyNetServiceInfo(appContext)) } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt index 5a1d8f9a..681b1f4c 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt @@ -5,6 +5,7 @@ package org.microg.gms.ui +import android.content.Context import android.os.Bundle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController @@ -50,12 +51,13 @@ class SettingsFragment : ResourceSettingsFragment() { override fun onResume() { super.onResume() + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - updateDetails() + updateDetails(appContext) } } - private suspend fun updateDetails() { + private suspend fun updateDetails(context: Context) { if (getGcmServiceInfo(requireContext()).configuration.enabled) { val database = GcmDatabase(context) val regCount = database.registrationList.size @@ -68,7 +70,7 @@ class SettingsFragment : ResourceSettingsFragment() { findPreference(PREF_CHECKIN)!!.setSummary(if (getCheckinServiceInfo(requireContext()).configuration.enabled) R.string.service_status_enabled_short else R.string.service_status_disabled_short) findPreference(PREF_SNET)!!.setSummary(if (getSafetyNetServiceInfo(requireContext()).configuration.enabled) R.string.service_status_enabled_short else R.string.service_status_disabled_short) - val backendCount = UnifiedLocationClient[requireContext()].getLocationBackends().size + UnifiedLocationClient[requireContext()].getGeocoderBackends().size + val backendCount = UnifiedLocationClient[context].getLocationBackends().size + UnifiedLocationClient[requireContext()].getGeocoderBackends().size findPreference(PREF_UNIFIEDNLP)!!.summary = resources.getQuantityString(R.plurals.pref_unifiednlp_summary, backendCount, backendCount); findPreference(PREF_EXPOSURE)?.isVisible = NearbyPreferencesIntegration.isAvailable diff --git a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsAppFragment.kt b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsAppFragment.kt index 7d8a36fc..15e95ad0 100644 --- a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsAppFragment.kt +++ b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsAppFragment.kt @@ -40,12 +40,13 @@ class ExposureNotificationsAppFragment : Fragment(R.layout.exposure_notification override fun onResume() { super.onResume() + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val pm = requireContext().packageManager + val pm = appContext.packageManager val applicationInfo = pm.getApplicationInfoIfExists(packageName) binding.appName = applicationInfo?.loadLabel(pm)?.toString() ?: packageName binding.appIcon = applicationInfo?.loadIcon(pm) - ?: AppCompatResources.getDrawable(requireContext(), android.R.mipmap.sym_def_app_icon) + ?: AppCompatResources.getDrawable(appContext, android.R.mipmap.sym_def_app_icon) } } } diff --git a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsFragment.kt b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsFragment.kt index 6cc00f5e..550ccba2 100644 --- a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsFragment.kt +++ b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsFragment.kt @@ -32,10 +32,11 @@ class ExposureNotificationsFragment : Fragment(R.layout.exposure_notifications_f } fun setEnabled(newStatus: Boolean) { + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val info = getExposureNotificationsServiceInfo(requireContext()) + val info = getExposureNotificationsServiceInfo(appContext) val newConfiguration = info.configuration.copy(enabled = newStatus) - setExposureNotificationsServiceConfiguration(requireContext(), newConfiguration) + setExposureNotificationsServiceConfiguration(appContext, newConfiguration) displayServiceInfo(info.copy(configuration = newConfiguration)) } } @@ -46,8 +47,9 @@ class ExposureNotificationsFragment : Fragment(R.layout.exposure_notifications_f override fun onResume() { super.onResume() + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - displayServiceInfo(getExposureNotificationsServiceInfo(requireContext())) + displayServiceInfo(getExposureNotificationsServiceInfo(appContext)) } } } diff --git a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsPreferencesFragment.kt b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsPreferencesFragment.kt index c7ae6332..df0731ff 100644 --- a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsPreferencesFragment.kt +++ b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsPreferencesFragment.kt @@ -101,15 +101,16 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() { } private fun updateStatus() { + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { handler.postDelayed(updateStatusRunnable, UPDATE_STATUS_INTERVAL) - val enabled = getExposureNotificationsServiceInfo(requireContext()).configuration.enabled + val enabled = getExposureNotificationsServiceInfo(appContext).configuration.enabled exposureEnableInfo.isVisible = !enabled - val bluetoothSupported = ScannerService.isSupported(requireContext()) - val advertisingSupported = if (bluetoothSupported == true) AdvertiserService.isSupported(requireContext()) else bluetoothSupported + val bluetoothSupported = ScannerService.isSupported(appContext) + val advertisingSupported = if (bluetoothSupported == true) AdvertiserService.isSupported(appContext) else bluetoothSupported - exposureLocationOff.isVisible = enabled && bluetoothSupported != false && !LocationManagerCompat.isLocationEnabled(requireContext().getSystemService(LOCATION_SERVICE) as LocationManager) + exposureLocationOff.isVisible = enabled && bluetoothSupported != false && !LocationManagerCompat.isLocationEnabled(appContext.getSystemService(LOCATION_SERVICE) as LocationManager) exposureBluetoothOff.isVisible = enabled && bluetoothSupported == null && !turningBluetoothOn exposureBluetoothUnsupported.isVisible = enabled && bluetoothSupported == false exposureBluetoothNoAdvertisement.isVisible = enabled && bluetoothSupported == true && advertisingSupported != true @@ -119,9 +120,9 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() { } private fun updateContent() { + val context = requireContext().applicationContext lifecycleScope.launchWhenResumed { handler.postDelayed(updateContentRunnable, UPDATE_CONTENT_INTERVAL) - val context = requireContext() val (apps, lastHourKeys, currentId) = ExposureDatabase.with(context) { database -> val apps = database.appList.map { packageName -> context.packageManager.getApplicationInfoIfExists(packageName) diff --git a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsRpisFragment.kt b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsRpisFragment.kt index f6fc8d83..31564ce7 100644 --- a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsRpisFragment.kt +++ b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsRpisFragment.kt @@ -72,8 +72,9 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() { } fun updateChart() { + val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - val rpiHourHistogram = ExposureDatabase.with(requireContext()) { database -> database.rpiHourHistogram } + val rpiHourHistogram = ExposureDatabase.with(appContext) { database -> database.rpiHourHistogram } val totalRpiCount = rpiHourHistogram.map { it.rpis }.sum() deleteAll.isEnabled = totalRpiCount > 0 histogramCategory.title = getString(R.string.prefcat_exposure_rpis_histogram_title, totalRpiCount)