React to changing profile availability
This commit is contained in:
@@ -5,7 +5,6 @@ import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Process
|
||||
import android.os.UserHandle
|
||||
import de.mm20.launcher2.search.AppProfile
|
||||
import de.mm20.launcher2.search.Application
|
||||
import de.mm20.launcher2.search.NullSerializer
|
||||
import de.mm20.launcher2.search.SavableSearchable
|
||||
@@ -15,7 +14,6 @@ class FakeApp: Application {
|
||||
override val componentName: ComponentName = ComponentName(randomString(), randomString())
|
||||
override val isSystemApp: Boolean = false
|
||||
override val isSuspended: Boolean = false
|
||||
override val profile: AppProfile = AppProfile.Personal
|
||||
override val user: UserHandle = Process.myUserHandle()
|
||||
override val versionName: String = "1.0"
|
||||
override val canUninstall: Boolean = false
|
||||
|
||||
@@ -11,6 +11,8 @@ import android.os.Looper
|
||||
import android.os.Process
|
||||
import android.os.UserHandle
|
||||
import de.mm20.launcher2.ktx.normalize
|
||||
import de.mm20.launcher2.profiles.Profile
|
||||
import de.mm20.launcher2.profiles.ProfileManager
|
||||
import de.mm20.launcher2.search.Application
|
||||
import de.mm20.launcher2.search.SearchableRepository
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
@@ -20,7 +22,9 @@ 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.map
|
||||
import kotlinx.coroutines.flow.runningFold
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
@@ -38,6 +42,7 @@ interface AppRepository : SearchableRepository<Application> {
|
||||
|
||||
internal class AppRepositoryImpl(
|
||||
private val context: Context,
|
||||
private val profileManager: ProfileManager,
|
||||
) : AppRepository {
|
||||
private val scope = CoroutineScope(Dispatchers.Default + Job())
|
||||
|
||||
@@ -45,11 +50,8 @@ internal class AppRepositoryImpl(
|
||||
context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
|
||||
private val installedApps = MutableStateFlow<List<LauncherApp>>(emptyList())
|
||||
private val suspendedPackages = MutableStateFlow<List<String>>(emptyList())
|
||||
|
||||
|
||||
private val profiles: List<UserHandle>
|
||||
get() = launcherApps.profiles.takeIf { it.isNotEmpty() } ?: listOf(Process.myUserHandle())
|
||||
private val profiles = profileManager.activeProfiles
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
||||
@@ -163,21 +165,42 @@ internal class AppRepositoryImpl(
|
||||
}
|
||||
|
||||
}, Handler(Looper.getMainLooper()))
|
||||
scope.launch {
|
||||
profiles.runningFold<List<Profile>, Pair<List<Profile>?, List<Profile>?>>(null to null) { acc, value ->
|
||||
acc.second to value
|
||||
}.collectLatest { (prev, curr) ->
|
||||
if (curr == null) return@collectLatest
|
||||
if (prev == null) {
|
||||
curr.forEach { addProfile(it) }
|
||||
} else {
|
||||
val added = curr - prev
|
||||
val removed = prev - curr
|
||||
added.forEach { addProfile(it) }
|
||||
removed.forEach { removeProfile(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun addProfile(profile: Profile) {
|
||||
mutex.withLock {
|
||||
val apps = installedApps.value.toMutableList()
|
||||
apps.addAll(getApplications(null, profile.userHandle))
|
||||
installedApps.value = apps
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeProfile(profile: Profile) {
|
||||
scope.launch {
|
||||
mutex.withLock {
|
||||
val apps = profiles.map { p ->
|
||||
try {
|
||||
launcherApps.getActivityList(null, p).mapNotNull { getApplication(it) }
|
||||
} catch (e: SecurityException) {
|
||||
emptyList()
|
||||
}
|
||||
}.flatten()
|
||||
val apps = installedApps.value.toMutableList()
|
||||
apps.removeAll { it.user == profile.userHandle }
|
||||
installedApps.value = apps
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getApplications(packageName: String, userHandle: UserHandle): List<LauncherApp> {
|
||||
private fun getApplications(packageName: String?, userHandle: UserHandle): List<LauncherApp> {
|
||||
if (packageName == context.packageName) return emptyList()
|
||||
|
||||
return try {
|
||||
|
||||
@@ -27,7 +27,6 @@ import de.mm20.launcher2.icons.TintedIconLayer
|
||||
import de.mm20.launcher2.icons.TransparentLayer
|
||||
import de.mm20.launcher2.ktx.getSerialNumber
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.search.AppProfile
|
||||
import de.mm20.launcher2.search.Application
|
||||
import de.mm20.launcher2.search.SearchableSerializer
|
||||
import de.mm20.launcher2.search.StoreLink
|
||||
@@ -61,9 +60,6 @@ internal data class LauncherApp(
|
||||
|
||||
private val isMainProfile = launcherActivityInfo.user == Process.myUserHandle()
|
||||
|
||||
override val profile: AppProfile
|
||||
get() = if (isMainProfile) AppProfile.Personal else AppProfile.Work
|
||||
|
||||
override val isSystemApp: Boolean = launcherActivityInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0
|
||||
|
||||
override val canUninstall: Boolean
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.koin.core.qualifier.named
|
||||
import org.koin.dsl.module
|
||||
|
||||
val applicationsModule = module {
|
||||
factory<SearchableRepository<Application>>(named<Application>()) { AppRepositoryImpl(androidContext()) }
|
||||
factory<AppRepository> { AppRepositoryImpl(androidContext()) }
|
||||
factory<SearchableRepository<Application>>(named<Application>()) { get<AppRepository>() }
|
||||
single<AppRepository> { AppRepositoryImpl(androidContext(), get()) }
|
||||
factory<SearchableDeserializer>(named(LauncherApp.Domain)) { LauncherAppDeserializer(androidContext()) }
|
||||
}
|
||||
Reference in New Issue
Block a user