Loading packages/SettingsLib/Spa/TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,9 @@ "presubmit": [ { "name": "SpaLibTests" }, { "name": "SpaPrivilegedLibTests" } ] } packages/SettingsLib/SpaPrivileged/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -45,3 +45,9 @@ java_defaults { "-J-Xmx4G", ], } // Expose the srcs to tests, so the tests can access the internal classes. filegroup { name: "SpaPrivilegedLib_srcs", srcs: ["src/**/*.kt"], } packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppsRepository.kt→packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt +27 −16 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.content.pm.UserInfo import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope Loading @@ -30,14 +29,25 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map class AppsRepository(context: Context) { /** * The config used to load the App List. */ internal data class AppListConfig( val userId: Int, val showInstantApps: Boolean, ) /** * The repository to load the App List data. */ internal class AppListRepository(context: Context) { private val packageManager = context.packageManager fun loadApps(userInfoFlow: Flow<UserInfo>): Flow<List<ApplicationInfo>> = userInfoFlow fun loadApps(configFlow: Flow<AppListConfig>): Flow<List<ApplicationInfo>> = configFlow .map { loadApps(it) } .flowOn(Dispatchers.Default) private suspend fun loadApps(userInfo: UserInfo): List<ApplicationInfo> { private suspend fun loadApps(config: AppListConfig): List<ApplicationInfo> { return coroutineScope { val hiddenSystemModulesDeferred = async { packageManager.getInstalledModules(0) Loading @@ -50,11 +60,11 @@ class AppsRepository(context: Context) { PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong() ) val installedApplicationsAsUser = packageManager.getInstalledApplicationsAsUser(flags, userInfo.id) packageManager.getInstalledApplicationsAsUser(flags, config.userId) val hiddenSystemModules = hiddenSystemModulesDeferred.await() installedApplicationsAsUser.filter { app -> app.isInAppList(hiddenSystemModules) app.isInAppList(config.showInstantApps, hiddenSystemModules) } } } Loading @@ -63,9 +73,7 @@ class AppsRepository(context: Context) { userIdFlow: Flow<Int>, showSystemFlow: Flow<Boolean>, ): Flow<(app: ApplicationInfo) -> Boolean> = userIdFlow.combine(showSystemFlow) { userId, showSystem -> showSystemPredicate(userId, showSystem) } userIdFlow.combine(showSystemFlow, ::showSystemPredicate) private suspend fun showSystemPredicate( userId: Int, Loading Loading @@ -102,11 +110,14 @@ class AppsRepository(context: Context) { } companion object { private fun ApplicationInfo.isInAppList(hiddenSystemModules: Set<String>) = when { private fun ApplicationInfo.isInAppList( showInstantApps: Boolean, hiddenSystemModules: Set<String>, ) = when { !showInstantApps && isInstantApp -> false packageName in hiddenSystemModules -> false enabled -> true enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER -> true isDisabledUntilUsed -> true else -> false } } Loading packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt +9 −9 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.settingslib.spaprivileged.model.app import android.app.Application import android.content.pm.ApplicationInfo import android.content.pm.UserInfo import android.icu.text.Collator import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope Loading Loading @@ -48,25 +47,26 @@ internal data class AppListData<T : AppRecord>( internal class AppListViewModel<T : AppRecord>( application: Application, ) : AndroidViewModel(application) { val userInfo = StateFlowBridge<UserInfo>() val appListConfig = StateFlowBridge<AppListConfig>() val listModel = StateFlowBridge<AppListModel<T>>() val showSystem = StateFlowBridge<Boolean>() val option = StateFlowBridge<Int>() val searchQuery = StateFlowBridge<String>() private val appsRepository = AppsRepository(application) private val appListRepository = AppListRepository(application) private val appRepository = AppRepositoryImpl(application) private val collator = Collator.getInstance().freeze() private val labelMap = ConcurrentHashMap<String, String>() private val scope = viewModelScope + Dispatchers.Default private val userIdFlow = userInfo.flow.map { it.id } private val userIdFlow = appListConfig.flow.map { it.userId } private val recordListFlow = listModel.flow .flatMapLatest { it.transform(userIdFlow, appsRepository.loadApps(userInfo.flow)) } .flatMapLatest { it.transform(userIdFlow, appListRepository.loadApps(appListConfig.flow)) } .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) private val systemFilteredFlow = appsRepository.showSystemPredicate(userIdFlow, showSystem.flow) private val systemFilteredFlow = appListRepository.showSystemPredicate(userIdFlow, showSystem.flow) .combine(recordListFlow) { showAppPredicate, recordList -> recordList.filter { showAppPredicate(it.app) } } Loading packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/Apps.kt→packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfos.kt +2 −2 Original line number Diff line number Diff line Loading @@ -32,8 +32,8 @@ val ApplicationInfo.userHandle: UserHandle fun ApplicationInfo.hasFlag(flag: Int): Boolean = (flags and flag) > 0 /** Checks whether the application is disabled until used. */ fun ApplicationInfo.isDisabledUntilUsed(): Boolean = enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED val ApplicationInfo.isDisabledUntilUsed: Boolean get() = enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED /** Converts to the route string which used in navigation. */ fun ApplicationInfo.toRoute() = "$packageName/$userId" Loading
packages/SettingsLib/Spa/TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,9 @@ "presubmit": [ { "name": "SpaLibTests" }, { "name": "SpaPrivilegedLibTests" } ] }
packages/SettingsLib/SpaPrivileged/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -45,3 +45,9 @@ java_defaults { "-J-Xmx4G", ], } // Expose the srcs to tests, so the tests can access the internal classes. filegroup { name: "SpaPrivilegedLib_srcs", srcs: ["src/**/*.kt"], }
packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppsRepository.kt→packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt +27 −16 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.content.pm.UserInfo import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope Loading @@ -30,14 +29,25 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map class AppsRepository(context: Context) { /** * The config used to load the App List. */ internal data class AppListConfig( val userId: Int, val showInstantApps: Boolean, ) /** * The repository to load the App List data. */ internal class AppListRepository(context: Context) { private val packageManager = context.packageManager fun loadApps(userInfoFlow: Flow<UserInfo>): Flow<List<ApplicationInfo>> = userInfoFlow fun loadApps(configFlow: Flow<AppListConfig>): Flow<List<ApplicationInfo>> = configFlow .map { loadApps(it) } .flowOn(Dispatchers.Default) private suspend fun loadApps(userInfo: UserInfo): List<ApplicationInfo> { private suspend fun loadApps(config: AppListConfig): List<ApplicationInfo> { return coroutineScope { val hiddenSystemModulesDeferred = async { packageManager.getInstalledModules(0) Loading @@ -50,11 +60,11 @@ class AppsRepository(context: Context) { PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong() ) val installedApplicationsAsUser = packageManager.getInstalledApplicationsAsUser(flags, userInfo.id) packageManager.getInstalledApplicationsAsUser(flags, config.userId) val hiddenSystemModules = hiddenSystemModulesDeferred.await() installedApplicationsAsUser.filter { app -> app.isInAppList(hiddenSystemModules) app.isInAppList(config.showInstantApps, hiddenSystemModules) } } } Loading @@ -63,9 +73,7 @@ class AppsRepository(context: Context) { userIdFlow: Flow<Int>, showSystemFlow: Flow<Boolean>, ): Flow<(app: ApplicationInfo) -> Boolean> = userIdFlow.combine(showSystemFlow) { userId, showSystem -> showSystemPredicate(userId, showSystem) } userIdFlow.combine(showSystemFlow, ::showSystemPredicate) private suspend fun showSystemPredicate( userId: Int, Loading Loading @@ -102,11 +110,14 @@ class AppsRepository(context: Context) { } companion object { private fun ApplicationInfo.isInAppList(hiddenSystemModules: Set<String>) = when { private fun ApplicationInfo.isInAppList( showInstantApps: Boolean, hiddenSystemModules: Set<String>, ) = when { !showInstantApps && isInstantApp -> false packageName in hiddenSystemModules -> false enabled -> true enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER -> true isDisabledUntilUsed -> true else -> false } } Loading
packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt +9 −9 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.settingslib.spaprivileged.model.app import android.app.Application import android.content.pm.ApplicationInfo import android.content.pm.UserInfo import android.icu.text.Collator import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope Loading Loading @@ -48,25 +47,26 @@ internal data class AppListData<T : AppRecord>( internal class AppListViewModel<T : AppRecord>( application: Application, ) : AndroidViewModel(application) { val userInfo = StateFlowBridge<UserInfo>() val appListConfig = StateFlowBridge<AppListConfig>() val listModel = StateFlowBridge<AppListModel<T>>() val showSystem = StateFlowBridge<Boolean>() val option = StateFlowBridge<Int>() val searchQuery = StateFlowBridge<String>() private val appsRepository = AppsRepository(application) private val appListRepository = AppListRepository(application) private val appRepository = AppRepositoryImpl(application) private val collator = Collator.getInstance().freeze() private val labelMap = ConcurrentHashMap<String, String>() private val scope = viewModelScope + Dispatchers.Default private val userIdFlow = userInfo.flow.map { it.id } private val userIdFlow = appListConfig.flow.map { it.userId } private val recordListFlow = listModel.flow .flatMapLatest { it.transform(userIdFlow, appsRepository.loadApps(userInfo.flow)) } .flatMapLatest { it.transform(userIdFlow, appListRepository.loadApps(appListConfig.flow)) } .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) private val systemFilteredFlow = appsRepository.showSystemPredicate(userIdFlow, showSystem.flow) private val systemFilteredFlow = appListRepository.showSystemPredicate(userIdFlow, showSystem.flow) .combine(recordListFlow) { showAppPredicate, recordList -> recordList.filter { showAppPredicate(it.app) } } Loading
packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/Apps.kt→packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfos.kt +2 −2 Original line number Diff line number Diff line Loading @@ -32,8 +32,8 @@ val ApplicationInfo.userHandle: UserHandle fun ApplicationInfo.hasFlag(flag: Int): Boolean = (flags and flag) > 0 /** Checks whether the application is disabled until used. */ fun ApplicationInfo.isDisabledUntilUsed(): Boolean = enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED val ApplicationInfo.isDisabledUntilUsed: Boolean get() = enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED /** Converts to the route string which used in navigation. */ fun ApplicationInfo.toRoute() = "$packageName/$userId"