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

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

Merge "Fix flicker of AppButtons"

parents 6e5b8e47 d70dbe40
Loading
Loading
Loading
Loading
+4 −15
Original line number Diff line number Diff line
@@ -21,23 +21,21 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import com.android.settingslib.applications.AppUtils
import com.android.settingslib.spa.framework.compose.collectAsStateWithLifecycle
import com.android.settingslib.spa.widget.button.ActionButton
import com.android.settingslib.spa.widget.button.ActionButtons
import com.android.settingslib.spaprivileged.model.app.isSystemModule
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext

@Composable
fun AppButtons(packageInfoPresenter: PackageInfoPresenter) {
    if (remember(packageInfoPresenter) { packageInfoPresenter.isMainlineModule() }) return
    val presenter = remember { AppButtonsPresenter(packageInfoPresenter) }
    if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
    presenter.Dialogs()
    ActionButtons(actionButtons = presenter.rememberActionsButtons().value)
}

private fun PackageInfoPresenter.isMainlineModule(): Boolean =
    AppUtils.isMainlineModule(userPackageManager, packageName)

private class AppButtonsPresenter(private val packageInfoPresenter: PackageInfoPresenter) {
    private val appLaunchButton = AppLaunchButton(packageInfoPresenter)
    private val appInstallButton = AppInstallButton(packageInfoPresenter)
@@ -46,15 +44,6 @@ private class AppButtonsPresenter(private val packageInfoPresenter: PackageInfoP
    private val appClearButton = AppClearButton(packageInfoPresenter)
    private val appForceStopButton = AppForceStopButton(packageInfoPresenter)

    val isAvailableFlow = flow { emit(isAvailable()) }

    private suspend fun isAvailable(): Boolean = withContext(Dispatchers.IO) {
        !packageInfoPresenter.userPackageManager.isSystemModule(packageInfoPresenter.packageName) &&
            !AppUtils.isMainlineModule(
                packageInfoPresenter.userPackageManager, packageInfoPresenter.packageName
            )
    }

    @Composable
    fun rememberActionsButtons() = remember {
        packageInfoPresenter.flow.map { packageInfo ->
+1 −3
Original line number Diff line number Diff line
@@ -148,9 +148,7 @@ class PackageInfoPresenter(
    private fun getPackageInfo() =
        PackageManagers.getPackageInfoAsUser(
            packageName = packageName,
            flags = PackageManager.MATCH_DISABLED_COMPONENTS or
                PackageManager.GET_SIGNATURES or
                PackageManager.GET_PERMISSIONS,
            flags = PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.GET_PERMISSIONS,
            userId = userId,
        )
}
+2 −23
Original line number Diff line number Diff line
@@ -18,12 +18,8 @@ package com.android.settings.spa.app.appinfo

import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.ModuleInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.NameNotFoundException
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
@@ -33,16 +29,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settingslib.applications.AppUtils
import com.android.settingslib.spa.testutils.delay
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.doThrow
import org.mockito.MockitoSession
import org.mockito.Spy
import org.mockito.quality.Strictness
@@ -74,7 +67,6 @@ class AppButtonsTest {
        whenever(packageInfoPresenter.context).thenReturn(context)
        whenever(packageInfoPresenter.packageName).thenReturn(PACKAGE_NAME)
        whenever(packageInfoPresenter.userPackageManager).thenReturn(packageManager)
        doThrow(NameNotFoundException()).`when`(packageManager).getModuleInfo(PACKAGE_NAME, 0)
        whenever(packageManager.getPackageInfo(PACKAGE_NAME, 0)).thenReturn(PACKAGE_INFO)
        whenever(AppUtils.isMainlineModule(packageManager, PACKAGE_NAME)).thenReturn(false)
    }
@@ -84,15 +76,6 @@ class AppButtonsTest {
        mockSession.finishMocking()
    }

    @Test
    fun isSystemModule_notDisplayed() {
        doReturn(ModuleInfo()).`when`(packageManager).getModuleInfo(PACKAGE_NAME, 0)

        setContent()

        composeTestRule.onRoot().assertIsNotDisplayed()
    }

    @Test
    fun isMainlineModule_notDisplayed() {
        whenever(AppUtils.isMainlineModule(packageManager, PACKAGE_NAME)).thenReturn(true)
@@ -110,12 +93,8 @@ class AppButtonsTest {
    }

    private fun setContent() {
        whenever(packageInfoPresenter.flow).thenReturn(MutableStateFlow(PACKAGE_INFO))
        composeTestRule.setContent {
            val scope = rememberCoroutineScope()
            LaunchedEffect(Unit) {
                whenever(packageInfoPresenter.flow).thenReturn(flowOf(PACKAGE_INFO).stateIn(scope))
            }

            AppButtons(packageInfoPresenter)
        }