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

Commit ef154077 authored by Yiyi Shen's avatar Yiyi Shen Committed by Android (Google) Code Review
Browse files

Merge "[Cleanup] Clean up legacy broadcast feature from output switcher" into main

parents 8b5f8436 1b32b313
Loading
Loading
Loading
Loading
+7 −30
Original line number Diff line number Diff line
@@ -44,11 +44,6 @@
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="top"
                android:orientation="horizontal">
            <ImageView
                android:id="@+id/app_source_icon"
                android:layout_width="20dp"
@@ -56,24 +51,6 @@
                android:layout_marginBottom="7dp"
                android:gravity="center_vertical"
                android:importantForAccessibility="no"/>

                <Space
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"/>

                <ImageView
                    android:id="@+id/broadcast_icon"
                    android:src="@drawable/settings_input_antenna"
                    android:contentDescription="@string/broadcasting_description_is_broadcasting"
                    android:layout_width="48dp"
                    android:layout_height="48dp"
                    android:padding="12dp"
                    android:gravity="center_vertical"
                    android:clickable="true"
                    android:focusable="true"
                    android:visibility="gone"/>
            </LinearLayout>
            <TextView
                android:id="@+id/header_title"
                android:layout_width="wrap_content"
+0 −194
Original line number Diff line number Diff line
@@ -26,10 +26,7 @@ import static com.android.systemui.FontStyles.GSF_TITLE_SMALL;

