Remove forced wifi-only sync when Data Saver is active (bitfireAT/davx5#171)

* Remove forced wifi-only sync when Data Saver is active

* move data saver warning to AppWarningsManager

* Minor changes

Co-authored-by: Ricki Hirner <hirner@bitfire.at>
This commit is contained in:
Sunik Kupfer 2022-12-07 18:25:24 +01:00 committed by Ricki Hirner
parent 1b17124b80
commit e6ecc7a9b0
No known key found for this signature in database
GPG key ID: 79A019FCAAEDD3AA
6 changed files with 100 additions and 53 deletions

View file

@ -43,46 +43,6 @@ class DefaultsProvider(
Pair(Settings.PROXY_HOST, "localhost")
)
val dataSaverChangedListener by lazy {
object: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
evaluateDataSaver(true)
}
}
}
init {
if (Build.VERSION.SDK_INT >= 24) {
val dataSaverChangedFilter = IntentFilter(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED)
context.registerReceiver(dataSaverChangedListener, dataSaverChangedFilter)
evaluateDataSaver()
}
}
override fun forceReload() {
evaluateDataSaver()
}
override fun close() {
if (Build.VERSION.SDK_INT >= 24)
context.unregisterReceiver(dataSaverChangedListener)
}
fun evaluateDataSaver(notify: Boolean = false) {
if (Build.VERSION.SDK_INT >= 24) {
context.getSystemService<ConnectivityManager>()?.let { connectivityManager ->
if (connectivityManager.restrictBackgroundStatus == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED)
booleanDefaults[AccountSettings.KEY_WIFI_ONLY] = true
else
booleanDefaults -= AccountSettings.KEY_WIFI_ONLY
}
if (notify)
settingsManager.onSettingsChanged()
}
}
class Factory @Inject constructor(): SettingsProviderFactory {
override fun getProviders(context: Context, settingsManager: SettingsManager) =
listOf(DefaultsProvider(context, settingsManager))

View file

@ -10,10 +10,10 @@ import android.accounts.AccountManager
import android.accounts.OnAccountsUpdateListener
import android.app.Activity
import android.app.Application
import android.content.ContentResolver
import android.content.Intent
import android.content.SyncStatusObserver
import android.content.*
import android.content.pm.PackageManager
import android.net.*
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.*
@ -62,7 +62,7 @@ class AccountListFragment: Fragment() {
startActivity(Intent(requireActivity(), PermissionsActivity::class.java))
}
model.showSyncDisabled.observe(viewLifecycleOwner) { syncDisabled ->
model.globalSyncDisabled.observe(viewLifecycleOwner) { syncDisabled ->
if (syncDisabled) {
val snackbar = Snackbar
.make(view, R.string.accounts_global_sync_disabled, Snackbar.LENGTH_INDEFINITE)
@ -97,6 +97,17 @@ class AccountListFragment: Fragment() {
startActivity(intent)
}
model.dataSaverOn.observe(viewLifecycleOwner) { datasaverOn ->
binding.datasaverOnInfo.visibility = if (Build.VERSION.SDK_INT >= 24 && datasaverOn) View.VISIBLE else View.GONE
}
binding.manageDatasaver.setOnClickListener {
if (Build.VERSION.SDK_INT >= 24) {
val intent = Intent(Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS, Uri.parse("package:" + requireActivity().packageName))
if (intent.resolveActivity(requireActivity().packageManager) != null)
startActivity(intent)
}
}
val accountAdapter = AccountAdapter(requireActivity())
binding.list.apply {
layoutManager = LinearLayoutManager(requireActivity())
@ -196,11 +207,17 @@ class AccountListFragment: Fragment() {
@HiltViewModel
class Model @Inject constructor(
application: Application,
val warnings: AppWarningsManager
private val warnings: AppWarningsManager
): AndroidViewModel(application), OnAccountsUpdateListener, SyncStatusObserver {
data class AccountInfo(
val account: Account,
val status: SyncStatus
)
// Warnings
val showSyncDisabled = warnings.globalSyncDisabled
val globalSyncDisabled = warnings.globalSyncDisabled
val dataSaverOn = warnings.dataSaverEnabled
val networkAvailable = warnings.networkAvailable
val storageLow = warnings.storageLow
@ -220,11 +237,6 @@ class AccountListFragment: Fragment() {
)
}
data class AccountInfo(
val account: Account,
val status: SyncStatus
)
override fun onAccountsUpdated(newAccounts: Array<out Account>) {
reloadAccounts()
}

View file

@ -10,6 +10,7 @@ import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService
import androidx.lifecycle.MutableLiveData
import at.bitfire.davdroid.StorageLowReceiver
@ -27,6 +28,7 @@ import javax.inject.Inject
* - whether storage is low [storageLow]
* - whether global sync is disabled [globalSyncDisabled]
* - whether a network connection is available [networkAvailable]
* - whether data saver is turned on -> [dataSaverEnabled]
*/
class AppWarningsManager @Inject constructor(
@ApplicationContext private val context: Context,
@ -46,6 +48,10 @@ class AppWarningsManager @Inject constructor(
private var networkReceiver: BroadcastReceiver? = null
private val connectivityManager = context.getSystemService<ConnectivityManager>()!!
/** whether data saver is restricting background synchronization ([ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED]) */
val dataSaverEnabled = MutableLiveData<Boolean>()
var dataSaverChangedListener: BroadcastReceiver? = null
init {
Logger.log.fine("Watching for warning conditions")
@ -55,6 +61,25 @@ class AppWarningsManager @Inject constructor(
// Network
watchConnectivity()
// Data saver
if (Build.VERSION.SDK_INT >= 24) {
val listener = object: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
checkDataSaver()
}
}
val dataSaverChangedFilter = IntentFilter(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED)
context.registerReceiver(listener, dataSaverChangedFilter)
dataSaverChangedListener = listener
checkDataSaver()
}
}
override fun onStatusChanged(which: Int) {
globalSyncDisabled.postValue(!ContentResolver.getMasterSyncAutomatically())
}
private fun watchConnectivity() {
@ -105,8 +130,13 @@ class AppWarningsManager @Inject constructor(
}
}
override fun onStatusChanged(which: Int) {
globalSyncDisabled.postValue(!ContentResolver.getMasterSyncAutomatically())
@RequiresApi(24)
private fun checkDataSaver() {
context.getSystemService<ConnectivityManager>()?.let { connectivityManager ->
dataSaverEnabled.postValue(
connectivityManager.restrictBackgroundStatus == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED
)
}
}
override fun close() {
@ -122,6 +152,12 @@ class AppWarningsManager @Inject constructor(
networkCallback?.let {
connectivityManager.unregisterNetworkCallback(it)
}
// Data Saver
dataSaverChangedListener?.let { listener ->
context.unregisterReceiver(listener)
dataSaverChangedListener = null
}
}
}

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#FFFFFF" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M11,8v3H8v2h3v3h2v-3h3v-2h-3V8H11zM13,2.05v3.03c3.39,0.49 6,3.39 6,6.92c0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53C21.68,14.83 22,13.45 22,12C22,6.82 18.05,2.55 13,2.05zM12,19c-3.87,0 -7,-3.13 -7,-7c0,-3.53 2.61,-6.43 6,-6.92V2.05C5.94,2.55 2,6.81 2,12c0,5.52 4.47,10 9.99,10c3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"/>
</vector>

View file

@ -99,6 +99,38 @@
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/datasaver_on_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:contentPadding="@dimen/card_padding">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:visibility="visible"
app:drawableLeftCompat="@drawable/ic_datasaver_on"
app:drawableTint="?android:attr/textColorPrimary"
android:drawablePadding="8dp"
style="@style/TextAppearance.MaterialComponents.Body1"
android:text="@string/account_list_datasaver_enabled"/>
<Button
android:id="@+id/manage_datasaver"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:text="@string/account_list_manage_datasaver" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.recyclerview.widget.RecyclerView
android:id="@android:id/list"
android:layout_width="match_parent"

View file

@ -145,6 +145,8 @@
<string name="account_list_manage_connections">Manage connections</string>
<string name="account_list_low_storage">Storage space low. Android will not run synchronization.</string>
<string name="account_list_manage_storage">Manage storage</string>
<string name="account_list_datasaver_enabled">Data saver enabled. Background synchronization is restricted.</string>
<string name="account_list_manage_datasaver">Manage data saver</string>
<string name="account_list_empty">Welcome to DAVx⁵!\n\nYou can add a CalDAV/CardDAV account now.</string>
<string name="accounts_global_sync_disabled">System-wide automatic synchronization is disabled</string>
<string name="accounts_global_sync_enable">Enable</string>