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

Commit 5251999f authored by Derek Jedral's avatar Derek Jedral Committed by Android (Google) Code Review
Browse files

Merge "Notify routers when the suggestion space is visible" into main

parents b6ac14b3 09baf7f2
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.Mock
import org.mockito.Mockito.anyInt
@@ -61,6 +62,7 @@ class MediaCarouselScrollHandlerTest : SysuiTestCase() {
    @Mock lateinit var seekBarUpdateListener: (visibleToUser: Boolean) -> Unit
    @Mock lateinit var closeGuts: (immediate: Boolean) -> Unit
    @Mock lateinit var falsingManager: FalsingManager
    @Mock lateinit var onCarouselVisibleToUser: () -> Unit
    @Mock lateinit var logger: MediaUiEventLogger
    @Mock lateinit var contentContainer: ViewGroup
    @Mock lateinit var settingsButton: View
@@ -90,6 +92,7 @@ class MediaCarouselScrollHandlerTest : SysuiTestCase() {
                seekBarUpdateListener,
                closeGuts,
                falsingManager,
                onCarouselVisibleToUser,
                logger,
            )
        mediaCarouselScrollHandler.playerWidthPlusPadding = carouselWidth
@@ -248,6 +251,19 @@ class MediaCarouselScrollHandlerTest : SysuiTestCase() {
        verify(mediaCarousel, never()).animationTargetX = anyFloat()
    }

    @Test
    fun testCarouselScrollToNewIndex_onCarouselVisibleToUser() {
        setupMediaContainer(visibleIndex = 0)
        whenever(mediaCarousel.relativeScrollX).thenReturn(carouselWidth)
        mediaCarouselScrollHandler.visibleToUser = true
        val captor = ArgumentCaptor.forClass(View.OnScrollChangeListener::class.java)
        verify(mediaCarousel).setOnScrollChangeListener(captor.capture())

        captor.value.onScrollChange(null, 0, 0, 0, 0)

        verify(onCarouselVisibleToUser).invoke()
    }

    private fun setupMediaContainer(visibleIndex: Int, showsSettingsButton: Boolean = true) {
        whenever(contentContainer.childCount).thenReturn(2)
        val child1: View = mock()
+11 −6
Original line number Diff line number Diff line
@@ -204,6 +204,9 @@ constructor(
        private var started = false
        private var playbackType = PLAYBACK_TYPE_UNKNOWN
        private var playbackVolumeControlId: String? = null
        private val requestSuggestionRunnable = Runnable {
            bgExecutor.execute { localMediaManager.requestDeviceSuggestion() }
        }
        private var current: MediaDeviceData? = null
            set(value) {
                val sameWithoutIcon = value != null && value.equalsWithoutIcon(field)
@@ -213,9 +216,11 @@ constructor(
                }
            }

        private var suggestionData: SuggestionData? = null
        private var suggestionData =
            SuggestionData(onSuggestionSpaceVisible = requestSuggestionRunnable)
            set(value) {
                if (field != value) {
                val sameWithoutConnect = value.equalsWithoutConnect(field)
                if (!sameWithoutConnect) {
                    field = value
                    fgExecutor.execute { processSuggestionData(key, oldKey, value) }
                }
@@ -238,6 +243,9 @@ constructor(
                if (!started) {
                    // Fetch in case a suggestion already exists before registering for suggestions
                    localMediaManager.registerCallback(this)
                    if (enableSuggestedDeviceUi()) {
                        onSuggestedDeviceUpdated(localMediaManager.getSuggestedDevice())
                    }
                    if (!Flags.removeUnnecessaryRouteScanning()) {
                        localMediaManager.startScan()
                    }
@@ -320,10 +328,7 @@ constructor(
                                    connect = { localMediaManager.connectSuggestedDevice(it) },
                                )
                            },
                        onSuggestionSpaceVisible =
                            Runnable {
                                bgExecutor.execute { localMediaManager.requestDeviceSuggestion() }
                            },
                        onSuggestionSpaceVisible = requestSuggestionRunnable,
                    )
            }
        }
+32 −3
Original line number Diff line number Diff line
@@ -221,17 +221,46 @@ constructor(

    /** Action to invoke to transfer media playback to this device. */
    val connect: () -> Unit,
)
) {
    fun equalsWithoutConnect(other: SuggestedMediaDeviceData?): Boolean {
        if (other == null) {
            return false
        }

        return name == other.name && connectionState == other.connectionState && icon == other.icon
    }
}

/** Wrapper for data needed to support suggestions in the media player. */
data class SuggestionData
constructor(
    /** The suggested device for playback. Null if no suggestion exists. */
    val suggestedMediaDeviceData: SuggestedMediaDeviceData?,
    val suggestedMediaDeviceData: SuggestedMediaDeviceData? = null,

    /**
     * Callback to be invoked when the area to surface the suggestion becomes visible. Suggestion
     * providers are notified of the visibility update and can provide suggestions.
     */
    val onSuggestionSpaceVisible: Runnable,
)
) {

    /**
     * Check whether [SuggestionData] objects are equal in all fields except the underlying connect
     * method, which can't be easily compared for equality, and is based on the underlying
     * suggestion anyway.
     */
    fun equalsWithoutConnect(other: SuggestionData?): Boolean {
        if (other == null) {
            return false
        }
        if (onSuggestionSpaceVisible != other.onSuggestionSpaceVisible) {
            return false
        }

        if (suggestedMediaDeviceData == null) {
            return other.suggestedMediaDeviceData == null
        }

        return suggestedMediaDeviceData.equalsWithoutConnect(other.suggestedMediaDeviceData)
    }
}
+13 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.Dumpable
import com.android.systemui.Flags
import com.android.systemui.Flags.enableSuggestedDeviceUi
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -352,6 +353,7 @@ constructor(
                this::updateSeekbarListening,
                this::closeGuts,
                falsingManager,
                this::onCarouselVisibleToUser,
                logger,
            )
        carouselLocale = context.resources.configuration.locales.get(0)
@@ -1214,6 +1216,17 @@ constructor(
        }
    }

    fun onCarouselVisibleToUser() {
        if (!enableSuggestedDeviceUi() || !mediaCarouselScrollHandler.visibleToUser) {
            return
        }
        val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex
        if (MediaPlayerData.players().size > visibleMediaIndex) {
            val mediaControlPanel = MediaPlayerData.getMediaControlPanel(visibleMediaIndex)
            mediaControlPanel?.onSuggestionSpaceVisible()
        }
    }

    @VisibleForTesting
    fun onSwipeToDismiss() {
        if (SceneContainerFlag.isEnabled) {
+15 −0
Original line number Diff line number Diff line
@@ -239,6 +239,7 @@ public class MediaControlPanel {
    private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig;
    private boolean mWasPlaying = false;
    private boolean mButtonClicked = false;
    @Nullable private Runnable mOnSuggestionSpaceVisibleRunnable = null;

    private final PaintDrawCallback mNoiseDrawCallback =
            new PaintDrawCallback() {
@@ -617,6 +618,19 @@ public class MediaControlPanel {
        Trace.endSection();
    }

    /**
     * Should be called when the space that holds device suggestions becomes visible to the user.
     */
    public void onSuggestionSpaceVisible() {
        if (!Flags.enableSuggestedDeviceUi()) {
            return;
        }
        @Nullable Runnable onSuggestionVisibleRunnable = mOnSuggestionSpaceVisibleRunnable;
        if (onSuggestionVisibleRunnable != null) {
            onSuggestionVisibleRunnable.run();
        }
    }

    private void bindDeviceSuggestion(@NonNull MediaData data) {
        if (!Flags.enableSuggestedDeviceUi()) {
            return;
@@ -625,6 +639,7 @@ public class MediaControlPanel {
        TextView deviceText = mMediaViewHolder.getSeamlessText();
        @Nullable SuggestionData suggestionData = data.getSuggestionData();
        if (suggestionData != null) {
            mOnSuggestionSpaceVisibleRunnable = suggestionData.getOnSuggestionSpaceVisible();
            @Nullable
            SuggestedMediaDeviceData suggestionDeviceData =
                    suggestionData.getSuggestedMediaDeviceData();
Loading