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

Commit d2269780 authored by Fabián Kozynski's avatar Fabián Kozynski
Browse files

[Flexiglass] Support media in landscape QQS

Tracks media presence using MediaCarouselInteractor (requires media
refactor flag). And changes the number of columns and rows in QS
accordingly.

For now, this only works to put media next to QQS in landscape-long. For
QS, it makes the grid 2x2 but media is still below. This will be
addressed in a follow-up.

Test: manual
Test: atest com.android.systemui.qs
Bug: 335826262
Flag: com.android.systemui.scene_container
Change-Id: Ica8c048f48395cfd05f559b52adae8cb5299bf33
parent 13de324b
Loading
Loading
Loading
Loading
+37 −13
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.clipScrollableContainer
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -42,6 +43,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -67,6 +69,7 @@ import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.animateSceneFloatAsState
import com.android.compose.modifiers.padding
import com.android.compose.modifiers.thenIf
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
@@ -235,6 +238,10 @@ private fun SceneScope.SingleShade(
    val shouldPunchHoleBehindScrim =
        layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade) ||
            layoutState.isTransitioningBetween(Scenes.Lockscreen, Scenes.Shade)
    // Media is visible and we are in landscape on a small height screen
    val mediaInRow =
        isMediaVisible &&
            LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact

    Box(
        modifier =
@@ -274,7 +281,12 @@ private fun SceneScope.SingleShade(
                                createBatteryMeterViewController = createBatteryMeterViewController,
                                statusBarIconController = statusBarIconController,
                            )
                            Box(Modifier.element(QuickSettings.Elements.QuickQuickSettings)) {

                            val content: @Composable (Modifier) -> Unit = { modifier ->
                                Box(
                                    Modifier.element(QuickSettings.Elements.QuickQuickSettings)
                                        .then(modifier)
                                ) {
                                    QuickSettings(
                                        viewModel.qsSceneAdapter,
                                        { viewModel.qsSceneAdapter.qqsHeight },
@@ -286,10 +298,22 @@ private fun SceneScope.SingleShade(
                                MediaCarousel(
                                    isVisible = isMediaVisible,
                                    mediaHost = mediaHost,
                                modifier = Modifier.fillMaxWidth(),
                                    modifier = Modifier.fillMaxWidth().then(modifier),
                                    carouselController = mediaCarouselController,
                                )
                            }

                            if (!mediaInRow) {
                                content(Modifier)
                            } else {
                                Row(
                                    modifier = Modifier.fillMaxWidth(),
                                    horizontalArrangement = spacedBy(16.dp),
                                    verticalAlignment = Alignment.CenterVertically,
                                ) {
                                    content(Modifier.weight(1f))
                                }
                            }
                            Spacer(modifier = Modifier.height(16.dp))
                        }
                    },
+10 −0
Original line number Diff line number Diff line
@@ -484,6 +484,11 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
        return changed;
    }

    @Override
    public int getMinRows() {
        return mMinRows;
    }

    @Override
    public boolean setMaxColumns(int maxColumns) {
        mMaxColumns = maxColumns;
@@ -497,6 +502,11 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
        return changed;
    }

    @Override
    public int getMaxColumns() {
        return mMaxColumns;
    }

    /**
     * Set the amount of excess space that we gave this view compared to the actual available
     * height. This is because this view is in a scrollview.
+12 −3
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import com.android.internal.widget.RemeasuringLinearLayout;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -441,7 +442,7 @@ public class QSPanel extends LinearLayout implements Tunable {
    }

    private boolean needsDynamicRowsAndColumns() {
        return true;
        return !SceneContainerFlag.isEnabled();
    }

    private void switchAllContentToParent(ViewGroup parent, QSTileLayout newLayout) {
@@ -634,8 +635,7 @@ public class QSPanel extends LinearLayout implements Tunable {
            switchAllContentToParent(newParent, mTileLayout);
            reAttachMediaHost(mediaHostView, horizontal);
            if (needsDynamicRowsAndColumns()) {
                mTileLayout.setMinRows(horizontal ? 2 : 1);
                mTileLayout.setMaxColumns(horizontal ? 2 : 4);
                setColumnRowLayout(horizontal);
            }
            updateMargins(mediaHostView);
            if (mHorizontalLinearLayout != null) {
@@ -644,6 +644,11 @@ public class QSPanel extends LinearLayout implements Tunable {
        }
    }

    void setColumnRowLayout(boolean withMedia) {
        mTileLayout.setMinRows(withMedia ? 2 : 1);
        mTileLayout.setMaxColumns(withMedia ? 2 : 4);
    }

    private void updateMargins(ViewGroup mediaHostView) {
        updateMediaHostContentMargins(mediaHostView);
        updateHorizontalLinearLayoutMargins();
@@ -736,6 +741,8 @@ public class QSPanel extends LinearLayout implements Tunable {
            return false;
        }

        int getMinRows();

        /**
         * Sets the max number of columns to show
         *
@@ -747,6 +754,8 @@ public class QSPanel extends LinearLayout implements Tunable {
            return false;
        }

        int getMaxColumns();

        /**
         * Sets the expansion value and proposedTranslation to panel.
         */
+14 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.haptics.qs.QSLongPressEffect;
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor;
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager;
import com.android.systemui.media.controls.ui.view.MediaHost;
import com.android.systemui.media.controls.ui.view.MediaHostState;
@@ -46,10 +47,13 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.SplitShadeStateController;
import com.android.systemui.tuner.TunerService;

import kotlinx.coroutines.flow.StateFlow;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;


/**
 * Controller for {@link QSPanel}.
 */
@@ -72,6 +76,8 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
    private final BrightnessSliderController.Factory mBrightnessSliderControllerFactory;
    private final BrightnessController.Factory mBrightnessControllerFactory;

    protected final MediaCarouselInteractor mMediaCarouselInteractor;

    private View.OnTouchListener mTileLayoutTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
@@ -94,7 +100,8 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
            FalsingManager falsingManager,
            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
            SplitShadeStateController splitShadeStateController,
            Provider<QSLongPressEffect> longPRessEffectProvider) {
            Provider<QSLongPressEffect> longPRessEffectProvider,
            MediaCarouselInteractor mediaCarouselInteractor) {
        super(view, qsHost, qsCustomizerController, usingMediaPlayer, mediaHost,
                metricsLogger, uiEventLogger, qsLogger, dumpManager, splitShadeStateController,
                longPRessEffectProvider);
@@ -113,6 +120,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
        mLastDensity = view.getResources().getConfiguration().densityDpi;
        mSceneContainerEnabled = SceneContainerFlag.isEnabled();
        mMediaCarouselInteractor = mediaCarouselInteractor;
    }

    @Override
@@ -125,6 +133,11 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
        mBrightnessSliderController.init();
    }

    @Override
    StateFlow<Boolean> getMediaVisibleFlow() {
        return mMediaCarouselInteractor.getHasAnyMediaOrRecommendation();
    }

    @Override
    protected void onViewAttached() {
        super.onViewAttached();
+51 −2
Original line number Diff line number Diff line
@@ -41,13 +41,17 @@ import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileViewImpl;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.statusbar.policy.SplitShadeStateController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.animation.DisappearParameters;
import com.android.systemui.util.kotlin.JavaAdapterKt;

import kotlin.Unit;
import kotlin.jvm.functions.Function1;

import kotlinx.coroutines.flow.StateFlow;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
@@ -58,6 +62,7 @@ import java.util.stream.Collectors;

import javax.inject.Provider;


/**
 * Controller for QSPanel views.
 *
@@ -95,6 +100,13 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr

    private boolean mDestroyed = false;

    private boolean mMediaVisibleFromInteractor;

    private final Consumer<Boolean> mMediaOrRecommendationVisibleConsumer = mediaVisible -> {
        mMediaVisibleFromInteractor = mediaVisible;
        setLayoutForMediaInScene();
    };

    @VisibleForTesting
    protected final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
            new QSPanel.OnConfigurationChangedListener() {
@@ -117,7 +129,11 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
                        /* newScreenLayout= */ mLastScreenLayout,
                        /* containerName= */ mView.getDumpableTag());

                    if (SceneContainerFlag.isEnabled()) {
                        setLayoutForMediaInScene();
                    } else {
                        switchTileLayoutIfNeeded();
                    }
                    onConfigurationChanged();
                    if (previousSplitShadeState != mShouldUseSplitNotificationShade) {
                        onSplitShadeChanged(mShouldUseSplitNotificationShade);
@@ -175,6 +191,9 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
        mView.initialize(mQSLogger, mUsingMediaPlayer);
        mQSLogger.logAllTilesChangeListening(mView.isListening(), mView.getDumpableTag(), "");
        mHost.addCallback(mQSHostCallback);
        if (SceneContainerFlag.isEnabled()) {
            registerForMediaInteractorChanges();
        }
    }

    /**
@@ -209,17 +228,32 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
            mQsTileRevealController.setExpansion(mRevealExpansion);
        }

        if (!SceneContainerFlag.isEnabled()) {
            mMediaHost.addVisibilityChangeListener(mMediaHostVisibilityListener);
        }
        mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
        setTiles();
        mLastOrientation = getResources().getConfiguration().orientation;
        mLastScreenLayout = getResources().getConfiguration().screenLayout;
        mQSLogger.logOnViewAttached(mLastOrientation, mView.getDumpableTag());
        if (SceneContainerFlag.isEnabled()) {
            setLayoutForMediaInScene();
        }
        switchTileLayout(true);

        mDumpManager.registerDumpable(mView.getDumpableTag(), this);
    }

    private void registerForMediaInteractorChanges() {
        JavaAdapterKt.collectFlow(
                mView,
                getMediaVisibleFlow(),
                mMediaOrRecommendationVisibleConsumer
        );
    }

    abstract StateFlow<Boolean> getMediaVisibleFlow();

    @Override
    protected void onViewDetached() {
        mQSLogger.logOnViewDetached(mLastOrientation, mView.getDumpableTag());
@@ -436,6 +470,11 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
        return false;
    }

    void setLayoutForMediaInScene() {
        boolean withMedia = shouldUseHorizontalInScene();
        mView.setColumnRowLayout(withMedia);
    }

    /**
     * Update the way the media disappears based on if we're using the horizontal layout
     */
@@ -476,6 +515,16 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
                == Configuration.SCREENLAYOUT_LONG_YES;
    }

    boolean shouldUseHorizontalInScene() {
        if (mShouldUseSplitNotificationShade) {
            return false;
        }
        return mMediaVisibleFromInteractor
                && mLastOrientation == Configuration.ORIENTATION_LANDSCAPE
                && (mLastScreenLayout & Configuration.SCREENLAYOUT_LONG_MASK)
                == Configuration.SCREENLAYOUT_LONG_YES;
    }

    private void logTiles() {
        for (int i = 0; i < mRecords.size(); i++) {
            QSTile tile = mRecords.get(i).tile;
Loading