Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 2d686bee authored by Sunik Kupfer's avatar Sunik Kupfer Committed by GitHub
Browse files

Show a warning if calendar or contacts storage is deactivated or missing (#1243)



* Add AppTheme to previews

* Show warning when contacts or calendar system apps are missing or disabled

* Change android icon to database missing icon

* Remove duplication

* Use packageChangedFlow to observer live changes

* Send user to settings app when deactivated and manual when missing

* Find whether content provider app is available by authority

* [WIP] Minor changes

* Open "Manage apps" instead of manual

---------

Co-authored-by: default avatarRicki Hirner <hirner@bitfire.at>
parent 2438f1a8
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -8,11 +8,14 @@ import android.accounts.Account
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager.NameNotFoundException
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.PowerManager
import android.provider.CalendarContract
import android.provider.ContactsContract
import androidx.core.content.getSystemService
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.lifecycle.ViewModel
@@ -30,6 +33,7 @@ import at.bitfire.davdroid.ui.account.AccountProgress
import at.bitfire.davdroid.ui.intro.IntroPage
import at.bitfire.davdroid.ui.intro.IntroPageFactory
import at.bitfire.davdroid.util.broadcastReceiverFlow
import at.bitfire.davdroid.util.packageChangedFlow
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -48,9 +52,9 @@ import java.util.logging.Logger

@HiltViewModel(assistedFactory = AccountsModel.Factory::class)
class AccountsModel @AssistedInject constructor(
    @Assisted val syncAccountsOnInit: Boolean,
    @Assisted private val syncAccountsOnInit: Boolean,
    private val accountRepository: AccountRepository,
    @ApplicationContext val context: Context,
    @ApplicationContext private val context: Context,
    private val db: AppDatabase,
    introPageFactory: IntroPageFactory,
    private val logger: Logger,
@@ -203,6 +207,16 @@ class AccountsModel @AssistedInject constructor(
            }
        }

    /** whether the calendar storage is missing or disabled */
    val calendarStorageDisabled = packageChangedFlow(context).map {
        !contentProviderAvailable(CalendarContract.AUTHORITY)
    }

    /** whether the calendar storage is missing or disabled */
    val contactsStorageDisabled = packageChangedFlow(context).map {
        !contentProviderAvailable(ContactsContract.AUTHORITY)
    }


    init {
        if (syncAccountsOnInit)
@@ -221,4 +235,17 @@ class AccountsModel @AssistedInject constructor(
            syncWorkerManager.enqueueOneTimeAllAuthorities(account, manual = true)
    }


    // helpers

    fun contentProviderAvailable(authority: String): Boolean =
        try {
            // resolveContentProvider returns null if the provider app is disabled or missing;
            // so we can't distinguish between "disabled" and "not found"
            context.packageManager.resolveContentProvider(authority, 0) != null
        } catch (_: NameNotFoundException) {
            logger.fine("$authority provider app not found")
            false
        }

}
 No newline at end of file
+75 −29
Original line number Diff line number Diff line
@@ -62,10 +62,12 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -122,7 +124,9 @@ fun AccountsScreen(
        internetUnavailable = !model.networkAvailable.collectAsStateWithLifecycle(false).value,
        batterySaverActive = model.batterySaverActive.collectAsStateWithLifecycle(false).value,
        dataSaverActive = model.dataSaverEnabled.collectAsStateWithLifecycle(false).value,
        storageLow = model.storageLow.collectAsStateWithLifecycle(false).value
        storageLow = model.storageLow.collectAsStateWithLifecycle(false).value,
        calendarStorageDisabled = model.calendarStorageDisabled.collectAsStateWithLifecycle(false).value,
        contactsStorageDisabled = model.contactsStorageDisabled.collectAsStateWithLifecycle(false).value
    )
}

@@ -140,7 +144,9 @@ fun AccountsScreen(
    internetUnavailable: Boolean = false,
    batterySaverActive: Boolean = false,
    dataSaverActive: Boolean = false,
    storageLow: Boolean = false
    storageLow: Boolean = false,
    calendarStorageDisabled: Boolean = false,
    contactsStorageDisabled: Boolean = false
) {
    val scope = rememberCoroutineScope()

@@ -293,7 +299,14 @@ fun AccountsScreen(
                                    val intent = Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS)
                                    if (intent.resolveActivity(context.packageManager) != null)
                                        context.startActivity(intent)
                                }
                                },
                                calendarStorageDisabled = calendarStorageDisabled,
                                contactsStorageDisabled = contactsStorageDisabled,
                                onManageApps = {
                                    val intent = Intent(Settings.ACTION_APPLICATION_SETTINGS)
                                    if (intent.resolveActivity(context.packageManager) != null)
                                        context.startActivity(intent)
                                },
                            )

                            // account list
