diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt index a2fb101e4e4cc..3b9bf47671c9b 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt @@ -33,7 +33,6 @@ import com.android.settingslib.spa.framework.compose.LifecycleEffect fun DisposableBroadcastReceiverAsUser( intentFilter: IntentFilter, userHandle: UserHandle, - onStart: () -> Unit = {}, onReceive: (Intent) -> Unit, ) { val context = LocalContext.current @@ -49,7 +48,6 @@ fun DisposableBroadcastReceiverAsUser( context.registerReceiverAsUser( broadcastReceiver, userHandle, intentFilter, null, null ) - onStart() }, onStop = { context.unregisterReceiver(broadcastReceiver) diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt index ce0c5511c3d0e..5342def0003d4 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt @@ -28,20 +28,12 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.runBlocking -/** - * The config used to load the App List. - */ -data class AppListConfig( - val userId: Int, - val showInstantApps: Boolean, -) - /** * The repository to load the App List data. */ internal interface AppListRepository { /** Loads the list of [ApplicationInfo]. */ - suspend fun loadApps(config: AppListConfig): List + suspend fun loadApps(userId: Int, showInstantApps: Boolean): List /** Gets the flow of predicate that could used to filter system app. */ fun showSystemPredicate( @@ -50,7 +42,7 @@ internal interface AppListRepository { ): Flow<(app: ApplicationInfo) -> Boolean> /** Gets the system app package names. */ - fun getSystemPackageNamesBlocking(config: AppListConfig): Set + fun getSystemPackageNamesBlocking(userId: Int, showInstantApps: Boolean): Set } /** @@ -59,15 +51,21 @@ internal interface AppListRepository { object AppListRepositoryUtil { /** Gets the system app package names. */ @JvmStatic - fun getSystemPackageNames(context: Context, config: AppListConfig): Set { - return AppListRepositoryImpl(context).getSystemPackageNamesBlocking(config) - } + fun getSystemPackageNames( + context: Context, + userId: Int, + showInstantApps: Boolean, + ): Set = + AppListRepositoryImpl(context).getSystemPackageNamesBlocking(userId, showInstantApps) } internal class AppListRepositoryImpl(private val context: Context) : AppListRepository { private val packageManager = context.packageManager - override suspend fun loadApps(config: AppListConfig): List = coroutineScope { + override suspend fun loadApps( + userId: Int, + showInstantApps: Boolean, + ): List = coroutineScope { val hiddenSystemModulesDeferred = async { packageManager.getInstalledModules(0) .filter { it.isHidden } @@ -82,12 +80,12 @@ internal class AppListRepositoryImpl(private val context: Context) : AppListRepo PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong() ) val installedApplicationsAsUser = - packageManager.getInstalledApplicationsAsUser(flags, config.userId) + packageManager.getInstalledApplicationsAsUser(flags, userId) val hiddenSystemModules = hiddenSystemModulesDeferred.await() val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await() installedApplicationsAsUser.filter { app -> - app.isInAppList(config.showInstantApps, hiddenSystemModules, hideWhenDisabledPackages) + app.isInAppList(showInstantApps, hiddenSystemModules, hideWhenDisabledPackages) } } @@ -97,18 +95,17 @@ internal class AppListRepositoryImpl(private val context: Context) : AppListRepo ): Flow<(app: ApplicationInfo) -> Boolean> = userIdFlow.combine(showSystemFlow, ::showSystemPredicate) - override fun getSystemPackageNamesBlocking(config: AppListConfig) = runBlocking { - getSystemPackageNames(config) - } + override fun getSystemPackageNamesBlocking(userId: Int, showInstantApps: Boolean) = + runBlocking { getSystemPackageNames(userId, showInstantApps) } - private suspend fun getSystemPackageNames(config: AppListConfig): Set = - coroutineScope { - val loadAppsDeferred = async { loadApps(config) } - val homeOrLauncherPackages = loadHomeOrLauncherPackages(config.userId) - val showSystemPredicate = - { app: ApplicationInfo -> isSystemApp(app, homeOrLauncherPackages) } - loadAppsDeferred.await().filter(showSystemPredicate).map { it.packageName }.toSet() - } + private suspend fun getSystemPackageNames(userId: Int, showInstantApps: Boolean): Set = + coroutineScope { + val loadAppsDeferred = async { loadApps(userId, showInstantApps) } + val homeOrLauncherPackages = loadHomeOrLauncherPackages(userId) + val showSystemPredicate = + { app: ApplicationInfo -> isSystemApp(app, homeOrLauncherPackages) } + loadAppsDeferred.await().filter(showSystemPredicate).map { it.packageName }.toSet() + } private suspend fun showSystemPredicate( userId: Int, diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt index 6cd1c0d6a5ae3..889604209b08b 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt @@ -26,6 +26,7 @@ import com.android.settingslib.spa.framework.util.StateFlowBridge import com.android.settingslib.spa.framework.util.asyncMapItem import com.android.settingslib.spa.framework.util.waitFirst import com.android.settingslib.spa.widget.ui.SpinnerOption +import com.android.settingslib.spaprivileged.template.app.AppListConfig import java.util.concurrent.ConcurrentHashMap import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -34,8 +35,8 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.shareIn @@ -78,32 +79,77 @@ internal open class AppListViewModelImpl( private val labelMap = ConcurrentHashMap() private val scope = viewModelScope + Dispatchers.IO - private val userIdFlow = appListConfig.flow.map { it.userId } + private val userSubGraphsFlow = appListConfig.flow.map { config -> + config.userIds.map { userId -> UserSubGraph(userId, config.showInstantApps) } + }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) - private val appsStateFlow = MutableStateFlow?>(null) + private inner class UserSubGraph( + private val userId: Int, + private val showInstantApps: Boolean, + ) { + private val userIdFlow = flowOf(userId) - private val recordListFlow = listModel.flow - .flatMapLatest { it.transform(userIdFlow, appsStateFlow.filterNotNull()) } - .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) + private val appsStateFlow = MutableStateFlow?>(null) - private val systemFilteredFlow = - appListRepository.showSystemPredicate(userIdFlow, showSystem.flow) - .combine(recordListFlow) { showAppPredicate, recordList -> - recordList.filter { showAppPredicate(it.app) } + val recordListFlow = listModel.flow + .flatMapLatest { it.transform(userIdFlow, appsStateFlow.filterNotNull()) } + .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) + + private val systemFilteredFlow = + appListRepository.showSystemPredicate(userIdFlow, showSystem.flow) + .combine(recordListFlow) { showAppPredicate, recordList -> + recordList.filter { showAppPredicate(it.app) } + } + .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) + + val listModelFilteredFlow = optionFlow.filterNotNull().flatMapLatest { option -> + listModel.flow.flatMapLatest { listModel -> + listModel.filter(this.userIdFlow, option, this.systemFilteredFlow) } + }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) + + fun reloadApps() { + scope.launch { + appsStateFlow.value = appListRepository.loadApps(userId, showInstantApps) + } + } + } + + private val combinedRecordListFlow = userSubGraphsFlow.flatMapLatest { userSubGraphList -> + combine(userSubGraphList.map { it.recordListFlow }) { it.toList().flatten() } + }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) override val spinnerOptionsFlow = - recordListFlow.combine(listModel.flow) { recordList, listModel -> + combinedRecordListFlow.combine(listModel.flow) { recordList, listModel -> listModel.getSpinnerOptions(recordList) - } + }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) - override val appListDataFlow = optionFlow.filterNotNull().flatMapLatest(::filterAndSort) - .combine(searchQuery.flow) { appListData, searchQuery -> + private val appEntryListFlow = userSubGraphsFlow.flatMapLatest { userSubGraphList -> + combine(userSubGraphList.map { it.listModelFilteredFlow }) { it.toList().flatten() } + }.asyncMapItem { record -> + val label = getLabel(record.app) + AppEntry( + record = record, + label = label, + labelCollationKey = collator.getCollationKey(label), + ) + } + + override val appListDataFlow = + combine( + appEntryListFlow, + listModel.flow, + optionFlow.filterNotNull(), + ) { appEntries, listModel, option -> + AppListData( + appEntries = appEntries.sortedWith(listModel.getComparator(option)), + option = option, + ) + }.combine(searchQuery.flow) { appListData, searchQuery -> appListData.filter { it.label.contains(other = searchQuery, ignoreCase = true) } - } - .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) + }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) init { scheduleOnFirstLoaded() @@ -111,30 +157,16 @@ internal open class AppListViewModelImpl( fun reloadApps() { scope.launch { - appsStateFlow.value = appListRepository.loadApps(appListConfig.flow.first()) + userSubGraphsFlow.collect { userSubGraphList -> + for (userSubGraph in userSubGraphList) { + userSubGraph.reloadApps() + } + } } } - private fun filterAndSort(option: Int) = listModel.flow.flatMapLatest { listModel -> - listModel.filter(userIdFlow, option, systemFilteredFlow) - .asyncMapItem { record -> - val label = getLabel(record.app) - AppEntry( - record = record, - label = label, - labelCollationKey = collator.getCollationKey(label), - ) - } - .map { appEntries -> - AppListData( - appEntries = appEntries.sortedWith(listModel.getComparator(option)), - option = option, - ) - } - } - private fun scheduleOnFirstLoaded() { - recordListFlow + combinedRecordListFlow .waitFirst(appListDataFlow) .combine(listModel.flow) { recordList, listModel -> if (listModel.onFirstLoaded(recordList)) { diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt index 57a60e505553c..4a8c00e68433f 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp import androidx.lifecycle.viewmodel.compose.viewModel +import com.android.settingslib.spa.framework.compose.LifecycleEffect import com.android.settingslib.spa.framework.compose.LogCompositions import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll @@ -43,7 +44,6 @@ import com.android.settingslib.spa.widget.ui.SpinnerOption import com.android.settingslib.spaprivileged.R import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser import com.android.settingslib.spaprivileged.model.app.AppEntry -import com.android.settingslib.spaprivileged.model.app.AppListConfig import com.android.settingslib.spaprivileged.model.app.AppListData import com.android.settingslib.spaprivileged.model.app.AppListModel import com.android.settingslib.spaprivileged.model.app.AppListViewModel @@ -56,6 +56,14 @@ import kotlinx.coroutines.flow.MutableStateFlow private const val TAG = "AppList" private const val CONTENT_TYPE_HEADER = "header" +/** + * The config used to load the App List. + */ +data class AppListConfig( + val userIds: List, + val showInstantApps: Boolean, +) + data class AppListState( val showSystem: State, val searchQuery: State, @@ -84,7 +92,7 @@ fun AppListInput.AppList() { internal fun AppListInput.AppListImpl( viewModelSupplier: @Composable () -> IAppListViewModel, ) { - LogCompositions(TAG, config.userId.toString()) + LogCompositions(TAG, config.userIds.toString()) val viewModel = viewModelSupplier() Column(Modifier.fillMaxSize()) { val optionsState = viewModel.spinnerOptionsFlow.collectAsState(null, Dispatchers.IO) @@ -168,21 +176,23 @@ private fun rememberViewModel( listModel: AppListModel, state: AppListState, ): AppListViewModel { - val viewModel: AppListViewModel = viewModel(key = config.userId.toString()) + val viewModel: AppListViewModel = viewModel(key = config.userIds.toString()) viewModel.appListConfig.setIfAbsent(config) viewModel.listModel.setIfAbsent(listModel) viewModel.showSystem.Sync(state.showSystem) viewModel.searchQuery.Sync(state.searchQuery) - DisposableBroadcastReceiverAsUser( - intentFilter = IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply { - addAction(Intent.ACTION_PACKAGE_REMOVED) - addAction(Intent.ACTION_PACKAGE_CHANGED) - addDataScheme("package") - }, - userHandle = UserHandle.of(config.userId), - onStart = { viewModel.reloadApps() }, - ) { viewModel.reloadApps() } - + LifecycleEffect(onStart = { viewModel.reloadApps() }) + val intentFilter = IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply { + addAction(Intent.ACTION_PACKAGE_REMOVED) + addAction(Intent.ACTION_PACKAGE_CHANGED) + addDataScheme("package") + } + for (userId in config.userIds) { + DisposableBroadcastReceiverAsUser( + intentFilter = intentFilter, + userHandle = UserHandle.of(userId), + ) { viewModel.reloadApps() } + } return viewModel -} \ No newline at end of file +} diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt index 404e27ccb79ad..2ebbe8aab809e 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt @@ -24,10 +24,9 @@ import com.android.settingslib.spa.widget.scaffold.MoreOptionsAction import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope import com.android.settingslib.spa.widget.scaffold.SearchScaffold import com.android.settingslib.spaprivileged.R -import com.android.settingslib.spaprivileged.model.app.AppListConfig import com.android.settingslib.spaprivileged.model.app.AppListModel import com.android.settingslib.spaprivileged.model.app.AppRecord -import com.android.settingslib.spaprivileged.template.common.WorkProfilePager +import com.android.settingslib.spaprivileged.template.common.UserProfilePager /** * The full screen template for an App List page. @@ -55,10 +54,10 @@ fun AppListPage( } }, ) { bottomPadding, searchQuery -> - WorkProfilePager(primaryUserOnly) { userInfo -> + UserProfilePager(primaryUserOnly) { userGroup -> val appListInput = AppListInput( config = AppListConfig( - userId = userInfo.id, + userIds = userGroup.userInfos.map { it.id }, showInstantApps = showInstantApps, ), listModel = listModel, diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt new file mode 100644 index 0000000000000..b5a4929c47f43 --- /dev/null +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.spaprivileged.template.common + +import android.content.pm.UserInfo +import android.content.pm.UserProperties +import android.os.UserHandle +import android.os.UserManager +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import com.android.settingslib.spa.widget.scaffold.SettingsPager +import com.android.settingslib.spaprivileged.framework.common.userManager +import com.android.settingslib.spaprivileged.model.enterprise.EnterpriseRepository + +/** + * Info about how to group multiple profiles for Settings. + * + * @see [UserProperties.ShowInSettings] + */ +data class UserGroup( + /** The users in this user group, if multiple users, the first one is parent user. */ + val userInfos: List, +) + +@Composable +fun UserProfilePager( + primaryUserOnly: Boolean = false, + content: @Composable (userGroup: UserGroup) -> Unit, +) { + val context = LocalContext.current + val userGroups = remember { + context.userManager.getUserGroups(primaryUserOnly) + } + val titles = remember { + val enterpriseRepository = EnterpriseRepository(context) + userGroups.map { userGroup -> + enterpriseRepository.getProfileTitle( + isManagedProfile = userGroup.userInfos.first().isManagedProfile, + ) + } + } + + SettingsPager(titles) { page -> + content(userGroups[page]) + } +} + +private fun UserManager.getUserGroups(primaryUserOnly: Boolean): List { + val userGroupList = mutableListOf() + val profileToShowInSettingsList = getProfiles(UserHandle.myUserId()) + .filter { userInfo -> !primaryUserOnly || userInfo.isPrimary } + .map { userInfo -> userInfo to getUserProperties(userInfo.userHandle).showInSettings } + + profileToShowInSettingsList.filter { it.second == UserProperties.SHOW_IN_SETTINGS_WITH_PARENT } + .takeIf { it.isNotEmpty() } + ?.map { it.first } + ?.let { userInfos -> userGroupList += UserGroup(userInfos) } + + profileToShowInSettingsList.filter { it.second == UserProperties.SHOW_IN_LAUNCHER_SEPARATE } + .forEach { userGroupList += UserGroup(userInfos = listOf(it.first)) } + + return userGroupList +} diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt deleted file mode 100644 index a76c4385b69ed..0000000000000 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settingslib.spaprivileged.template.common - -import android.content.pm.UserInfo -import android.os.UserHandle -import android.os.UserManager -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext -import com.android.settingslib.spa.widget.scaffold.SettingsPager -import com.android.settingslib.spaprivileged.model.enterprise.EnterpriseRepository - -@Composable -fun WorkProfilePager( - primaryUserOnly: Boolean = false, - content: @Composable (userInfo: UserInfo) -> Unit, -) { - val context = LocalContext.current - val profiles = remember { - val userManager = checkNotNull(context.getSystemService(UserManager::class.java)) - userManager.getProfiles(UserHandle.myUserId()).filter { userInfo -> - !primaryUserOnly || userInfo.isPrimary - } - } - val titles = remember { - val enterpriseRepository = EnterpriseRepository(context) - profiles.map { - enterpriseRepository.getProfileTitle(isManagedProfile = it.isManagedProfile) - } - } - - SettingsPager(titles) { page -> - content(profiles[page]) - } -} diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt index 01f4cc67de835..9bd92423f9d2a 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt @@ -85,23 +85,6 @@ class DisposableBroadcastReceiverAsUserTest { assertThat(onReceiveIsCalled).isTrue() } - @Test - fun broadcastReceiver_onStartIsCalled() { - var onStartIsCalled = false - composeTestRule.setContent { - CompositionLocalProvider(LocalContext provides context) { - DisposableBroadcastReceiverAsUser( - intentFilter = IntentFilter(), - userHandle = USER_HANDLE, - onStart = { onStartIsCalled = true }, - onReceive = {}, - ) - } - } - - assertThat(onStartIsCalled).isTrue() - } - private companion object { val USER_HANDLE: UserHandle = UserHandle.of(0) } diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt index b0ea40a49a0ee..57972edc6d3a5 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt @@ -83,9 +83,8 @@ class AppListRepositoryTest { @Test fun loadApps_notShowInstantApps() = runTest { mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP)) - val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) - val appListFlow = repository.loadApps(appListConfig) + val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) assertThat(appListFlow).containsExactly(NORMAL_APP) } @@ -93,9 +92,8 @@ class AppListRepositoryTest { @Test fun loadApps_showInstantApps() = runTest { mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP)) - val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = true) - val appListFlow = repository.loadApps(appListConfig) + val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = true) assertThat(appListFlow).containsExactly(NORMAL_APP, INSTANT_APP) } @@ -109,9 +107,8 @@ class AppListRepositoryTest { whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)) .thenReturn(arrayOf(app.packageName)) mockInstalledApplications(listOf(app)) - val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) - val appListFlow = repository.loadApps(appListConfig) + val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) assertThat(appListFlow).isEmpty() } @@ -126,9 +123,8 @@ class AppListRepositoryTest { whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)) .thenReturn(arrayOf(app.packageName)) mockInstalledApplications(listOf(app)) - val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) - val appListFlow = repository.loadApps(appListConfig) + val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) assertThat(appListFlow).isEmpty() } @@ -142,9 +138,8 @@ class AppListRepositoryTest { whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)) .thenReturn(arrayOf(app.packageName)) mockInstalledApplications(listOf(app)) - val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) - val appListFlow = repository.loadApps(appListConfig) + val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) assertThat(appListFlow).containsExactly(app) } @@ -157,9 +152,8 @@ class AppListRepositoryTest { enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER } mockInstalledApplications(listOf(app)) - val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) - val appListFlow = repository.loadApps(appListConfig) + val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) assertThat(appListFlow).containsExactly(app) } @@ -171,9 +165,8 @@ class AppListRepositoryTest { enabled = false } mockInstalledApplications(listOf(app)) - val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) - val appListFlow = repository.loadApps(appListConfig) + val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) assertThat(appListFlow).isEmpty() } @@ -223,7 +216,7 @@ class AppListRepositoryTest { @Test fun showSystemPredicate_appInLauncher() = runTest { - val app = IN_LAUMCHER_APP + val app = IN_LAUNCHER_APP whenever( packageManager.queryIntentActivitiesAsUser(any(), any(), eq(USER_ID)) @@ -237,10 +230,13 @@ class AppListRepositoryTest { @Test fun getSystemPackageNames_returnExpectedValues() = runTest { mockInstalledApplications(listOf( - NORMAL_APP, INSTANT_APP, SYSTEM_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUMCHER_APP)) - val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) + NORMAL_APP, INSTANT_APP, SYSTEM_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUNCHER_APP)) - val systemPackageNames = AppListRepositoryUtil.getSystemPackageNames(context, appListConfig) + val systemPackageNames = AppListRepositoryUtil.getSystemPackageNames( + context = context, + userId = USER_ID, + showInstantApps = false, + ) assertThat(systemPackageNames).containsExactly("system.app", "home.app", "app.in.launcher") } @@ -280,7 +276,7 @@ class AppListRepositoryTest { flags = ApplicationInfo.FLAG_SYSTEM } - val IN_LAUMCHER_APP = ApplicationInfo().apply { + val IN_LAUNCHER_APP = ApplicationInfo().apply { packageName = "app.in.launcher" flags = ApplicationInfo.FLAG_SYSTEM } diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt index b1d02f57c8d7a..fc40aed43c92c 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt @@ -23,6 +23,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spa.framework.compose.stateOf import com.android.settingslib.spa.framework.util.mapItem import com.android.settingslib.spa.testutils.waitUntil +import com.android.settingslib.spaprivileged.template.app.AppListConfig import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow @@ -84,14 +85,17 @@ class AppListViewModelTest { } private object FakeAppListRepository : AppListRepository { - override suspend fun loadApps(config: AppListConfig) = listOf(APP) + override suspend fun loadApps(userId: Int, showInstantApps: Boolean) = listOf(APP) override fun showSystemPredicate( userIdFlow: Flow, showSystemFlow: Flow, ): Flow<(app: ApplicationInfo) -> Boolean> = flowOf { true } - override fun getSystemPackageNamesBlocking(config: AppListConfig): Set = setOf() + override fun getSystemPackageNamesBlocking( + userId: Int, + showInstantApps: Boolean, + ): Set = emptySet() } private object FakeAppRepository : AppRepository { @@ -105,7 +109,7 @@ class AppListViewModelTest { const val USER_ID = 0 const val PACKAGE_NAME = "package.name" const val LABEL = "Label" - val CONFIG = AppListConfig(userId = USER_ID, showInstantApps = false) + val CONFIG = AppListConfig(userIds = listOf(USER_ID), showInstantApps = false) val APP = ApplicationInfo().apply { packageName = PACKAGE_NAME } diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt index d5c7c191d3ffb..a99d02de0df06 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt @@ -32,7 +32,6 @@ import com.android.settingslib.spa.framework.compose.toState import com.android.settingslib.spa.widget.ui.SpinnerOption import com.android.settingslib.spaprivileged.R import com.android.settingslib.spaprivileged.model.app.AppEntry -import com.android.settingslib.spaprivileged.model.app.AppListConfig import com.android.settingslib.spaprivileged.model.app.AppListData import com.android.settingslib.spaprivileged.model.app.IAppListViewModel import com.android.settingslib.spaprivileged.tests.testutils.TestAppListModel @@ -115,7 +114,7 @@ class AppListTest { ) { composeTestRule.setContent { AppListInput( - config = AppListConfig(userId = USER_ID, showInstantApps = false), + config = AppListConfig(userIds = listOf(USER_ID), showInstantApps = false), listModel = TestAppListModel(enableGrouping = enableGrouping), state = AppListState( showSystem = false.toState(),