From d6b7f549615285f8132a759a96bba809f65743ec Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Tue, 17 Jan 2023 15:18:57 +0800 Subject: [PATCH] Display cloned app under person tab in App List This is for the new SPA App List. Before this change, cloned app is displayed in separated tab, after this change, cloned app will displayed under person tab in App List. Fix: 266040895 Test: Manually with Settings Test: Unit test Change-Id: I0dd448c3a33815b9b63348381d97b2520e05ab27 --- .../DisposableBroadcastReceiverAsUser.kt | 2 - .../model/app/AppListRepository.kt | 51 ++++----- .../model/app/AppListViewModel.kt | 104 ++++++++++++------ .../spaprivileged/template/app/AppList.kt | 38 ++++--- .../spaprivileged/template/app/AppListPage.kt | 7 +- .../template/common/UserProfilePager.kt | 78 +++++++++++++ .../template/common/WorkProfilePager.kt | 50 --------- .../DisposableBroadcastReceiverAsUserTest.kt | 17 --- .../model/app/AppListRepositoryTest.kt | 34 +++--- .../model/app/AppListViewModelTest.kt | 10 +- .../spaprivileged/template/app/AppListTest.kt | 3 +- 11 files changed, 220 insertions(+), 174 deletions(-) create mode 100644 packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt delete mode 100644 packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt 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(),