Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 29ddeab3 authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Add showInstantApps to AppListPage"

parents 0cb7161d dcfda409
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2,6 +2,9 @@
  "presubmit": [
    {
      "name": "SpaLibTests"
    },
    {
      "name": "SpaPrivilegedLibTests"
    }
  ]
}
+6 −0
Original line number Diff line number Diff line
@@ -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"],
}
+27 −16
Original line number Diff line number Diff line
@@ -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
@@ -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)
@@ -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)
            }
        }
    }
@@ -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,
@@ -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
        }
    }
+9 −9
Original line number Diff line number Diff line
@@ -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
@@ -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) }
            }
+2 −2
Original line number Diff line number Diff line
@@ -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