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

Commit c4a44e33 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Set the footer actions visibility outside of the ViewModel (1/2)

This CL removes FooterActionsViewModel.isVisible and sets the footer
actions view visibility directly in QsImpl, like most other QS views.
This avoids flickers caused by delayed collection of the previous
isVisible flow.

Bug: 302118830
Test: Manual, using steps from b/302118830#comment1
Change-Id: I4b678427eeb59de279703025f2fd3c78720dac9f
parent 69c57d24
Loading
Loading
Loading
Loading
+2 −9
Original line number Diff line number Diff line
@@ -46,7 +46,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.layout
@@ -69,7 +68,6 @@ import com.android.compose.animation.Expandable
import com.android.compose.modifiers.background
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.compose.theme.colorAttr
import com.android.systemui.res.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
@@ -78,6 +76,7 @@ import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsForegroundServicesButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsSecurityButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.res.R
import kotlinx.coroutines.launch

/** The Quick Settings footer actions row. */
@@ -89,8 +88,7 @@ fun FooterActions(
) {
    val context = LocalContext.current

    // Collect visibility and alphas as soon as we are composed, even when not visible.
    val isVisible by viewModel.isVisible.collectAsState()
    // Collect alphas as soon as we are composed, even when not visible.
    val alpha by viewModel.alpha.collectAsState()
    val backgroundAlpha = viewModel.backgroundAlpha.collectAsState()

@@ -142,11 +140,6 @@ fun FooterActions(
        modifier
            .fillMaxWidth()
            .graphicsLayer { this.alpha = alpha }
            .drawWithContent {
                if (isVisible) {
                    drawContent()
                }
            }
            .then(backgroundModifier)
            .padding(
                top = dimensionResource(R.dimen.qs_footer_actions_top_padding),
+5 −2
Original line number Diff line number Diff line
@@ -170,6 +170,7 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl
    private CommandQueue mCommandQueue;

    private View mRootView;
    private View mFooterActionsView;

    @Inject
    public QSImpl(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
@@ -285,6 +286,7 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl
        if (!mFeatureFlags.isEnabled(Flags.COMPOSE_QS_FOOTER_ACTIONS)
                || !ComposeFacade.INSTANCE.isComposeAvailable()) {
            Log.d(TAG, "Binding the View implementation of the QS footer actions");
            mFooterActionsView = footerActionsView;
            mFooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
                    mListeningAndVisibilityLifecycleOwner);
            return;
@@ -294,6 +296,7 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl
        Log.d(TAG, "Binding the Compose implementation of the QS footer actions");
        View composeView = ComposeFacade.INSTANCE.createFooterActionsView(root.getContext(),
                mQSFooterActionsViewModel, mListeningAndVisibilityLifecycleOwner);
        mFooterActionsView = composeView;

        // The id R.id.qs_footer_actions is used by QSContainerImpl to set the horizontal margin
        // to all views except for qs_footer_actions, so we set it to the Compose view.
@@ -472,7 +475,7 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl
        boolean footerVisible = qsPanelVisible && (mQsExpanded || !keyguardShowing
                || mHeaderAnimating || mShowCollapsedOnKeyguard);
        mFooter.setVisibility(footerVisible ? View.VISIBLE : View.INVISIBLE);
        mQSFooterActionsViewModel.onVisibilityChangeRequested(footerVisible);
        mFooterActionsView.setVisibility(footerVisible ? View.VISIBLE : View.INVISIBLE);
        mFooter.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
                || (mQsExpanded && !mStackScrollerOverscrolling));
        mQSPanelController.setVisibility(qsPanelVisible ? View.VISIBLE : View.INVISIBLE);
@@ -856,7 +859,7 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl
        boolean customizing = isCustomizing();
        mQSPanelScrollView.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
        mFooter.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
        mQSFooterActionsViewModel.onVisibilityChangeRequested(!customizing);
        mFooterActionsView.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
        mHeader.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
        // Let the panel know the position changed and it needs to update where notifications
        // and whatnot are.
+2 −12
Original line number Diff line number Diff line
@@ -24,13 +24,11 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.res.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.dagger.SysUISingleton
@@ -40,6 +38,7 @@ import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsForegroundServicesButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsSecurityButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.res.R
import javax.inject.Inject
import kotlin.math.roundToInt
import kotlinx.coroutines.launch
@@ -98,10 +97,6 @@ class FooterActionsViewBinder @Inject constructor() {
        var previousForegroundServices: FooterActionsForegroundServicesButtonViewModel? = null
        var previousUserSwitcher: FooterActionsButtonViewModel? = null

        // Set the initial visibility on the View directly so that we don't briefly show it for a
        // few frames before [viewModel.isVisible] is collected.
        view.isInvisible = !viewModel.isVisible.value

        // Listen for ViewModel updates when the View is attached.
        view.repeatWhenAttached {
            val attachedScope = this.lifecycleScope
@@ -111,12 +106,7 @@ class FooterActionsViewBinder @Inject constructor() {
                // TODO(b/242040009): Should this move somewhere else?
                launch { viewModel.observeDeviceMonitoringDialogRequests(view.context) }

                // Make sure we set the correct visibility and alpha even when QS are not currently
                // shown.
                launch {
                    viewModel.isVisible.collect { isVisible -> view.isInvisible = !isVisible }
                }

                // Make sure we set the correct alphas even when QS are not currently shown.
                launch { viewModel.alpha.collect { view.alpha = it } }
                launch {
                    viewModel.backgroundAlpha.collect {
+0 −12
Original line number Diff line number Diff line
@@ -77,14 +77,6 @@ class FooterActionsViewModel(
     */
    val observeDeviceMonitoringDialogRequests: suspend (quickSettingsContext: Context) -> Unit,
) {
    /**
     * Whether the UI rendering this ViewModel should be visible. Note that even when this is false,
     * the UI should still participate to the layout it is included in (i.e. in the View world it
     * should be INVISIBLE, not GONE).
     */
    private val _isVisible = MutableStateFlow(false)
    val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()

    /** The alpha the UI rendering this ViewModel should have. */
    private val _alpha = MutableStateFlow(1f)
    val alpha: StateFlow<Float> = _alpha.asStateFlow()
@@ -93,10 +85,6 @@ class FooterActionsViewModel(
    private val _backgroundAlpha = MutableStateFlow(1f)
    val backgroundAlpha: StateFlow<Float> = _backgroundAlpha.asStateFlow()

    fun onVisibilityChangeRequested(visible: Boolean) {
        _isVisible.value = visible
    }

    /** Called when the expansion of the Quick Settings changed. */
    fun onQuickSettingsExpansionChanged(expansion: Float, isInSplitShade: Boolean) {
        if (isInSplitShade) {
+0 −12
Original line number Diff line number Diff line
@@ -372,18 +372,6 @@ class FooterActionsViewModelTest : SysuiTestCase() {
        job.cancel()
    }

    @Test
    fun isVisible() {
        val underTest = utils.footerActionsViewModel()
        assertThat(underTest.isVisible.value).isFalse()

        underTest.onVisibilityChangeRequested(visible = true)
        assertThat(underTest.isVisible.value).isTrue()

        underTest.onVisibilityChangeRequested(visible = false)
        assertThat(underTest.isVisible.value).isFalse()
    }

    @Test
    fun alpha_inSplitShade_followsExpansion() {
        val underTest = utils.footerActionsViewModel()