import android.annotation.NonNull;
import android.app.WallpaperColors;
import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.ColorFilter;
@@ -42,7 +39,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -68,17 +64,13 @@ import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.google.android.material.button.MaterialButton;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/** Base dialog for media output UI */
public abstract class MediaOutputBaseDialog extends SystemUIDialog
        implements MediaSwitchingController.Callback, Window.Callback {

    private static final String TAG = "MediaOutputDialog";
    private static final String PREF_NAME = "MediaOutputDialog";
    private static final String PREF_IS_LE_BROADCAST_FIRST_LAUNCH = "PrefIsLeBroadcastFirstLaunch";
    private static final boolean DEBUG = true;
    private static final int HANDLE_BROADCAST_FAILED_DELAY = 3000;

    protected final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
    private final LinearLayoutManager mLayoutManager;
@@ -100,7 +92,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
    private TextView mHeaderSubtitle;
    private ImageView mHeaderIcon;
    private ImageView mAppResourceIcon;
    private ImageView mBroadcastIcon;
    private RecyclerView mDevicesRecyclerView;
    private ViewGroup mDeviceListLayout;
    private ViewGroup mQuickAccessShelf;
@@ -111,89 +102,12 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
    private View mFooterSpacer;
    private Button mStopButton;
    private WallpaperColors mWallpaperColors;
    private boolean mShouldLaunchLeBroadcastDialog;
    private boolean mIsLeBroadcastCallbackRegistered;
    private boolean mDismissing;

    MediaOutputAdapterBase mAdapter;

    protected Executor mExecutor;


    private final BluetoothLeBroadcast.Callback mBroadcastCallback =
            new BluetoothLeBroadcast.Callback() {
                @Override
                public void onBroadcastStarted(int reason, int broadcastId) {
                    if (DEBUG) {
                        Log.d(TAG, "onBroadcastStarted(), reason = " + reason
                                + ", broadcastId = " + broadcastId);
                    }
                    mMainThreadHandler.post(() -> handleLeBroadcastStarted());
                }

                @Override
                public void onBroadcastStartFailed(int reason) {
                    if (DEBUG) {
                        Log.d(TAG, "onBroadcastStartFailed(), reason = " + reason);
                    }
                    mMainThreadHandler.postDelayed(() -> handleLeBroadcastStartFailed(),
                            HANDLE_BROADCAST_FAILED_DELAY);
                }

                @Override
                public void onBroadcastMetadataChanged(int broadcastId,
                        @NonNull BluetoothLeBroadcastMetadata metadata) {
                    if (DEBUG) {
                        Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId
                                + ", metadata = " + metadata);
                    }
                    mMainThreadHandler.post(() -> handleLeBroadcastMetadataChanged());
                }

                @Override
                public void onBroadcastStopped(int reason, int broadcastId) {
                    if (DEBUG) {
                        Log.d(TAG, "onBroadcastStopped(), reason = " + reason
                                + ", broadcastId = " + broadcastId);
                    }
                    mMainThreadHandler.post(() -> handleLeBroadcastStopped());
                }

                @Override
                public void onBroadcastStopFailed(int reason) {
                    if (DEBUG) {
                        Log.d(TAG, "onBroadcastStopFailed(), reason = " + reason);
                    }
                    mMainThreadHandler.post(() -> handleLeBroadcastStopFailed());
                }

                @Override
                public void onBroadcastUpdated(int reason, int broadcastId) {
                    if (DEBUG) {
                        Log.d(TAG, "onBroadcastUpdated(), reason = " + reason
                                + ", broadcastId = " + broadcastId);
                    }
                    mMainThreadHandler.post(() -> handleLeBroadcastUpdated());
                }

                @Override
                public void onBroadcastUpdateFailed(int reason, int broadcastId) {
                    if (DEBUG) {
                        Log.d(TAG, "onBroadcastUpdateFailed(), reason = " + reason
                                + ", broadcastId = " + broadcastId);
                    }
                    mMainThreadHandler.post(() -> handleLeBroadcastUpdateFailed());
                }

                @Override
                public void onPlaybackStarted(int reason, int broadcastId) {
                }

                @Override
                public void onPlaybackStopped(int reason, int broadcastId) {
                }
            };

    private class LayoutManagerWrapper extends LinearLayoutManager {
        LayoutManagerWrapper(Context context) {
            super(context);
@@ -219,7 +133,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
        mBroadcastSender = broadcastSender;
        mMediaSwitchingController = mediaSwitchingController;
        mLayoutManager = new LayoutManagerWrapper(mContext);
        mExecutor = Executors.newSingleThreadExecutor();
        mIncludePlaybackAndAppMetadata = includePlaybackAndAppMetadata;
    }

@@ -253,7 +166,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
        mDoneButton = mDialogView.requireViewById(R.id.done);
        mStopButton = mDialogView.requireViewById(R.id.stop);
        mAppResourceIcon = mDialogView.requireViewById(R.id.app_source_icon);
        mBroadcastIcon = mDialogView.requireViewById(R.id.broadcast_icon);

        // Init device list
        mLayoutManager.setAutoMeasureEnabled(true);
@@ -333,22 +245,10 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
    @Override
    public void start() {
        mMediaSwitchingController.start(this);
        if (isBroadcastSupported() && !mIsLeBroadcastCallbackRegistered) {
            mMediaSwitchingController.registerLeBroadcastServiceCallback(
                    mExecutor, mBroadcastCallback);
            mIsLeBroadcastCallbackRegistered = true;
        }
    }

    @Override
    public void stop() {
        // unregister broadcast callback should only depend on profile and registered flag
        // rather than remote device or broadcast state
        // otherwise it might have risks of leaking registered callback handle
        if (mMediaSwitchingController.isBroadcastSupported() && mIsLeBroadcastCallbackRegistered) {
            mMediaSwitchingController.unregisterLeBroadcastServiceCallback(mBroadcastCallback);
            mIsLeBroadcastCallbackRegistered = false;
        }
        mMediaSwitchingController.stop();
    }

@@ -451,8 +351,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
        mStopButton.setText(getStopButtonText());
        mStopButton.setOnClickListener(v -> onStopButtonClick());

        mBroadcastIcon.setVisibility(getBroadcastIconVisibility());
        mBroadcastIcon.setOnClickListener(v -> onBroadcastIconClick());
        if (!mAdapter.isDragging()) {
            int currentActivePosition = mAdapter.getCurrentActivePosition();
            if (!colorSetUpdated && !deviceSetChanged && currentActivePosition >= 0
@@ -512,86 +410,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
                        : mMediaSwitchingController.getColorScheme().getSurfaceContainer());
    }

    public void handleLeBroadcastStarted() {
        // Waiting for the onBroadcastMetadataChanged. The UI launchs the broadcast dialog when
        // the metadata is ready.
        mShouldLaunchLeBroadcastDialog = true;
    }

    public void handleLeBroadcastStartFailed() {
        mStopButton.setText(R.string.media_output_broadcast_start_failed);
        mStopButton.setEnabled(false);
        refresh();
    }

    public void handleLeBroadcastMetadataChanged() {
        if (mShouldLaunchLeBroadcastDialog) {
            startLeBroadcastDialog();
            mShouldLaunchLeBroadcastDialog = false;
        }
        refresh();
    }

    public void handleLeBroadcastStopped() {
        mShouldLaunchLeBroadcastDialog = false;
        refresh();
    }

    public void handleLeBroadcastStopFailed() {
        refresh();
    }

    public void handleLeBroadcastUpdated() {
        refresh();
    }

    public void handleLeBroadcastUpdateFailed() {
        refresh();
    }

    protected void startLeBroadcast() {
        mStopButton.setText(R.string.media_output_broadcast_starting);
        mStopButton.setEnabled(false);
        if (!mMediaSwitchingController.startBluetoothLeBroadcast()) {
            // If the system can't execute "broadcast start", then UI shows the error.
            handleLeBroadcastStartFailed();
        }
    }

    protected boolean startLeBroadcastDialogForFirstTime(){
        SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME,
                Context.MODE_PRIVATE);
        if (sharedPref != null
                && sharedPref.getBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, true)) {
            Log.d(TAG, "PREF_IS_LE_BROADCAST_FIRST_LAUNCH: true");

            mMediaSwitchingController.launchLeBroadcastNotifyDialog(
                    mDialogView,
                    mBroadcastSender,
                    MediaSwitchingController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH,
                    (d, w) -> {
                        startLeBroadcast();
                    });
            SharedPreferences.Editor editor = sharedPref.edit();
            editor.putBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, false);
            editor.apply();
            return true;
        }
        return false;
    }

    protected void startLeBroadcastDialog() {
        refresh();
    }

    protected void stopLeBroadcast() {
        mStopButton.setEnabled(false);
        if (!mMediaSwitchingController.stopBluetoothLeBroadcast()) {
            // If the system can't execute "broadcast stop", then UI does refresh.
            mMainThreadHandler.post(() -> refresh());
        }
    }

    abstract IconCompat getAppSourceIcon();

    abstract int getHeaderIconRes();
