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

Commit fc24381f authored by Luna Zhang's avatar Luna Zhang Committed by Jiaming Cheng
Browse files

MediaOutputDialog should display at the QS shade's center on desktop

Bug: b/378513663
Test: atest
Flag: com.android.systemui.qs_tile_detailed_view
Change-Id: Icfcace9529d3afb31383746fb40fcef2fa068c81
parent d7400b68
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.qs.composefragment.dagger.usingMediaInComposeFragment
import com.android.systemui.qs.panels.data.repository.qsPanelAppearanceRepository
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.domain.startable.sceneContainerStartable
@@ -180,6 +181,7 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() {
            underTest.onPanelShapeInWindowChanged(expected)

            assertThat(actual).isEqualTo(expected)
            assertThat(kosmos.qsPanelAppearanceRepository.qsPanelShape.value).isEqualTo(expected)

            disposable.dispose()
        }
+27 −1
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@ import static com.android.media.flags.Flags.enableOutputSwitcherPersonalAudioSha
import static com.android.media.flags.Flags.enableOutputSwitcherRedesign;

import android.annotation.Nullable;
import android.app.Dialog;
import android.content.Context;
import android.content.res.Configuration;
import android.media.RoutingSessionInfo;
import android.os.Bundle;
import android.view.View;
@@ -45,6 +47,7 @@ import java.util.concurrent.Executor;
public class MediaOutputDialog extends MediaOutputBaseDialog {
    private final DialogTransitionAnimator mDialogTransitionAnimator;
    private final UiEventLogger mUiEventLogger;
    @Nullable private final OnDialogEventListener mOnDialogEventListener;

    MediaOutputDialog(
            Context context,
@@ -55,7 +58,8 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
            UiEventLogger uiEventLogger,
            Executor mainExecutor,
            Executor backgroundExecutor,
            boolean includePlaybackAndAppMetadata) {
            boolean includePlaybackAndAppMetadata,
            @Nullable OnDialogEventListener onDialogEventListener) {
        super(context, broadcastSender, mediaSwitchingController, includePlaybackAndAppMetadata);
        mDialogTransitionAnimator = dialogTransitionAnimator;
        mUiEventLogger = uiEventLogger;
@@ -63,6 +67,7 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
                ? new MediaOutputAdapter(mMediaSwitchingController)
                : new MediaOutputAdapterLegacy(mMediaSwitchingController, mainExecutor,
                        backgroundExecutor);
        mOnDialogEventListener = onDialogEventListener;
        if (!aboveStatusbar) {
            getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
        }
@@ -72,6 +77,18 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mUiEventLogger.log(MediaOutputEvent.MEDIA_OUTPUT_DIALOG_SHOW);

        if (mOnDialogEventListener != null) {
            mOnDialogEventListener.onCreate(this);
        }
    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {
        super.onConfigurationChanged(configuration);
        if (mOnDialogEventListener != null) {
            mOnDialogEventListener.onConfigurationChanged(this, configuration);
        }
    }

    @Override
@@ -162,4 +179,13 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
            default -> null;
        };
    }

    /** Callback for configuration changes . */
    public interface OnDialogEventListener{
        /** Will be called inside onConfigurationChanged. */
        void onConfigurationChanged(Dialog dialog, Configuration newConfig);

        /** Will be called when the dialog is created. */
        void onCreate(Dialog dialog);
    }
}
+7 −1
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ constructor(
        controller: DialogTransitionAnimator.Controller?,
        userHandle: UserHandle? = null,
        token: MediaSession.Token? = null,
        onDialogEventListener: MediaOutputDialog.OnDialogEventListener? = null,
    ) {
        createAndShow(
            packageName,
@@ -95,11 +96,13 @@ constructor(
            includePlaybackAndAppMetadata = true,
            userHandle = userHandle,
            token = token,
            onDialogEventListener = onDialogEventListener,
        )
    }

    open fun createAndShowForSystemRouting(
        controller: DialogTransitionAnimator.Controller? = null
        controller: DialogTransitionAnimator.Controller? = null,
        onDialogEventListener: MediaOutputDialog.OnDialogEventListener? = null,
    ) {
        createAndShow(
            packageName = null,
@@ -107,6 +110,7 @@ constructor(
            dialogTransitionAnimatorController = controller,
            includePlaybackAndAppMetadata = false,
            userHandle = null,
            onDialogEventListener = onDialogEventListener,
        )
    }

@@ -120,6 +124,7 @@ constructor(
        includePlaybackAndAppMetadata: Boolean = true,
        userHandle: UserHandle? = null,
        token: MediaSession.Token? = null,
        onDialogEventListener: MediaOutputDialog.OnDialogEventListener? = null,
    ) {
        // Dismiss the previous dialog, if any.
        mediaOutputDialog?.dismiss()
@@ -137,6 +142,7 @@ constructor(
                mainExecutor,
                backgroundExecutor,
                includePlaybackAndAppMetadata,
                onDialogEventListener,
            )

        // Show the dialog.
+36 −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.qs.panels.data.repository

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

/** Observing the shape of the Quick Settings panel. */
@SysUISingleton
class QSPanelAppearanceRepository @Inject constructor() {

    private val _qsPanelShape = MutableStateFlow<ShadeScrimShape?>(null)
    val qsPanelShape: StateFlow<ShadeScrimShape?> = _qsPanelShape.asStateFlow()

    fun setQsPanelShape(shape: ShadeScrimShape?) {
        _qsPanelShape.value = shape
    }
}
+35 −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.qs.panels.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.panels.data.repository.QSPanelAppearanceRepository
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow

/** Observing the shape of the Quick Settings panel. */
@SysUISingleton
class QSPanelAppearanceInteractor
@Inject
constructor(private val repository: QSPanelAppearanceRepository) {
    val qsPanelShape: StateFlow<ShadeScrimShape?> = repository.qsPanelShape

    fun setQsPanelShape(shape: ShadeScrimShape?) {
        repository.setQsPanelShape(shape)
    }
}
Loading