diff --git a/samples/catalog-app-shared/src/androidMain/kotlin/com/metacto/catalogapp/di/PlatformModule.kt b/samples/catalog-app-shared/src/androidMain/kotlin/com/metacto/catalogapp/di/PlatformModule.kt index ce3cc93a..f37e420d 100644 --- a/samples/catalog-app-shared/src/androidMain/kotlin/com/metacto/catalogapp/di/PlatformModule.kt +++ b/samples/catalog-app-shared/src/androidMain/kotlin/com/metacto/catalogapp/di/PlatformModule.kt @@ -1,7 +1,12 @@ package com.metacto.catalogapp.di +import com.metacto.catalogapp.permissions.PermissionFactory +import com.metacto.core.ui.permissions.helpers.IPermissionFactory import org.koin.dsl.module actual val platformModule = module { // Define android specific dependencies here + single { + PermissionFactory() + } } \ No newline at end of file diff --git a/samples/catalog-app-shared/src/androidMain/kotlin/com/metacto/catalogapp/permissions/PermissionFactory.kt b/samples/catalog-app-shared/src/androidMain/kotlin/com/metacto/catalogapp/permissions/PermissionFactory.kt new file mode 100644 index 00000000..0e645b84 --- /dev/null +++ b/samples/catalog-app-shared/src/androidMain/kotlin/com/metacto/catalogapp/permissions/PermissionFactory.kt @@ -0,0 +1,54 @@ +package com.metacto.catalogapp.permissions + +import android.Manifest +import android.os.Build +import com.metacto.core.ui.permissions.enums.Permission +import com.metacto.core.ui.permissions.helpers.IPermissionFactory + +class PermissionFactory : IPermissionFactory { + + override fun getPermissions(permission: Permission): List { + return when(permission) { + Permission.REMOTE_NOTIFICATION -> remoteNotificationsPermissions() + Permission.CAMERA -> listOf(Manifest.permission.CAMERA) + Permission.GALLERY -> galleryCompat() + Permission.STORAGE -> allStoragePermissions() + + else -> error( + "Permission $permission is not supported. Please implement the required permissions in the PermissionFactory." + ) + } + } + + private fun galleryCompat(): List { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + listOf( + Manifest.permission.READ_MEDIA_IMAGES, + Manifest.permission.READ_MEDIA_VIDEO + ) + } else { + listOf(Manifest.permission.READ_EXTERNAL_STORAGE) + } + } + + + private fun allStoragePermissions(): List { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + listOf( + Manifest.permission.READ_MEDIA_AUDIO, + Manifest.permission.READ_MEDIA_IMAGES, + Manifest.permission.READ_MEDIA_VIDEO + ) + } else { + listOf(Manifest.permission.READ_EXTERNAL_STORAGE) + } + } + + private fun remoteNotificationsPermissions(): List { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + listOf(Manifest.permission.POST_NOTIFICATIONS) + } else { + emptyList() + } + } +} \ No newline at end of file diff --git a/samples/playground-app-shared/src/androidMain/kotlin/com/metacto/playground/di/PlatformModule.kt b/samples/playground-app-shared/src/androidMain/kotlin/com/metacto/playground/di/PlatformModule.kt index 41b20d16..b4d8c404 100644 --- a/samples/playground-app-shared/src/androidMain/kotlin/com/metacto/playground/di/PlatformModule.kt +++ b/samples/playground-app-shared/src/androidMain/kotlin/com/metacto/playground/di/PlatformModule.kt @@ -4,4 +4,5 @@ import org.koin.dsl.module actual val platformModule = module { // Define android specific dependencies here + // TODO: Define permission factory for this project } \ No newline at end of file diff --git a/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/di/Di.android.kt b/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/di/Di.android.kt index c470119e..52b7b427 100644 --- a/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/di/Di.android.kt +++ b/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/di/Di.android.kt @@ -16,7 +16,7 @@ internal actual fun platformModule() = module { // Add Android specific dependencies here single { - PermissionManager(androidContext()) + PermissionManager(androidContext(), get()) } single { diff --git a/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/PermissionManager.kt b/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/PermissionManager.kt index a3293fe6..5ad3a973 100644 --- a/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/PermissionManager.kt +++ b/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/PermissionManager.kt @@ -17,7 +17,7 @@ import com.metacto.core.extensions.openAppSettings import com.metacto.core.ui.permissions.enums.Permission import com.metacto.core.ui.permissions.enums.PermissionState import com.metacto.core.ui.permissions.exceptions.DeniedAlwaysException -import com.metacto.core.ui.permissions.helpers.toPlatformPermission +import com.metacto.core.ui.permissions.helpers.IPermissionFactory import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.first @@ -27,7 +27,11 @@ import kotlinx.coroutines.withTimeoutOrNull import java.util.UUID import kotlin.coroutines.suspendCoroutine -internal class PermissionManager(private val context: Context) : IPermissionManager { +internal class PermissionManager( + private val context: Context, + private val permissionFactory: IPermissionFactory +) : IPermissionManager { + private val activityHolder = MutableStateFlow(null) private val launcherHolder = MutableStateFlow>?>(null) private var permissionCallback: PermissionCallback? = null @@ -114,7 +118,7 @@ internal class PermissionManager(private val context: Context) : IPermissionMana private suspend fun handlePermissionRequest(permission: Permission) { mutex.withLock { val launcher = awaitActivityResultLauncher() - val platformPermissions = permission.toPlatformPermission() + val platformPermissions = getAndroidPermissions(permission) suspendCoroutine { continuation -> permissionCallback = PermissionCallback(permission, continuation::resumeWith) @@ -135,6 +139,10 @@ internal class PermissionManager(private val context: Context) : IPermissionMana } } + private fun getAndroidPermissions(permission: Permission): List { + return permissionFactory.getPermissions(permission) + } + private suspend fun awaitActivityResultLauncher(): ActivityResultLauncher> { return launcherHolder.value ?: withTimeoutOrNull(AWAIT_ACTIVITY_TIMEOUT_MS) { launcherHolder.filterNotNull().first() @@ -157,7 +165,7 @@ internal class PermissionManager(private val context: Context) : IPermissionMana } private suspend fun getRuntimePermissionState(permission: Permission): PermissionState { - val permissions = permission.toPlatformPermission() + val permissions = getAndroidPermissions(permission) val status = permissions.map { ContextCompat.checkSelfPermission(context, it) } diff --git a/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/helpers/IPermissionFactory.kt b/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/helpers/IPermissionFactory.kt new file mode 100644 index 00000000..83068f5c --- /dev/null +++ b/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/helpers/IPermissionFactory.kt @@ -0,0 +1,7 @@ +package com.metacto.core.ui.permissions.helpers + +import com.metacto.core.ui.permissions.enums.Permission + +interface IPermissionFactory { + fun getPermissions(permission: Permission): List +} \ No newline at end of file diff --git a/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/helpers/PermissionsMap.kt b/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/helpers/PermissionsMap.kt deleted file mode 100644 index c83a74cb..00000000 --- a/ui/core-ui/src/androidMain/kotlin/com/metacto/core/ui/permissions/helpers/PermissionsMap.kt +++ /dev/null @@ -1,145 +0,0 @@ -package com.metacto.core.ui.permissions.helpers - -import android.Manifest -import android.os.Build -import com.metacto.core.ui.permissions.enums.Permission - -@Suppress("CyclomaticComplexMethod") -internal fun Permission.toPlatformPermission(): List { - return when (this) { - Permission.CAMERA -> listOf(Manifest.permission.CAMERA) - Permission.GALLERY -> galleryCompat() - Permission.STORAGE -> allStoragePermissions() - Permission.WRITE_STORAGE -> listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Permission.LOCATION -> fineLocationCompat() - Permission.COARSE_LOCATION -> listOf(Manifest.permission.ACCESS_COARSE_LOCATION) - Permission.BACKGROUND_LOCATION -> backgroundLocationCompat() - Permission.REMOTE_NOTIFICATION -> remoteNotificationsPermissions() - Permission.RECORD_AUDIO -> listOf(Manifest.permission.RECORD_AUDIO) - Permission.BLUETOOTH_LE -> allBluetoothPermissions() - Permission.BLUETOOTH_SCAN -> bluetoothScanCompat() - Permission.BLUETOOTH_ADVERTISE -> bluetoothAdvertiseCompat() - Permission.BLUETOOTH_CONNECT -> bluetoothConnectCompat() - Permission.CONTACTS -> listOf( - Manifest.permission.READ_CONTACTS, - Manifest.permission.WRITE_CONTACTS - ) - - Permission.MOTION -> motionPermissions() - Permission.CALENDER -> listOf( - Manifest.permission.READ_CALENDAR, - Manifest.permission.WRITE_CALENDAR - ) - } -} - -private fun allStoragePermissions(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - listOf( - Manifest.permission.READ_MEDIA_AUDIO, - Manifest.permission.READ_MEDIA_IMAGES, - Manifest.permission.READ_MEDIA_VIDEO - ) - } else { - listOf(Manifest.permission.READ_EXTERNAL_STORAGE) - } -} - -private fun galleryCompat(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - listOf( - Manifest.permission.READ_MEDIA_IMAGES, - Manifest.permission.READ_MEDIA_VIDEO - ) - } else { - listOf(Manifest.permission.READ_EXTERNAL_STORAGE) - } -} - -private fun fineLocationCompat(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - listOf( - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - ) - } else { - listOf(Manifest.permission.ACCESS_FINE_LOCATION) - } -} - -private fun backgroundLocationCompat(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - listOf( - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.ACCESS_BACKGROUND_LOCATION, - ) - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - listOf( - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_BACKGROUND_LOCATION, - ) - } else { - listOf(Manifest.permission.ACCESS_FINE_LOCATION) - } -} - -private fun allBluetoothPermissions(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - listOf( - Manifest.permission.BLUETOOTH_CONNECT, - Manifest.permission.BLUETOOTH_SCAN, - Manifest.permission.BLUETOOTH_ADVERTISE, - Manifest.permission.ACCESS_COARSE_LOCATION - ) - } else { - listOf( - Manifest.permission.BLUETOOTH, - Manifest.permission.ACCESS_COARSE_LOCATION - ) - } -} - -private fun bluetoothScanCompat(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - listOf(Manifest.permission.BLUETOOTH_SCAN) - } else { - listOf(Manifest.permission.BLUETOOTH) - } - -} - -private fun bluetoothAdvertiseCompat(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - listOf(Manifest.permission.BLUETOOTH_ADVERTISE) - } else { - listOf(Manifest.permission.BLUETOOTH) - } -} - -private fun bluetoothConnectCompat(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - listOf(Manifest.permission.BLUETOOTH_CONNECT) - } else { - listOf(Manifest.permission.BLUETOOTH) - } -} - -private fun motionPermissions(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - listOf( - Manifest.permission.ACTIVITY_RECOGNITION, - Manifest.permission.BODY_SENSORS - ) - } else { - listOf(Manifest.permission.BODY_SENSORS) - } -} - -private fun remoteNotificationsPermissions(): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - listOf(Manifest.permission.POST_NOTIFICATIONS) - } else { - emptyList() - } -} \ No newline at end of file