@@ -613,18 +431,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
        dismiss();
    }

    public int getBroadcastIconVisibility() {
        return View.GONE;
    }

    public void onBroadcastIconClick() {
        // Do nothing.
    }

    public boolean isBroadcastSupported() {
        return false;
    }

    @Override
    public void onMediaChanged() {
        mMainThreadHandler.post(() -> refresh());
+6 −76
Original line number Diff line number Diff line
@@ -18,13 +18,11 @@ package com.android.systemui.media.dialog;

import static com.android.media.flags.Flags.enableOutputSwitcherPersonalAudioSharing;
import static com.android.media.flags.Flags.enableOutputSwitcherRedesign;
import static com.android.settingslib.flags.Flags.legacyLeAudioSharing;

import android.annotation.Nullable;
import android.content.Context;
import android.media.RoutingSessionInfo;
import android.os.Bundle;
import android.util.FeatureFlagUtils;
import android.view.View;
import android.view.WindowManager;

@@ -109,101 +107,33 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
                    mMediaSwitchingController.isActiveRemoteDevice(
                            mMediaSwitchingController.getCurrentConnectedMediaDevice());
        }
        // TODO(b/333324985): Remove these code (code under flag legacy_le_audio_sharing) once flag
        //  enable_le_audio_sharing has reached nextfood.
        // isBroadcastSupported always returns false when flag legacy_le_audio_sharing is disabled
        boolean showBroadcastButton =
                isBroadcastSupported() && mMediaSwitchingController.isPlaying();

        boolean inBroadcast =
                enableOutputSwitcherPersonalAudioSharing()
                        && mMediaSwitchingController.getSessionReleaseType()
                                == RoutingSessionInfo.RELEASE_TYPE_SHARING;

        return (isActiveRemoteDevice || showBroadcastButton || inBroadcast)
        return (isActiveRemoteDevice || inBroadcast)
                ? View.VISIBLE
                : View.GONE;
    }

    @Override
    public boolean isBroadcastSupported() {
        if (!legacyLeAudioSharing()) return false;
        boolean isBluetoothLeDevice = false;
        boolean isBroadcastEnabled = false;
        if (FeatureFlagUtils.isEnabled(mContext,
                FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST)) {
            if (mMediaSwitchingController.getCurrentConnectedMediaDevice() != null) {
                isBluetoothLeDevice =
                        mMediaSwitchingController.isBluetoothLeDevice(
                                mMediaSwitchingController.getCurrentConnectedMediaDevice());
                // if broadcast is active, broadcast should be considered as supported
                // there could be a valid case that broadcast is ongoing
                // without active LEA device connected
                isBroadcastEnabled = mMediaSwitchingController.isBluetoothLeBroadcastEnabled();
            }
        } else {
            // To decouple LE Audio Broadcast and Unicast, it always displays the button when there
            // is no LE Audio device connected to the phone
            isBluetoothLeDevice = true;
        }

        return mMediaSwitchingController.isBroadcastSupported()
                && (isBluetoothLeDevice || isBroadcastEnabled);
    }

    @Override
    public CharSequence getStopButtonText() {
        int resId = R.string.media_output_dialog_button_stop_casting;
        if (isBroadcastSupported()
                && mMediaSwitchingController.isPlaying()
                && !mMediaSwitchingController.isBluetoothLeBroadcastEnabled()) {
            // TODO(b/333324985): Remove these code (code under flag legacy_le_audio_sharing)
            //  once flag enable_le_audio_sharing has reached nextfood.
            // isBroadcastSupported always returns false when flag legacy_le_audio_sharing is
            // disabled.
            resId = R.string.media_output_broadcast;
        } else if (enableOutputSwitcherPersonalAudioSharing()) {
        if (enableOutputSwitcherPersonalAudioSharing()) {
            CharSequence stopButtonText = getTextForSessionReleaseType();
            if (stopButtonText != null) {
                return stopButtonText;
            }
        }
        return mContext.getText(resId);
        return mContext.getText(R.string.media_output_dialog_button_stop_casting);
    }

    @Override
    public void onStopButtonClick() {
        if (isBroadcastSupported() && mMediaSwitchingController.isPlaying()) {
            // TODO(b/333324985): Remove these code (code under flag legacy_le_audio_sharing)
            //  once flag enable_le_audio_sharing has reached nextfood.
            // isBroadcastSupported always returns false when flag legacy_le_audio_sharing is
            // disabled.
            if (!mMediaSwitchingController.isBluetoothLeBroadcastEnabled()) {
                if (startLeBroadcastDialogForFirstTime()) {
                    return;
                }
                startLeBroadcast();
            } else {
                stopLeBroadcast();
            }
        } else {
        mMediaSwitchingController.releaseSession();
        mDialogTransitionAnimator.disableAllCurrentDialogsExitAnimations();
        dismiss();
    }
    }

    @Override
    public int getBroadcastIconVisibility() {
        return (isBroadcastSupported() && mMediaSwitchingController.isBluetoothLeBroadcastEnabled())
                ? View.VISIBLE
                : View.GONE;
    }

    @Override
    public void onBroadcastIconClick() {
        startLeBroadcastDialog();
    }

    @VisibleForTesting
    public enum MediaOutputEvent implements UiEventLogger.UiEventEnum {
+0 −255

File changed.

Preview size limit exceeded, changes collapsed.

+0 −79
Original line number Diff line number Diff line
@@ -57,7 +57,6 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestCaseExtKt;
import com.android.systemui.animation.DialogTransitionAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.kosmos.Kosmos;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
@@ -104,7 +103,6 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
    private final AudioManager mAudioManager = mock(AudioManager.class);
    private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
    private KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
    private FeatureFlags mFlags = mock(FeatureFlags.class);
    private UserTracker mUserTracker = mock(UserTracker.class);

    private List<MediaController> mMediaControllers = new ArrayList<>();
@@ -115,9 +113,6 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
    private CharSequence mHeaderTitle;
    private CharSequence mHeaderSubtitle;
    private String mStopText;
    private boolean mIsBroadcasting;
    private boolean mIsBroadcastIconVisibility;


    @Before
    public void setUp() {
@@ -167,7 +162,6 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
                        mAudioManager,
                        mPowerExemptionManager,
                        mKeyguardManager,
                        mFlags,
                        new FakeSystemClock(),
                        volumePanelGlobalStateInteractor,
                        mUserTracker);
@@ -240,27 +234,6 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
        assertThat(view.getVisibility()).isEqualTo(View.GONE);
    }

    @Test
    public void refresh_broadcastIconVisibilityOff_broadcastIconLayoutNotVisible() {
        mIsBroadcastIconVisibility = false;

        mMediaOutputBaseDialogImpl.refresh();
        final ImageView view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
                R.id.broadcast_icon);

        assertThat(view.getVisibility()).isEqualTo(View.GONE);
    }
    @Test
    public void refresh_broadcastIconVisibilityOn_broadcastIconLayoutVisible() {
        mIsBroadcastIconVisibility = true;

        mMediaOutputBaseDialogImpl.refresh();
        final ImageView view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
                R.id.broadcast_icon);

        assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
    }

    @Test
    public void refresh_checkTitle() {
        mHeaderTitle = "test_string";
@@ -326,48 +299,6 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
        verify(mBroadcastSender).closeSystemDialogs();
    }

    @Test
    public void whenBroadcasting_verifyLeBroadcastServiceCallBackIsRegisteredAndUnregistered() {
        when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                mLocalBluetoothLeBroadcast);
        mIsBroadcasting = true;

        mMediaOutputBaseDialogImpl.start();
        verify(mLocalBluetoothLeBroadcast).registerServiceCallBack(any(), any());

        mMediaOutputBaseDialogImpl.stop();
        verify(mLocalBluetoothLeBroadcast).unregisterServiceCallBack(any());
    }

    @Test
    public void
            whenNotBroadcasting_verifyLeBroadcastServiceCallBackIsNotRegisteredOrUnregistered() {
        when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                mLocalBluetoothLeBroadcast);
        mIsBroadcasting = false;

        mMediaOutputBaseDialogImpl.start();
        mMediaOutputBaseDialogImpl.stop();

        verify(mLocalBluetoothLeBroadcast, never()).registerServiceCallBack(any(), any());
        verify(mLocalBluetoothLeBroadcast, never()).unregisterServiceCallBack(any());
    }

    @Test
    public void
            whenNotBroadcasting_verifyLeBroadcastServiceCallBackIsUnregisteredIfProfileEnabled() {
        when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                mLocalBluetoothLeBroadcast);
        mIsBroadcasting = true;

        mMediaOutputBaseDialogImpl.start();
        verify(mLocalBluetoothLeBroadcast).registerServiceCallBack(any(), any());

        mIsBroadcasting = false;
        mMediaOutputBaseDialogImpl.stop();
        verify(mLocalBluetoothLeBroadcast).unregisterServiceCallBack(any());
    }

    @Test
    public void refresh_checkStopText() {
        mStopText = "test_string";
@@ -422,19 +353,9 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
            return 0;
        }

        @Override
        public boolean isBroadcastSupported() {
            return mIsBroadcasting;
        }

        @Override
        public CharSequence getStopButtonText() {
            return mStopText;
        }

        @Override
        public int getBroadcastIconVisibility() {
            return mIsBroadcastIconVisibility ? View.VISIBLE : View.GONE;
        }
    }
}
Loading