Add plugin settings screen
This commit is contained in:
@@ -2,6 +2,8 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.plugin.Plugin
|
||||
import de.mm20.launcher2.plugin.PluginType
|
||||
|
||||
@@ -16,37 +18,44 @@ class PluginScanner(
|
||||
val plugins = mutableListOf<Plugin>()
|
||||
|
||||
for (cr in contentResolvers) {
|
||||
val providerInfo = cr.providerInfo ?: continue
|
||||
val authority = providerInfo.authority ?: continue
|
||||
val bundle = context.contentResolver.call(
|
||||
Uri.Builder()
|
||||
.scheme("content")
|
||||
.authority(authority)
|
||||
.build(),
|
||||
"getType",
|
||||
null,
|
||||
null,
|
||||
) ?: continue
|
||||
val type = bundle.getString("type")
|
||||
?.let {
|
||||
try {
|
||||
PluginType.valueOf(it)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
} ?: continue
|
||||
plugins.add(
|
||||
Plugin(
|
||||
label = cr.loadLabel(context.packageManager).toString(),
|
||||
description = providerInfo.metaData?.getString("de.mm20.launcher2.plugin.description"),
|
||||
packageName = providerInfo.packageName,
|
||||
className = providerInfo.name,
|
||||
type = type,
|
||||
authority = authority,
|
||||
settingsActivity = providerInfo.metaData?.getString("de.mm20.launcher2.plugin.settings"),
|
||||
enabled = false,
|
||||
try {
|
||||
val providerInfo = cr.providerInfo ?: continue
|
||||
val authority = providerInfo.authority ?: continue
|
||||
val bundle = context.contentResolver.call(
|
||||
Uri.Builder()
|
||||
.scheme("content")
|
||||
.authority(authority)
|
||||
.build(),
|
||||
"getType",
|
||||
null,
|
||||
null,
|
||||
) ?: continue
|
||||
val type = bundle.getString("type")
|
||||
?.let {
|
||||
try {
|
||||
PluginType.valueOf(it)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
} ?: continue
|
||||
plugins.add(
|
||||
Plugin(
|
||||
label = cr.loadLabel(context.packageManager).toString(),
|
||||
description = providerInfo.metaData?.getString("de.mm20.launcher2.plugin.description"),
|
||||
packageName = providerInfo.packageName,
|
||||
className = providerInfo.name,
|
||||
type = type,
|
||||
authority = authority,
|
||||
settingsActivity = providerInfo.metaData?.getString("de.mm20.launcher2.plugin.settings"),
|
||||
enabled = false,
|
||||
)
|
||||
)
|
||||
)
|
||||
} catch (e: SecurityException) {
|
||||
continue
|
||||
} catch (e: Exception) {
|
||||
CrashReporter.logException(e)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return plugins
|
||||
|
||||
@@ -2,9 +2,12 @@ package de.mm20.launcher2.plugins
|
||||
|
||||
import PluginScanner
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import androidx.core.content.ContextCompat
|
||||
import de.mm20.launcher2.plugin.Plugin
|
||||
@@ -16,6 +19,7 @@ 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.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -32,7 +36,11 @@ interface PluginService {
|
||||
fun enablePlugin(plugin: Plugin)
|
||||
fun disablePlugin(plugin: Plugin)
|
||||
fun getPluginsWithState(type: PluginType? = null): Flow<List<PluginWithState>>
|
||||
|
||||
fun isPluginHostInstalled(): Flow<Boolean>
|
||||
suspend fun getPluginState(plugin: Plugin): PluginState?
|
||||
|
||||
suspend fun getPluginIcon(plugin: Plugin): Drawable?
|
||||
}
|
||||
|
||||
internal class PluginServiceImpl(
|
||||
@@ -42,6 +50,10 @@ internal class PluginServiceImpl(
|
||||
|
||||
private val scope: CoroutineScope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
|
||||
private val pluginHostInstalled = MutableStateFlow(false)
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
||||
init {
|
||||
refreshPlugins()
|
||||
ContextCompat.registerReceiver(
|
||||
@@ -65,9 +77,16 @@ internal class PluginServiceImpl(
|
||||
repository.update(plugin.copy(enabled = false))
|
||||
}
|
||||
|
||||
private val mutex = Mutex()
|
||||
private fun refreshPlugins() {
|
||||
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 enabledPlugins =
|
||||
repository.findMany(enabled = true).first().map { it.authority }
|
||||
@@ -79,8 +98,8 @@ internal class PluginServiceImpl(
|
||||
it
|
||||
}
|
||||
}
|
||||
repository.deleteMany()
|
||||
repository.insertMany(plugins)
|
||||
repository.deleteMany().join()
|
||||
repository.insertMany(plugins).join()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,6 +147,26 @@ internal class PluginServiceImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override fun isPluginHostInstalled(): Flow<Boolean> {
|
||||
return pluginHostInstalled
|
||||
}
|
||||
|
||||
override suspend fun getPluginIcon(plugin: Plugin): Drawable? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val info = try {
|
||||
context.packageManager.getProviderInfo(
|
||||
ComponentName(
|
||||
plugin.packageName,
|
||||
plugin.className
|
||||
), 0
|
||||
)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
return@withContext null
|
||||
}
|
||||
info.loadIcon(context.packageManager) ?: info.applicationInfo?.loadIcon(context.packageManager)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class AppUpdateReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
refreshPlugins()
|
||||
|
||||
Reference in New Issue
Block a user