AccountSettingsActivity: make canAccessWifiSsid live-capable (#732)

* Added `canAccessWifiSsidLive`

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

* Fixed initial state

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

* Cleaned up code

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

* More cleanup

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

* Removed inspection check

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Renamed function

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Using `broadcastReceiverFlow`

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Simplified check

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Using `MODE_CHANGED_ACTION`

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Updated comment

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Set default value for immediate

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

* Use derivedStateOf instead of produceState; correctly collect broadcastReceiverFlow

* Always show WifiSSID Card in Preview (otherwise Preview won't render)

* Don't call flow.map in Composable

---------

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
This commit is contained in:
Arnau Mora 2024-05-11 14:49:56 +02:00 committed by GitHub
parent 0552bcab4a
commit a246046f41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 60 additions and 7 deletions

View file

@ -292,13 +292,8 @@ class AccountSettingsActivity: AppCompatActivity() {
onDismiss = { showWifiOnlySsidsDialog = false }
)
// TODO make canAccessWifiSsid live-capable
val canAccessWifiSsid =
if (LocalInspectionMode.current)
false
else
PermissionUtils.canAccessWifiSsid(context)
if (onlyOnSsids != null && !canAccessWifiSsid)
val canAccessWifiSsid by PermissionUtils.rememberCanAccessWifiSsid()
if (LocalInspectionMode.current || (onlyOnSsids != null && !canAccessWifiSsid))
ActionCard(
icon = Icons.Default.SyncProblem,
actionText = stringResource(R.string.settings_sync_wifi_only_ssids_permissions_action),

View file

@ -8,21 +8,35 @@ import android.Manifest
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.location.LocationManager
import android.net.Uri
import android.os.Build
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.location.LocationManagerCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.NotificationUtils
import at.bitfire.davdroid.ui.NotificationUtils.notifyIfPossible
import at.bitfire.davdroid.ui.PermissionsActivity
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
object PermissionUtils {
@ -73,6 +87,50 @@ object PermissionUtils {
locationAvailable
}
/**
* Returns a live state of whether all conditions to access the current WiFi's SSID are met:
*
* 1. location permissions ([WIFI_SSID_PERMISSIONS]) granted (Android 8.1+)
* 2. location enabled (Android 9+)
*
* @return `true` if SSID can be obtained reliably; `false` otherwise (SSID will be "unknown" or something like that)
*/
@Composable
@OptIn(ExperimentalPermissionsApi::class)
fun rememberCanAccessWifiSsid(): State<Boolean> {
// before Android 8.1, SSIDs are always readable
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1)
return remember { mutableStateOf(true) }
val locationAvailableFlow =
// Android 9+: dynamically check whether Location is enabled
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
locationEnabledFlow(LocalContext.current)
else
// Android <9 doesn't require active Location to read the SSID
flowOf(true)
val locationAvailable by locationAvailableFlow.collectAsStateWithLifecycle(false)
val permissions = rememberMultiplePermissionsState(WIFI_SSID_PERMISSIONS.toList())
return remember {
derivedStateOf {
locationAvailable && permissions.allPermissionsGranted
}
}
}
private fun locationEnabledFlow(context: Context): Flow<Boolean> =
broadcastReceiverFlow(
context,
IntentFilter(LocationManager.MODE_CHANGED_ACTION),
null,
immediate = true
).map {
val locationManager = context.getSystemService<LocationManager>()!!
LocationManagerCompat.isLocationEnabled(locationManager)
}
/**
* Checks whether at least one of the given permissions is granted.
*