@@ -435,6 +448,7 @@ fun AccountList(
@Composable
@Preview
fun AccountList_Preview_Idle() {
    AppTheme {
        AccountList(
            listOf(
                AccountsModel.AccountInfo(
@@ -444,10 +458,12 @@ fun AccountList_Preview_Idle() {
            )
        )
    }
}

@Composable
@Preview
fun AccountList_Preview_SyncPending() {
    AppTheme {
        AccountList(listOf(
            AccountsModel.AccountInfo(
                Account("Account Name", "test"),
@@ -455,10 +471,12 @@ fun AccountList_Preview_SyncPending() {
            )
        ))
    }
}

@Composable
@Preview
fun AccountList_Preview_Syncing() {
    AppTheme {
        AccountList(listOf(
            AccountsModel.AccountInfo(
                Account("Account Name", "test"),
@@ -466,6 +484,7 @@ fun AccountList_Preview_Syncing() {
            )
        ))
    }
}


@Composable
@@ -479,7 +498,10 @@ fun SyncWarnings(
    dataSaverActive: Boolean = true,
    onManageDataSaver: () -> Unit = {},
    lowStorageWarning: Boolean = true,
    onManageStorage: () -> Unit = {}
    onManageStorage: () -> Unit = {},
    calendarStorageDisabled: Boolean = false,
    contactsStorageDisabled: Boolean = false,
    onManageApps: () -> Unit = {}
) {
    Column(Modifier.padding(horizontal = 8.dp)) {
        if (notificationsWarning)
@@ -531,17 +553,41 @@ fun SyncWarnings(
            ) {
                Text(stringResource(R.string.account_list_low_storage))
            }

        if (calendarStorageDisabled)
            ActionCard(
                icon = ImageVector.vectorResource(R.drawable.ic_database_off),
                actionText = stringResource(R.string.account_list_manage_apps),
                onAction = onManageApps,
                modifier = Modifier.padding(vertical = 4.dp)
            ) {
                Text(stringResource(R.string.account_list_calendar_storage_disabled))
            }

        if (contactsStorageDisabled)
            ActionCard(
                icon = ImageVector.vectorResource(R.drawable.ic_database_off),
                actionText = stringResource(R.string.account_list_manage_apps),
                onAction = onManageApps,
                modifier = Modifier.padding(vertical = 4.dp)
            ) {
                Text(stringResource(R.string.account_list_contacts_storage_disabled))
            }
    }
}

@Composable
@Preview
fun SyncWarnings_Preview() {
    AppTheme {
        SyncWarnings(
            notificationsWarning = true,
            internetWarning = true,
            batterySaverActive = true,
            dataSaverActive = true,
        lowStorageWarning = true
            lowStorageWarning = true,
            calendarStorageDisabled = true,
            contactsStorageDisabled = true
        )
    }
}
 No newline at end of file
+9 −0
Original line number Diff line number Diff line
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M446,514ZM552,419ZM446,514ZM552,419ZM446,514ZM552,419ZM791,904 L56,169l56,-57 736,736 -57,56ZM480,840q-151,0 -255.5,-46.5T120,680v-400q0,-26 17.5,-49.5T187,187l252,252q-72,-3 -133,-18t-106,-40v120q51,29 123,44t157,15q20,0 39,-0.5t38,-2.5l70,70q-34,7 -71,10t-76,3q-85,0 -157,-15t-123,-44v99q9,29 97.5,54.5T480,760q64,0 128.5,-13T715,715l58,58q-49,31 -125.5,49T480,840ZM830,717 L760,647v-66q-11,6 -22,11t-23,10l-61,-61q30,-8 56.5,-17.5T760,501v-120q-41,23 -94,37t-116,19l-76,-76q44,0 92,-7t89.5,-18.5q41.5,-11.5 70,-26T760,281q-11,-29 -100.5,-55T480,200q-37,0 -75.5,5T331,218l-66,-66q45,-15 100,-23.5t115,-8.5q149,0 254.5,47T840,280v400q0,10 -2.5,19t-7.5,18Z"
      android:fillColor="@android:color/black"/>
</vector>
+3 −0
Original line number Diff line number Diff line
@@ -141,6 +141,9 @@
    <string name="account_list_manage_battery_saver">Manage battery saver</string>
    <string name="account_list_low_storage">Storage space low. Android will not sync local changes immediately, but during the next regular sync.</string>
    <string name="account_list_manage_storage">Manage storage</string>
    <string name="account_list_calendar_storage_disabled">Calendar provider missing. Did you disable the \"Calendar storage\" system app?</string>
    <string name="account_list_contacts_storage_disabled">Contacts provider missing. Did you disable the \"Contacts storage\" system app?</string>
    <string name="account_list_manage_apps">Manage apps</string>
    <string name="account_list_welcome">Welcome to DAVx⁵!</string>
    <string name="account_list_empty">Connect to your server and keep your calendars and contacts synchronized.</string>
    <string name="accounts_sync_all">Sync all accounts</string>