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

Commit 0ac6dc85 authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Set target SDK to level 29 (Android 10)

- ask for ACCESS_FINE_LOCATION/ACCESS_BACKGROUND_LOCATION when sync is restricted to specific WiFi SSIDs
- use Android 5+ way to determine active network connections, if possible
parent 1a52794b
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -19,12 +19,12 @@ android {
    defaultConfig {
        applicationId "at.bitfire.davdroid"

        versionCode 302
        versionCode 303
        buildConfigField "long", "buildTime", System.currentTimeMillis() + "L"
        buildConfigField "boolean", "customCerts", "true"

        minSdkVersion 19        // Android 4.4
        targetSdkVersion 28     // Android 9.0
        targetSdkVersion 29     // Android 10.0
        multiDexEnabled true    // >64k methods for Android 4.4

        buildConfigField "String", "userAgent", "\"DAVx5\""
+6 −2
Original line number Diff line number Diff line
@@ -27,8 +27,12 @@
    <uses-permission android:name="android.permission.WRITE_CALENDAR"/>

    <!-- android.permission-group.LOCATION -->
    <!-- required since Android 8.1 to get the WiFi name (for "sync in Wifi only" feature) -->
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <!-- getting the WiFi name (for "sync in Wifi only") requires
      - coarse location (Android 8.1)
      - fine location (Android 10)  -->
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <!-- required since Android 10 to get the WiFi name while in background (= while syncing) -->
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

    <!-- ical4android declares task access permissions -->

+4 −0
Original line number Diff line number Diff line
@@ -54,6 +54,10 @@ class ContactsSyncAdapterService: SyncAdapterService() {
                }
                accountSettings.accountManager.setUserData(account, PREVIOUS_GROUP_METHOD, groupMethod)

                /* don't run sync if
                   - sync conditions (e.g. "sync only in WiFi") are not met AND
                   - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
                 */
                if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(accountSettings))
                    return

+21 −3
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ import android.app.Service
import android.content.*
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.wifi.WifiManager
import android.os.Build
import android.os.Bundle
@@ -93,18 +94,35 @@ abstract class SyncAdapterService: Service() {

        protected fun checkSyncConditions(settings: AccountSettings): Boolean {
            if (settings.getSyncWifiOnly()) {
                // WiFi required
                val connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager

                // check for connected WiFi network
                var wifiAvailable = false
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    connectivityManager.allNetworks.forEach { network ->
                        connectivityManager.getNetworkCapabilities(network)?.let { capabilities ->
                            if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
                                capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED))
                                wifiAvailable = true
                        }
                    }
                } else {
                    val network = connectivityManager.activeNetworkInfo
                if (network == null || network.type != ConnectivityManager.TYPE_WIFI || !network.isConnected) {
                    if (network?.isConnected == true && network.type == ConnectivityManager.TYPE_WIFI)
                        wifiAvailable = true
                }
                if (!wifiAvailable) {
                    Logger.log.info("Not on connected WiFi, stopping")
                    return false
                }
                // if execution reaches this point, we're on a connected WiFi

                settings.getSyncWifiOnlySSIDs()?.let { onlySSIDs ->
                    // getting the WiFi name requires location permission (and active location services) since Android 8.1
                    // see https://issuetracker.google.com/issues/70633700
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 &&
                        ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                        ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                        val intent = Intent(context, AccountSettingsActivity::class.java)
                        intent.putExtra(AccountSettingsActivity.EXTRA_ACCOUNT, settings.account)
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+12 −7
Original line number Diff line number Diff line
@@ -254,12 +254,17 @@ class AccountSettingsActivity: AppCompatActivity() {
                false
            }

            // getting the WiFi name requires location permission (and active location services) since Android 8.1
            // see https://issuetracker.google.com/issues/70633700
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 &&
                accountSettings.getSyncWifiOnly() && onlySSIDs != null &&
                ContextCompat.checkSelfPermission(requireActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
                    requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 0)
            // Android 8.1+: getting the WiFi name requires location permission (and active location services)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && accountSettings.getSyncWifiOnly() && onlySSIDs != null) {
                val requiredPermissions = mutableListOf(Manifest.permission.ACCESS_FINE_LOCATION)

                // Android 10+: getting the Wifi name in the background (while syncing) requires extra permission
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                    requiredPermissions += Manifest.permission.ACCESS_BACKGROUND_LOCATION

                if (requiredPermissions.any { ContextCompat.checkSelfPermission(requireActivity(), it) != PackageManager.PERMISSION_GRANTED })
                    requestPermissions(requiredPermissions.toTypedArray(), 0)
            }

            // preference group: CardDAV
            findPreference<ListPreference>("contact_group_method")!!.let {
@@ -379,7 +384,7 @@ class AccountSettingsActivity: AppCompatActivity() {
        override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults)

            if (permissions.first() == Manifest.permission.ACCESS_COARSE_LOCATION && grantResults.first() == PackageManager.PERMISSION_DENIED) {
            if (grantResults.any { it == PackageManager.PERMISSION_DENIED }) {
                // location permission denied, reset SSID restriction
                AccountSettings(requireActivity(), account).setSyncWifiOnlySSIDs(null)
                reload()
Loading