diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 150888ccb2d8a..89854bbab3e8c 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -24,9 +24,6 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; @@ -42,7 +39,6 @@ import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserHandle; import android.util.Pair; import android.util.Slog; import android.view.View; @@ -524,27 +520,6 @@ public class StatusBarManager { private final Map nearbyMediaDevicesProviderMap = new HashMap<>(); - /** - * Media controls based on {@link android.app.Notification.MediaStyle} notifications will have - * actions based on the media session's {@link android.media.session.PlaybackState}, rather than - * the notification's actions. - * - * These actions will be: - * - Play/Pause (depending on whether the current state is a playing state) - * - Previous (if declared), or a custom action if the slot is not reserved with - * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV} - * - Next (if declared), or a custom action if the slot is not reserved with - * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT} - * - Custom action - * - Custom action - * - * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV - * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) - private static final long MEDIA_CONTROL_SESSION_ACTIONS = 203800354L; - @UnsupportedAppUsage private Context mContext; private IStatusBarService mService; @@ -1152,20 +1127,6 @@ public class StatusBarManager { } } - /** - * Checks whether the given package should use session-based actions for its media controls. - * - * @param packageName App posting media controls - * @param userId Current user ID - * @return true if the app supports session actions - * - * @hide - */ - public static boolean useMediaSessionActionsForApp(String packageName, int userId) { - UserHandle handle = UserHandle.getUserHandleForUid(userId); - return CompatChanges.isChangeEnabled(MEDIA_CONTROL_SESSION_ACTIONS, packageName, handle); - } - /** @hide */ public static String windowStateToString(int state) { if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING"; diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index 2d1db716b7005..d1873a0f40cfa 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -76,8 +76,5 @@ - - - diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 4b45cc338a6ad..e24b2d6c6aa90 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -314,11 +314,6 @@ - - - - - diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index 61cfe925f6408..2db3de173257e 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -145,7 +145,7 @@ public class Flags { /***************************************/ // 900 - media public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true); - public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, false); + public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, true); public static final BooleanFlag MEDIA_SESSION_LAYOUT = new BooleanFlag(902, true); public static final BooleanFlag MEDIA_NEARBY_DEVICES = new BooleanFlag(903, true); public static final BooleanFlag MEDIA_MUTE_AWAIT = new BooleanFlag(904, true); diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index ffdd5376b12ea..510d15bd7b733 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -137,6 +137,7 @@ public class MediaControlPanel { private MediaCarouselController mMediaCarouselController; private final MediaOutputDialogFactory mMediaOutputDialogFactory; private final FalsingManager mFalsingManager; + private final MediaFlags mMediaFlags; // Used for swipe-to-dismiss logging. protected boolean mIsImpressed = false; @@ -155,7 +156,7 @@ public class MediaControlPanel { Lazy lazyMediaDataManager, MediaOutputDialogFactory mediaOutputDialogFactory, MediaCarouselController mediaCarouselController, - FalsingManager falsingManager, SystemClock systemClock) { + FalsingManager falsingManager, MediaFlags mediaFlags, SystemClock systemClock) { mContext = context; mBackgroundExecutor = backgroundExecutor; mActivityStarter = activityStarter; @@ -166,6 +167,7 @@ public class MediaControlPanel { mMediaOutputDialogFactory = mediaOutputDialogFactory; mMediaCarouselController = mediaCarouselController; mFalsingManager = falsingManager; + mMediaFlags = mediaFlags; mSystemClock = systemClock; loadDimens(); @@ -504,8 +506,9 @@ public class MediaControlPanel { List actionIcons = data.getActions(); List actionsWhenCollapsed = data.getActionsToShowInCompact(); - // If we got session actions, use those instead - if (data.getSemanticActions() != null) { + // If the session actions flag is enabled, but we're still using the regular layout, use + // the session actions anyways + if (mMediaFlags.areMediaSessionActionsEnabled() && data.getSemanticActions() != null) { MediaButton semanticActions = data.getSemanticActions(); actionIcons = new ArrayList(); diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index ea92abd27e977..9e14fe91f21d5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -610,8 +610,7 @@ class MediaDataManager( var actionIcons: List = emptyList() var actionsToShowCollapsed: List = emptyList() var semanticActions: MediaButton? = null - if (mediaFlags.areMediaSessionActionsEnabled(sbn.packageName, sbn.user.identifier) && - mediaController.playbackState != null) { + if (mediaFlags.areMediaSessionActionsEnabled() && mediaController.playbackState != null) { semanticActions = createActionsFromState(sbn.packageName, mediaController) } else { val actions = createActionsFromNotification(sbn) @@ -727,7 +726,7 @@ class MediaDataManager( } } - // Finally, assign the remaining button slots: play/pause A B C D + // Finally, assign the remaining button slots: C A play/pause B D // A = previous, else custom action (if not reserved) // B = next, else custom action (if not reserved) // C and D are always custom actions diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt index f5200f9c8c93f..dd35a9a813996 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt @@ -16,7 +16,6 @@ package com.android.systemui.media -import android.app.StatusBarManager import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags @@ -27,17 +26,16 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) { /** * Check whether media control actions should be based on PlaybackState instead of notification */ - fun areMediaSessionActionsEnabled(packageName: String, userId: Int): Boolean { - val enabled = StatusBarManager.useMediaSessionActionsForApp(packageName, userId) - // Allow global override with flag - return enabled || featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS) + fun areMediaSessionActionsEnabled(): Boolean { + return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS) } /** * Check whether media controls should use the new session-based layout */ fun useMediaSessionLayout(): Boolean { - return featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT) + return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS) && + featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT) } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt index daf81bdc6e822..dcbe0ab96dac3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt @@ -37,6 +37,7 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.MockitoAnnotations import javax.inject.Provider +import org.mockito.Mockito.`when` as whenever private val DATA = MediaData( userId = -1, @@ -82,6 +83,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Before fun setup() { MockitoAnnotations.initMocks(this) + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true) mediaCarouselController = MediaCarouselController( context, mediaControlPanelFactory, diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 90eff1ae9804e..cb68d81287dff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -101,6 +101,7 @@ public class MediaControlPanelTest : SysuiTestCase() { @Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory @Mock private lateinit var mediaCarouselController: MediaCarouselController @Mock private lateinit var falsingManager: FalsingManager + @Mock private lateinit var mediaFlags: MediaFlags private lateinit var appIcon: ImageView private lateinit var albumView: ImageView private lateinit var titleText: TextView @@ -146,7 +147,7 @@ public class MediaControlPanelTest : SysuiTestCase() { player = MediaControlPanel(context, bgExecutor, activityStarter, broadcastSender, mediaViewController, seekBarViewModel, Lazy { mediaDataManager }, - mediaOutputDialogFactory, mediaCarouselController, falsingManager, clock) + mediaOutputDialogFactory, mediaCarouselController, falsingManager, mediaFlags, clock) whenever(seekBarViewModel.progress).thenReturn(seekBarData) // Set up mock views for the players @@ -214,6 +215,9 @@ public class MediaControlPanelTest : SysuiTestCase() { device = device, active = true, resumeAction = null) + + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false) + whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false) } /** @@ -291,6 +295,9 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindSemanticActionsOldLayout() { + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true) + whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false) + val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play) val semanticActions = MediaButton( playOrPause = MediaAction(icon, Runnable {}, "play"), @@ -325,6 +332,9 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindSemanticActionsNewLayout() { + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true) + whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true) + val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play) val semanticActions = MediaButton( playOrPause = MediaAction(icon, Runnable {}, "play"), @@ -371,6 +381,9 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindNotificationActionsNewLayout() { + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true) + whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true) + val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play) val actions = listOf( MediaAction(icon, Runnable {}, "previous"), diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index be2450d11c081..925ae30e87733 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -26,7 +26,6 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.SbnBuilder import com.android.systemui.tuner.TunerService import com.android.systemui.util.concurrency.FakeExecutor -import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock @@ -38,7 +37,6 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyInt import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito @@ -169,7 +167,7 @@ class MediaDataManagerTest : SysuiTestCase() { whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA) whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf(mediaRecommendationItem)) whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L) - whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(false) + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false) } @After @@ -596,7 +594,7 @@ class MediaDataManagerTest : SysuiTestCase() { @Test fun testPlaybackActions_noState_usesNotification() { val desc = "Notification Action" - whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(true) + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true) whenever(controller.playbackState).thenReturn(null) val notifWithAction = SbnBuilder().run { @@ -623,7 +621,7 @@ class MediaDataManagerTest : SysuiTestCase() { @Test fun testPlaybackActions_hasPrevNext() { val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4") - whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(true) + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true) val stateActions = PlaybackState.ACTION_PLAY or PlaybackState.ACTION_SKIP_TO_PREVIOUS or PlaybackState.ACTION_SKIP_TO_NEXT @@ -671,7 +669,7 @@ class MediaDataManagerTest : SysuiTestCase() { @Test fun testPlaybackActions_noPrevNext_usesCustom() { val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4", "custom 5") - whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(true) + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true) val stateActions = PlaybackState.ACTION_PLAY val stateBuilder = PlaybackState.Builder() .setActions(stateActions) @@ -709,7 +707,7 @@ class MediaDataManagerTest : SysuiTestCase() { @Test fun testPlaybackActions_reservedSpace() { val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4") - whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(true) + whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true) val stateActions = PlaybackState.ACTION_PLAY val stateBuilder = PlaybackState.Builder() .setActions(stateActions)