Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:56:56 +01:00
parent 75dc487a7a
commit 39c29d175b
6317 changed files with 388324 additions and 2 deletions

View file

@ -0,0 +1,13 @@
plugins {
id(ThunderbirdPlugins.Library.android)
}
android {
namespace = "app.k9mail.core.android.permissions"
}
dependencies {
testImplementation(libs.androidx.test.core)
testImplementation(libs.robolectric)
testImplementation(libs.assertk)
}

View file

@ -0,0 +1,38 @@
package app.k9mail.core.android.permissions
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat
/**
* Checks if a [Permission] has been granted to the app.
*/
class AndroidPermissionChecker(
private val context: Context,
) : PermissionChecker {
override fun checkPermission(permission: Permission): PermissionState {
return when (permission) {
Permission.Contacts -> {
checkSelfPermission(Manifest.permission.READ_CONTACTS)
}
Permission.Notifications -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)
} else {
PermissionState.GrantedImplicitly
}
}
}
}
private fun checkSelfPermission(permission: String): PermissionState {
return if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) {
PermissionState.Granted
} else {
PermissionState.Denied
}
}
}

View file

@ -0,0 +1,14 @@
package app.k9mail.core.android.permissions
import android.os.Build
import androidx.annotation.ChecksSdkIntAtLeast
/**
* Checks if the Android version the app is running on supports runtime permissions.
*/
internal class AndroidPermissionsModelChecker : PermissionsModelChecker {
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.M)
override fun hasRuntimePermissions(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
}
}

View file

@ -0,0 +1,9 @@
package app.k9mail.core.android.permissions
import org.koin.core.module.Module
import org.koin.dsl.module
val corePermissionsAndroidModule: Module = module {
factory<PermissionChecker> { AndroidPermissionChecker(context = get()) }
factory<PermissionsModelChecker> { AndroidPermissionsModelChecker() }
}

View file

@ -0,0 +1,9 @@
package app.k9mail.core.android.permissions
/**
* System permissions we ask for during onboarding.
*/
enum class Permission {
Contacts,
Notifications,
}

View file

@ -0,0 +1,8 @@
package app.k9mail.core.android.permissions
/**
* Checks if a [Permission] has been granted to the app.
*/
interface PermissionChecker {
fun checkPermission(permission: Permission): PermissionState
}

View file

@ -0,0 +1,10 @@
package app.k9mail.core.android.permissions
enum class PermissionState {
/**
* The permission is not a runtime permission in the Android version we're running on.
*/
GrantedImplicitly,
Granted,
Denied,
}

View file

@ -0,0 +1,8 @@
package app.k9mail.core.android.permissions
/**
* Checks what permission model the system is using.
*/
interface PermissionsModelChecker {
fun hasRuntimePermissions(): Boolean
}

View file

@ -0,0 +1,66 @@
package app.k9mail.core.android.permissions
import android.Manifest
import android.app.Application
import android.os.Build
import androidx.test.core.app.ApplicationProvider
import assertk.assertThat
import assertk.assertions.isEqualTo
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.Shadows
import org.robolectric.annotation.Config
@RunWith(RobolectricTestRunner::class)
@Config(minSdk = Build.VERSION_CODES.TIRAMISU)
class AndroidPermissionCheckerTest {
private val application: Application = ApplicationProvider.getApplicationContext()
private val shadowApplication = Shadows.shadowOf(application)
private val permissionChecker = AndroidPermissionChecker(application)
@Test
fun `granted READ_CONTACTS permission`() {
shadowApplication.grantPermissions(Manifest.permission.READ_CONTACTS)
val result = permissionChecker.checkPermission(Permission.Contacts)
assertThat(result).isEqualTo(PermissionState.Granted)
}
@Test
fun `denied READ_CONTACTS permission`() {
shadowApplication.denyPermissions(Manifest.permission.READ_CONTACTS)
val result = permissionChecker.checkPermission(Permission.Contacts)
assertThat(result).isEqualTo(PermissionState.Denied)
}
@Test
fun `granted POST_NOTIFICATIONS permission`() {
shadowApplication.grantPermissions(Manifest.permission.POST_NOTIFICATIONS)
val result = permissionChecker.checkPermission(Permission.Notifications)
assertThat(result).isEqualTo(PermissionState.Granted)
}
@Test
fun `denied POST_NOTIFICATIONS permission`() {
shadowApplication.denyPermissions(Manifest.permission.POST_NOTIFICATIONS)
val result = permissionChecker.checkPermission(Permission.Notifications)
assertThat(result).isEqualTo(PermissionState.Denied)
}
@Test
@Config(minSdk = Build.VERSION_CODES.S_V2, maxSdk = Build.VERSION_CODES.S_V2)
fun `POST_NOTIFICATIONS permission not available`() {
val result = permissionChecker.checkPermission(Permission.Notifications)
assertThat(result).isEqualTo(PermissionState.GrantedImplicitly)
}
}