diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0954ec8d..594c1b4c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,8 +6,6 @@ - - @@ -63,10 +61,6 @@ tools:node="remove"> - - diff --git a/app/src/main/kotlin/at/bitfire/davdroid/App.kt b/app/src/main/kotlin/at/bitfire/davdroid/App.kt index 5a5674cf..fedf98c2 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/App.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/App.kt @@ -97,9 +97,6 @@ class App: Application(), Thread.UncaughtExceptionHandler, Configuration.Provide // watch for account changes/deletions accountsUpdatedListener.listen() - // foreground service (possible workaround for devices which prevent DAVx5 from being started) - ForegroundService.startOrStop(this) - // watch storage because low storage means synchronization is stopped storageLowReceiver.listen() diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ForegroundService.kt b/app/src/main/kotlin/at/bitfire/davdroid/ForegroundService.kt deleted file mode 100644 index 9c1ef3df..00000000 --- a/app/src/main/kotlin/at/bitfire/davdroid/ForegroundService.kt +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************************************** - * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details. - **************************************************************************************************/ - -package at.bitfire.davdroid - -import android.app.PendingIntent -import android.app.Service -import android.content.Context -import android.content.Intent -import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC -import android.os.Build -import android.os.PowerManager -import androidx.core.app.NotificationCompat -import androidx.core.app.NotificationManagerCompat -import androidx.core.app.ServiceCompat -import androidx.core.content.getSystemService -import at.bitfire.davdroid.settings.Settings -import at.bitfire.davdroid.settings.SettingsManager -import at.bitfire.davdroid.ui.AppSettingsActivity -import at.bitfire.davdroid.ui.NotificationUtils -import at.bitfire.davdroid.ui.NotificationUtils.notifyIfPossible -import dagger.hilt.EntryPoint -import dagger.hilt.InstallIn -import dagger.hilt.android.EntryPointAccessors -import dagger.hilt.components.SingletonComponent - -class ForegroundService : Service() { - - companion object { - - @EntryPoint - @InstallIn(SingletonComponent::class) - interface ForegroundServiceEntryPoint { - fun settingsManager(): SettingsManager - } - - /** - * Whether the app is currently exempted from battery optimization. - * @return true if battery optimization is not applied to the current app; false if battery optimization is applied - */ - private fun batteryOptimizationWhitelisted(context: Context) = - context.getSystemService()!!.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID) - - /** - * Whether the foreground service is enabled (checked) in the app settings. - * - * @return true: foreground service enabled; false: foreground service not enabled - */ - private fun shouldBeActive(context: Context): Boolean { - val settingsManager = EntryPointAccessors.fromApplication(context, ForegroundServiceEntryPoint::class.java).settingsManager() - return settingsManager.getBooleanOrNull(Settings.FOREGROUND_SERVICE) == true - } - - /** - * Starts the foreground service when enabled in the app settings and applicable. - * Stops a potentially running foreground service when disabled in the app settings. - */ - fun startOrStop(context: Context) { - val foregroundServiceIntent = Intent(Intent.ACTION_DEFAULT, null, context, ForegroundService::class.java) - if (shouldBeActive(context)) { - if (batteryOptimizationWhitelisted(context)) { - if (Build.VERSION.SDK_INT >= 26) - // After the next call, we have 5 seconds to call startForeground() - // [https://developer.android.com/about/versions/oreo/android-8.0-changes.html#back-all] - context.startForegroundService(foregroundServiceIntent) - else - context.startService(foregroundServiceIntent) - } else - notifyBatteryOptimization(context) - } else - try { - context.stopService(foregroundServiceIntent) - } catch (ignored: Exception) { } - } - - private fun notifyBatteryOptimization(context: Context) { - val settingsIntent = Intent(context, AppSettingsActivity::class.java).apply { - putExtra(AppSettingsActivity.EXTRA_SCROLL_TO, Settings.BATTERY_OPTIMIZATION) - } - val pendingSettingsIntent = PendingIntent.getActivity(context, 0, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - val builder = - NotificationCompat.Builder(context, NotificationUtils.CHANNEL_DEBUG) - .setSmallIcon(R.drawable.ic_warning_notify) - .setContentTitle(context.getString(R.string.battery_optimization_notify_title)) - .setContentText(context.getString(R.string.battery_optimization_notify_text)) - .setContentIntent(pendingSettingsIntent) - .setCategory(NotificationCompat.CATEGORY_ERROR) - - val nm = NotificationManagerCompat.from(context) - nm.notifyIfPossible(NotificationUtils.NOTIFY_BATTERY_OPTIMIZATION, builder.build()) - } - } - - - override fun onCreate() { - super.onCreate() - - val settingsIntent = Intent(this, AppSettingsActivity::class.java).apply { - putExtra(AppSettingsActivity.EXTRA_SCROLL_TO, Settings.FOREGROUND_SERVICE) - } - val builder = NotificationCompat.Builder(this, NotificationUtils.CHANNEL_STATUS) - .setSmallIcon(R.drawable.ic_foreground_notify) - .setContentTitle(getString(R.string.foreground_service_notify_title)) - .setContentText(getString(R.string.foreground_service_notify_text)) - .setStyle(NotificationCompat.BigTextStyle()) - .setContentIntent(PendingIntent.getActivity(this, 0, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)) - .setCategory(NotificationCompat.CATEGORY_STATUS) - ServiceCompat.startForeground(this, NotificationUtils.NOTIFY_FOREGROUND, builder.build(), FOREGROUND_SERVICE_TYPE_DATA_SYNC) - } - - override fun onBind(intent: Intent?): Nothing? = null - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int) = START_STICKY - -} \ No newline at end of file diff --git a/app/src/main/kotlin/at/bitfire/davdroid/servicedetection/RefreshCollectionsWorker.kt b/app/src/main/kotlin/at/bitfire/davdroid/servicedetection/RefreshCollectionsWorker.kt index 2077cc06..2a970bcd 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/servicedetection/RefreshCollectionsWorker.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/servicedetection/RefreshCollectionsWorker.kt @@ -238,6 +238,9 @@ class RefreshCollectionsWorker @AssistedInject constructor( return Result.success() } + /** + * Used by WorkManager to show a foreground service notification for expedited jobs on Android <12. + */ override suspend fun getForegroundInfo(): ForegroundInfo { val notification = NotificationUtils.newBuilder(applicationContext, NotificationUtils.CHANNEL_STATUS) .setSmallIcon(R.drawable.ic_foreground_notify) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/settings/Settings.kt b/app/src/main/kotlin/at/bitfire/davdroid/settings/Settings.kt index cbdfa2c6..c9461166 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/settings/Settings.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/settings/Settings.kt @@ -9,7 +9,6 @@ import androidx.appcompat.app.AppCompatDelegate object Settings { const val BATTERY_OPTIMIZATION = "battery_optimization" - const val FOREGROUND_SERVICE = "foreground_service" const val DISTRUST_SYSTEM_CERTIFICATES = "distrust_system_certs" diff --git a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncWorker.kt b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncWorker.kt index 7bb186ed..48ab609c 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncWorker.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncWorker.kt @@ -426,6 +426,9 @@ class SyncWorker @AssistedInject constructor( return@withContext Result.success() } + /** + * Used by WorkManager to show a foreground service notification for expedited jobs on Android <12. + */ override suspend fun getForegroundInfo(): ForegroundInfo { val notification = NotificationUtils.newBuilder(applicationContext, NotificationUtils.CHANNEL_STATUS) .setSmallIcon(R.drawable.ic_foreground_notify) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/AppSettingsActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/AppSettingsActivity.kt index 70d60544..705fa0fb 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/AppSettingsActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/AppSettingsActivity.kt @@ -23,7 +23,6 @@ import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreferenceCompat import at.bitfire.cert4android.CustomCertStore import at.bitfire.davdroid.BuildConfig -import at.bitfire.davdroid.ForegroundService import at.bitfire.davdroid.R import at.bitfire.davdroid.resource.TaskUtils import at.bitfire.davdroid.settings.Settings @@ -167,16 +166,6 @@ class AppSettingsActivity: AppCompatActivity() { } } - findPreference(Settings.FOREGROUND_SERVICE)!!.apply { - isChecked = settings.getBooleanOrNull(Settings.FOREGROUND_SERVICE) == true - isEnabled = settings.getBooleanOrNull(Settings.BATTERY_OPTIMIZATION) == true - onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - settings.putBoolean(Settings.FOREGROUND_SERVICE, newValue as Boolean) - ForegroundService.startOrStop(requireActivity()) - false - } - } - // connection settings val proxyType = settings.getInt(Settings.PROXY_TYPE) findPreference(Settings.PROXY_TYPE)!!.apply { diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/NotificationUtils.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/NotificationUtils.kt index e41544d5..940b8b4c 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/NotificationUtils.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/NotificationUtils.kt @@ -24,13 +24,10 @@ object NotificationUtils { // notification IDs const val NOTIFY_VERBOSE_LOGGING = 1 const val NOTIFY_REFRESH_COLLECTIONS = 2 - const val NOTIFY_FOREGROUND = 3 const val NOTIFY_DATABASE_CORRUPTED = 4 - const val NOTIFY_BATTERY_OPTIMIZATION = 5 const val NOTIFY_SYNC_ERROR = 10 const val NOTIFY_INVALID_RESOURCE = 11 const val NOTIFY_WEBDAV_ACCESS = 12 - // const val NOTIFY_LOW_STORAGE = 13 const val NOTIFY_SYNC_EXPEDITED = 14 const val NOTIFY_TASKS_PROVIDER_TOO_OLD = 20 const val NOTIFY_PERMISSIONS = 21 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dbd6e5c5..f9b0e971 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -158,11 +158,7 @@ Service detection failed Couldn\'t refresh collection list - - Can not run in foreground - Battery optimization whitelisting required - - + Running in foreground On some devices, this is necessary for automatic synchronization. @@ -177,8 +173,6 @@ Battery optimization App is whitelisted (recommended) App is not whitelisted (not recommended) - Keep in foreground - May help if your device prevents automatic synchronization Connection Proxy type diff --git a/app/src/main/res/xml/settings_app.xml b/app/src/main/res/xml/settings_app.xml index 275a0628..97acad11 100644 --- a/app/src/main/res/xml/settings_app.xml +++ b/app/src/main/res/xml/settings_app.xml @@ -26,11 +26,6 @@ android:summaryOn="@string/app_settings_battery_optimization_whitelisted" android:summaryOff="@string/app_settings_battery_optimization_not_whitelisted"/> - -