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

Commit 5d49cc79 authored by amehfooz's avatar amehfooz
Browse files

[ROSP] Add media carousel location for status bar popup

This change introduces a new location for the media carousel,
specifically within a status bar popup. This popup is displayed when the
media controls chip is clicked.

Key changes include:
- Added `LOCATION_STATUS_BAR_POPUP` to `MediaHierarchyManager` to represent the new location.
- Modified `MediaHierarchyManager` to handle the new location and update the desired location accordingly.
- Created a new `MediaControlPopup` composable to display the media carousel within the popup.
- Added a new `MediaHost` for the popup location.

Bug: b/385202114
Flag: com.android.systemui.status_bar_popup_chips

Test: Make sure media carousel shows up when chip is clicked.
Screenshot provided in b/385202114 comment#2
Test: Make sure the carousel moves to the other locations as expected

Change-Id: I383708af32e335a8ce9c91ef815e4f07030847d1
parent 9c2ce8fd
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.CrossFadeHelper
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -229,7 +230,7 @@ constructor(
        else result.setIntersect(animationStartClipping, targetClipping)
    }

    private val mediaHosts = arrayOfNulls<MediaHost>(LOCATION_COMMUNAL_HUB + 1)
    private val mediaHosts = arrayOfNulls<MediaHost>(LOCATION_STATUS_BAR_POPUP + 1)

    /**
     * The last location where this view was at before going to the desired location. This is useful
@@ -374,6 +375,15 @@ constructor(
            }
        }

    /** Is the Media Control StatusBarPopup showing */
    var isMediaControlPopupShowing: Boolean = false
        set(value) {
            if (field != value && StatusBarPopupChips.isEnabled) {
                field = value
                updateDesiredLocation(forceNoAnimation = true)
            }
        }

    /** Are location changes currently blocked? */
    private val blockLocationChanges: Boolean
        get() {
@@ -1225,6 +1235,7 @@ constructor(
            // Keep the current location until we're allowed to again
            return desiredLocation
        }

        val onLockscreen =
            (!bypassController.bypassEnabled && (statusbarState == StatusBarState.KEYGUARD))

@@ -1234,6 +1245,8 @@ constructor(
            (onCommunalNotDreaming && qsExpansion == 0.0f) || onCommunalDreamingAndShadeExpanding
        val location =
            when {
                isMediaControlPopupShowing && StatusBarPopupChips.isEnabled ->
                    LOCATION_STATUS_BAR_POPUP
                dreamOverlayActive && dreamMediaComplicationActive -> LOCATION_DREAM_OVERLAY
                onCommunal -> LOCATION_COMMUNAL_HUB
                (qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
@@ -1377,6 +1390,9 @@ constructor(
        /** Attached to a view in the communal UI grid */
        const val LOCATION_COMMUNAL_HUB = 4

        /** Attached to a popup that is shown with a media control chip in the status bar */
        const val LOCATION_STATUS_BAR_POPUP = 5

        /** Attached at the root of the hierarchy in an overlay */
        const val IN_OVERLAY = -1000

@@ -1422,6 +1438,7 @@ private annotation class TransformationType
            MediaHierarchyManager.LOCATION_LOCKSCREEN,
            MediaHierarchyManager.LOCATION_DREAM_OVERLAY,
            MediaHierarchyManager.LOCATION_COMMUNAL_HUB,
            MediaHierarchyManager.LOCATION_STATUS_BAR_POPUP,
            MediaHierarchyManager.LOCATION_UNKNOWN,
        ],
)
+15 −11
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
        uid: Int,
        packageName: String,
        instanceId: InstanceId,
        playbackLocation: Int
        playbackLocation: Int,
    ) {
        val event =
            when (playbackLocation) {
@@ -61,7 +61,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
        uid: Int,
        packageName: String,
        instanceId: InstanceId,
        playbackLocation: Int
        playbackLocation: Int,
    ) {
        val event =
            when (playbackLocation) {
@@ -112,7 +112,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
            MediaUiEvent.OPEN_SETTINGS_LONG_PRESS,
            uid,
            packageName,
            instanceId
            instanceId,
        )
    }

@@ -156,6 +156,8 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
                    MediaUiEvent.MEDIA_CAROUSEL_LOCATION_DREAM
                MediaHierarchyManager.LOCATION_COMMUNAL_HUB ->
                    MediaUiEvent.MEDIA_CAROUSEL_LOCATION_COMMUNAL
                MediaHierarchyManager.LOCATION_STATUS_BAR_POPUP ->
                    MediaUiEvent.MEDIA_CAROUSEL_LOCATION_STATUS_BAR_POPUP
                else -> throw IllegalArgumentException("Unknown media carousel location $location")
            }
        logger.log(event)
@@ -166,7 +168,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
            MediaUiEvent.MEDIA_RECOMMENDATION_ADDED,
            0,
            packageName,
            instanceId
            instanceId,
        )
    }

@@ -175,7 +177,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
            MediaUiEvent.MEDIA_RECOMMENDATION_REMOVED,
            0,
            packageName,
            instanceId
            instanceId,
        )
    }

