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

Commit d664de2c authored by Beth Thibodeau's avatar Beth Thibodeau
Browse files

Update when media controls get cleared

Some apps include an action to dismiss a media notification, so we
should listen for that happening and clear controls in that case.

Also, remove STATE_CONNECTING as a condition to clear controls -
This was originally added in ag/11056932 as a workaround for an issue
with YouTube cast sessions. However this caused issues with other apps
like Spotify which set STATE_CONNECTING while still active. YT was using
that as a workaround for legacy behavior and will update to use
STATE_NONE for R+ builds (b/155213698). In the meantime, listening for
when the notification is removed will also work to clear YT's controls
as expected.

Fixes: 154953276
Fixes: 155029855
Test: manual

Change-Id: Ie9320e1406c1f457a39f67705ec1ffcb3a983488
parent 0920ccba
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -124,11 +124,7 @@ public class MediaControlPanel {
        @Override
        public void onPlaybackStateChanged(PlaybackState state) {
            final int s = state != null ? state.getState() : PlaybackState.STATE_NONE;
            // When the playback state is NONE or CONNECTING, transition the player to the
            // resumption state. State CONNECTING needs to be considered for Cast sessions. Ending
            // a cast session in YT results in the CONNECTING state, which makes sense if you
            // thinking of the session as waiting to connect to another cast device.
            if (s == PlaybackState.STATE_NONE || s == PlaybackState.STATE_CONNECTING) {
            if (s == PlaybackState.STATE_NONE) {
                Log.d(TAG, "playback state change will trigger resumption, state=" + state);
                clearControls();
                makeInactive();
+1 −1
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ public class QSMediaBrowser {
        public void onChildrenLoaded(String parentId,
                List<MediaBrowser.MediaItem> children) {
            if (children.size() == 0) {
                Log.e(TAG, "No children found");
                Log.e(TAG, "No children found for " + mComponentName);
                return;
            }
            // We ask apps to return a playable item as the first child when sending
+40 −1
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import android.widget.LinearLayout;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.InfoMediaManager;
@@ -75,6 +76,9 @@ import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.BrightnessController;
import com.android.systemui.settings.ToggleSliderView;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener;
import com.android.systemui.tuner.TunerService;
@@ -116,6 +120,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
    private final DelayableExecutor mBackgroundExecutor;
    private boolean mUpdateCarousel = false;
    private ActivityStarter mActivityStarter;
    private NotificationEntryManager mNotificationEntryManager;

    protected boolean mExpanded;
    protected boolean mListening;
@@ -151,6 +156,15 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
        }
    };

    private final NotificationEntryListener mNotificationEntryListener =
            new NotificationEntryListener() {
        @Override
        public void onEntryRemoved(NotificationEntry entry, NotificationVisibility visibility,
                boolean removedByUser, int reason) {
            checkToRemoveMediaNotification(entry);
        }
    };

    @Inject
    public QSPanel(
            @Named(VIEW_CONTEXT) Context context,
@@ -161,7 +175,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
            @Main Executor foregroundExecutor,
            @Background DelayableExecutor backgroundExecutor,
            @Nullable LocalBluetoothManager localBluetoothManager,
            ActivityStarter activityStarter
            ActivityStarter activityStarter,
            NotificationEntryManager entryManager
    ) {
        super(context, attrs);
        mContext = context;
@@ -172,6 +187,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
        mLocalBluetoothManager = localBluetoothManager;
        mBroadcastDispatcher = broadcastDispatcher;
        mActivityStarter = activityStarter;
        mNotificationEntryManager = entryManager;

        setOrientation(VERTICAL);

@@ -407,6 +423,27 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
        mHasLoadedMediaControls = true;
    }

    private void checkToRemoveMediaNotification(NotificationEntry entry) {
        if (!useQsMediaPlayer(mContext)) {
            return;
        }

        if (!entry.isMediaNotification()) {
            return;
        }

        // If this entry corresponds to an existing set of controls, clear the controls
        // This will handle apps that use an action to clear their notification
        for (QSMediaPlayer p : mMediaPlayers) {
            if (p.getKey() != null && p.getKey().equals(entry.getKey())) {
                Log.d(TAG, "Clearing controls since notification removed " + entry.getKey());
                p.clearControls();
                return;
            }
        }
        Log.d(TAG, "Media notification removed but no player found " + entry.getKey());
    }

    protected void addDivider() {
        mDivider = LayoutInflater.from(mContext).inflate(R.layout.qs_divider, this, false);
        mDivider.setBackgroundColor(Utils.applyAlpha(mDivider.getAlpha(),
@@ -473,6 +510,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
                loadMediaResumptionControls();
            }
        }
        mNotificationEntryManager.addNotificationEntryListener(mNotificationEntryListener);
    }

    @Override
@@ -489,6 +527,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
        }
        mDumpManager.unregisterDumpable(getDumpableTag());
        mBroadcastDispatcher.unregisterReceiver(mUserChangeReceiver);
        mNotificationEntryManager.removeNotificationEntryListener(mNotificationEntryListener);
        super.onDetachedFromWindow();
    }

+5 −2
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.Utils;
@@ -86,10 +87,12 @@ public class QuickQSPanel extends QSPanel {
            @Main Executor foregroundExecutor,
            @Background DelayableExecutor backgroundExecutor,
            @Nullable LocalBluetoothManager localBluetoothManager,
            ActivityStarter activityStarter
            ActivityStarter activityStarter,
            NotificationEntryManager entryManager
    ) {
        super(context, attrs, dumpManager, broadcastDispatcher, qsLogger,
                foregroundExecutor, backgroundExecutor, localBluetoothManager, activityStarter);
                foregroundExecutor, backgroundExecutor, localBluetoothManager, activityStarter,
                entryManager);
        if (mFooter != null) {
            removeView(mFooter.getView());
        }
+4 −1
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.util.concurrency.DelayableExecutor;

import org.junit.Before;
@@ -91,6 +92,8 @@ public class QSPanelTest extends SysuiTestCase {
    private LocalBluetoothManager mLocalBluetoothManager;
    @Mock
    private ActivityStarter mActivityStarter;
    @Mock
    private NotificationEntryManager mEntryManager;

    @Before
    public void setup() throws Exception {
@@ -101,7 +104,7 @@ public class QSPanelTest extends SysuiTestCase {
            mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
            mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher,
                    mQSLogger, mForegroundExecutor, mBackgroundExecutor,
                    mLocalBluetoothManager, mActivityStarter);
                    mLocalBluetoothManager, mActivityStarter, mEntryManager);
            // Provides a parent with non-zero size for QSPanel
            mParentView = new FrameLayout(mContext);
            mParentView.addView(mQsPanel);