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

Commit f057b41c authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Android 11: handle new background location permissions for WiFi SSID restriction

parent ab5f834d
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
    <!-- 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_COARSE_LOCATION"/>
    <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"/>
@@ -88,11 +89,18 @@
            android:name=".ui.account.AccountActivity"
            android:parentActivityName=".ui.AccountsActivity"
            android:theme="@style/AppTheme.NoActionBar"/>
        <activity android:name=".ui.account.SettingsActivity"/>
        <activity android:name=".ui.CreateAddressBookActivity"
        <activity
            android:name=".ui.CreateAddressBookActivity"
            android:label="@string/create_addressbook"/>
        <activity android:name=".ui.CreateCalendarActivity"
        <activity
            android:name=".ui.CreateCalendarActivity"
            android:label="@string/create_calendar"/>
        <activity
            android:name=".ui.account.SettingsActivity" />
        <activity
            android:name=".ui.account.WifiPermissionsActivity"
            android:label="@string/wifi_permissions_label"
            android:parentActivityName=".ui.account.SettingsActivity" />

        <activity
            android:name=".ui.DebugInfoActivity"
+39 −0
Original line number Diff line number Diff line
@@ -5,9 +5,14 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.LocationManager
import android.net.Uri
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.location.LocationManagerCompat
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.NotificationUtils
import at.bitfire.davdroid.ui.PermissionsActivity

@@ -22,6 +27,31 @@ object PermissionUtils {
            Manifest.permission.WRITE_CALENDAR
    )

    val WIFI_SSID_PERMISSIONS =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
            else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION)
            else
                arrayOf()

    /**
     * Checks whether all conditions to access the current WiFi's SSID are met:
     *
     * 1. location permissions ([WIFI_SSID_PERMISSIONS]) granted
     * 2. location enabled
     *
     * @return *true* if SSID can be obtained; *false* if the SSID will be <unknown> or something like that
     */
    fun canAccessWifiSsid(context: Context): Boolean {
        val locationEnabled = ContextCompat.getSystemService(context, LocationManager::class.java)?.let { locationManager ->
            LocationManagerCompat.isLocationEnabled(locationManager)
        } ?: /* location feature not available on this device */ false

        return  havePermissions(context, WIFI_SSID_PERMISSIONS) &&
                locationEnabled
    }

    /**
     * Checks whether at least one of the given permissions is granted.
     *
@@ -64,4 +94,13 @@ object PermissionUtils {
                .notify(NotificationUtils.NOTIFY_PERMISSIONS, notify)
    }

    fun showAppSettings(context: Context) {
        val intent = Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                Uri.fromParts("package", BuildConfig.APPLICATION_ID, null))
        if (intent.resolveActivity(context.packageManager) != null)
            context.startActivity(intent)
        else
            Logger.log.warning("App settings Intent not resolvable")
    }

}
 No newline at end of file
+8 −4
Original line number Diff line number Diff line
@@ -229,10 +229,14 @@ class AccountSettings(
    fun setSyncWiFiOnly(wiFiOnly: Boolean) =
            accountManager.setUserData(account, KEY_WIFI_ONLY, if (wiFiOnly) "1" else null)

    fun getSyncWifiOnlySSIDs(): List<String>? = (if (settings.containsKey(KEY_WIFI_ONLY_SSIDS))
    fun getSyncWifiOnlySSIDs(): List<String>? =
            if (getSyncWifiOnly()) {
                (if (settings.containsKey(KEY_WIFI_ONLY_SSIDS))
                    settings.getString(KEY_WIFI_ONLY_SSIDS)
                else
                    accountManager.getUserData(account, KEY_WIFI_ONLY_SSIDS))?.split(',')
            } else
                null
    fun setSyncWifiOnlySSIDs(ssids: List<String>?) =
            accountManager.setUserData(account, KEY_WIFI_ONLY_SSIDS, StringUtils.trimToNull(ssids?.joinToString(",")))

+0 −1
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ import android.accounts.AccountManager
import android.content.Context
import android.os.Bundle
import at.bitfire.davdroid.log.Logger
import kotlin.jvm.Throws

object AccountUtils {

+12 −13
Original line number Diff line number Diff line
@@ -8,23 +8,19 @@

package at.bitfire.davdroid.syncadapter

import android.Manifest
import android.accounts.Account
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
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.PermissionUtils
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.ui.account.SettingsActivity
import at.bitfire.davdroid.ui.account.WifiPermissionsActivity
import java.lang.ref.WeakReference
import java.util.*
import java.util.logging.Level
@@ -167,22 +163,25 @@ abstract class SyncAdapterService: Service() {
                // 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_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                        val intent = Intent(context, SettingsActivity::class.java)
                        intent.putExtra(SettingsActivity.EXTRA_ACCOUNT, settings.account)
                    // check required permissions and location status
                    if (!PermissionUtils.canAccessWifiSsid(context)) {
                        // not all permissions granted; show notification
                        val intent = Intent(context, WifiPermissionsActivity::class.java)
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        intent.putExtra(WifiPermissionsActivity.EXTRA_ACCOUNT, settings.account)
                        PermissionUtils.notifyPermissions(context, intent)

                        Logger.log.warning("Can't access WiFi SSID, aborting sync")
                        return false
                    }

                    val wifi = context.getSystemService<WifiManager>()!!
                    val info = wifi.connectionInfo
                    if (info == null || !onlySSIDs.contains(info.ssid.trim('"'))) {
                        Logger.log.info("Connected to wrong WiFi network (${info.ssid}), ignoring")
                        Logger.log.info("Connected to wrong WiFi network (${info.ssid}), aborting sync")
                        return false
                    }
                    } else
                        Logger.log.fine("Connected to WiFi network ${info.ssid}")
                }
            }
            return true
Loading