@@ -184,7 +186,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
            MediaUiEvent.MEDIA_RECOMMENDATION_ACTIVATED,
            uid,
            packageName,
            instanceId
            instanceId,
        )
    }

@@ -194,7 +196,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
            0,
            packageName,
            instanceId,
            position
            position,
        )
    }

@@ -203,7 +205,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
            MediaUiEvent.MEDIA_RECOMMENDATION_CARD_TAP,
            0,
            packageName,
            instanceId
            instanceId,
        )
    }

@@ -212,7 +214,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
            MediaUiEvent.MEDIA_OPEN_BROADCAST_DIALOG,
            uid,
            packageName,
            instanceId
            instanceId,
        )
    }

@@ -221,7 +223,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
            MediaUiEvent.MEDIA_CAROUSEL_SINGLE_PLAYER,
            uid,
            packageName,
            instanceId
            instanceId,
        )
    }

@@ -230,7 +232,7 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
            MediaUiEvent.MEDIA_CAROUSEL_MULTIPLE_PLAYERS,
            uid,
            packageName,
            instanceId
            instanceId,
        )
    }
}
@@ -280,6 +282,8 @@ enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
    MEDIA_CAROUSEL_LOCATION_DREAM(1040),
    @UiEvent(doc = "The media carousel moved to the communal hub UI")
    MEDIA_CAROUSEL_LOCATION_COMMUNAL(1520),
    @UiEvent(doc = "The media carousel moved to the status bar popup")
    MEDIA_CAROUSEL_LOCATION_STATUS_BAR_POPUP(2170),
    @UiEvent(doc = "A media recommendation card was added to the media carousel")
    MEDIA_RECOMMENDATION_ADDED(1041),
    @UiEvent(doc = "A media recommendation card was removed from the media carousel")
+21 −1
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ public interface MediaModule {
    String KEYGUARD = "media_keyguard";
    String DREAM = "dream";
    String COMMUNAL_HUB = "communal_Hub";
    String POPUP = "popup";

    /** */
    @Provides
@@ -102,7 +103,26 @@ public interface MediaModule {
    @Provides
    @SysUISingleton
    @Named(COMMUNAL_HUB)
    static MediaHost providesCommunalMediaHost(MediaHost.MediaHostStateHolder stateHolder,
    static MediaHost providesCommunalMediaHost(
            MediaHost.MediaHostStateHolder stateHolder,
            MediaHierarchyManager hierarchyManager,
            MediaDataManager dataManager,
            MediaHostStatesManager statesManager,
            MediaCarouselController carouselController,
            MediaCarouselControllerLogger logger) {
        return new MediaHost(
                stateHolder,
                hierarchyManager,
                dataManager,
                statesManager,
                carouselController,
                logger);
    }

    @Provides
    @SysUISingleton
    @Named(POPUP)
    static MediaHost providesPopupMediaHost(MediaHost.MediaHostStateHolder stateHolder,
            MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
            MediaHostStatesManager statesManager, MediaCarouselController carouselController,
            MediaCarouselControllerLogger logger) {
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.systemui.statusbar.featurepods.media.ui.compose

import android.widget.FrameLayout
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.res.R

/** Displays a popup containing media controls. Embeds the MediaCarousel within a Compose popup. */
@Composable
fun MediaControlPopup(mediaHost: MediaHost, modifier: Modifier = Modifier) {
    AndroidView(
        modifier =
            modifier
                .width(400.dp)
                .height(200.dp)
                .clip(
                    shape =
                        RoundedCornerShape(dimensionResource(R.dimen.notification_corner_radius))
                ),
        factory = { _ ->
            mediaHost.hostView.apply {
                layoutParams =
                    FrameLayout.LayoutParams(
                        FrameLayout.LayoutParams.MATCH_PARENT,
                        FrameLayout.LayoutParams.MATCH_PARENT,
                    )
            }
            mediaHost.hostView
        },
        onReset = {},
    )
}
+4 −2
Original line number Diff line number Diff line
@@ -28,7 +28,9 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.res.R
import com.android.systemui.statusbar.featurepods.media.ui.compose.MediaControlPopup
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel

@@ -37,7 +39,7 @@ import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipM
 * status bar.
 */
@Composable
fun StatusBarPopup(viewModel: PopupChipModel.Shown) {
fun StatusBarPopup(viewModel: PopupChipModel.Shown, mediaHost: MediaHost) {
    val density = Density(LocalContext.current)
    Popup(
        properties =
@@ -56,7 +58,7 @@ fun StatusBarPopup(viewModel: PopupChipModel.Shown) {
        Box(modifier = Modifier.padding(8.dp).wrapContentSize()) {
            when (viewModel.chipId) {
                is PopupChipId.MediaControl -> {
                    // TODO(b/385202114): Populate MediaControlPopup contents.
                    MediaControlPopup(mediaHost = mediaHost)
                }
            }
            // Future popup types will be handled here.
Loading