Implement custom permission system for plugins

This commit is contained in:
MM20
2023-12-18 16:51:48 +01:00
parent 1c542f38ba
commit cb7f6b6693
20 changed files with 294 additions and 126 deletions
@@ -4,5 +4,5 @@ import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module
val servicesPluginsModule = module {
single<PluginService> { PluginServiceImpl(androidContext(), get(), get()) }
single<PluginService> { PluginServiceImpl(androidContext(), get()) }
}
@@ -13,8 +13,6 @@ import android.os.Build
import android.util.Base64
import android.util.Log
import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.plugin.Plugin
import de.mm20.launcher2.plugin.PluginPackage
import de.mm20.launcher2.plugin.PluginRepository
@@ -25,8 +23,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
@@ -50,8 +46,6 @@ interface PluginService {
enabled: Boolean? = null,
): Flow<List<PluginWithState>>
fun isPluginHostInstalled(): Flow<Boolean>
fun getPluginPackages(): Flow<List<PluginPackage>>
fun getPluginPackage(packageName: String): Flow<PluginPackage?>
suspend fun getPluginState(plugin: Plugin): PluginState?
@@ -65,13 +59,10 @@ interface PluginService {
internal class PluginServiceImpl(
private val context: Context,
private val repository: PluginRepository,
private val permissionsManager: PermissionsManager,
) : PluginService {
private val scope: CoroutineScope = CoroutineScope(Job() + Dispatchers.Default)
private val pluginHostInstalled = MutableStateFlow(false)
private val mutex = Mutex()
init {
@@ -84,14 +75,6 @@ internal class PluginServiceImpl(
addAction(Intent.ACTION_PACKAGE_CHANGED)
addDataScheme("package")
})
scope.launch {
permissionsManager.hasPermission(PermissionGroup.Plugins).collectLatest {
if (it) {
refreshPlugins()
}
}
}
}
override fun enablePluginPackage(plugin: PluginPackage) {
@@ -113,14 +96,6 @@ internal class PluginServiceImpl(
private fun refreshPlugins() {
Log.d("PluginService", "Refreshing plugins")
scope.launch {
try {
val permission =
context.packageManager.getPermissionInfo(PluginContract.Permission, 0)
pluginHostInstalled.value = permission != null
} catch (e: PackageManager.NameNotFoundException) {
pluginHostInstalled.value = false
return@launch
}
mutex.withLock {
val enabledPluginPackages =
repository.findMany(enabled = true).first().map { it.packageName }.distinct()
@@ -157,24 +132,25 @@ internal class PluginServiceImpl(
}
override suspend fun getPluginState(plugin: Plugin): PluginState {
val bundle = withContext(Dispatchers.IO) {
context.contentResolver.call(
Uri.Builder()
.scheme("content")
.authority(plugin.authority)
.build(),
PluginContract.Methods.GetState,
null,
null
)
} ?: return PluginState.Error
val bundle =
try {
withContext(Dispatchers.IO) {
context.contentResolver.call(
Uri.Builder()
.scheme("content")
.authority(plugin.authority)
.build(),
PluginContract.Methods.GetState,
null,
null
)
} ?: return PluginState.Error
} catch (e: SecurityException) {
return PluginState.NoPermission
}
return PluginState.fromBundle(bundle) ?: PluginState.Error
}
override fun isPluginHostInstalled(): Flow<Boolean> {
return pluginHostInstalled
}
override suspend fun getPluginIcon(plugin: Plugin): Drawable? {
return withContext(Dispatchers.IO) {
val info = try {