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

Commit a88fd507 authored by Michael Mikhail's avatar Michael Mikhail
Browse files

Run inflations of UMO in a background thread

In order to reduce the latency when configuration changes, we use a
background thread.

Bug: 269224904
Test: atest MediaCarouselControllerTest
Change-Id: Ib7b10c90325cfe6cf589ab8195ac87e02149283c
parent 55940174
Loading
Loading
Loading
Loading
+58 −47
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -68,6 +69,7 @@ import com.android.systemui.util.time.SystemClock
import com.android.systemui.util.traceSection
import java.io.PrintWriter
import java.util.TreeMap
import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
@@ -93,7 +95,8 @@ constructor(
    private val mediaHostStatesManager: MediaHostStatesManager,
    private val activityStarter: ActivityStarter,
    private val systemClock: SystemClock,
    @Main executor: DelayableExecutor,
    @Main private val mainExecutor: DelayableExecutor,
    @Background private val backgroundExecutor: Executor,
    private val mediaManager: MediaDataManager,
    configurationController: ConfigurationController,
    falsingCollector: FalsingCollector,
@@ -256,7 +259,7 @@ constructor(
            MediaCarouselScrollHandler(
                mediaCarousel,
                pageIndicator,
                executor,
                mainExecutor,
                this::onSwipeToDismiss,
                this::updatePageIndicatorLocation,
                this::updateSeekbarListening,
@@ -618,10 +621,50 @@ constructor(
                MediaPlayerData.visiblePlayerKeys()
                    .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
            if (existingPlayer == null) {
                val newPlayer = mediaControlPanelFactory.get()
                newPlayer.attachPlayer(
                    MediaViewHolder.create(LayoutInflater.from(context), mediaContent)
                setupNewPlayer(key, data, isSsReactivated, curVisibleMediaKey)
            } else {
                existingPlayer.bindPlayer(data, key)
                MediaPlayerData.addMediaPlayer(
                    key,
                    data,
                    existingPlayer,
                    systemClock,
                    isSsReactivated,
                    debugLogger
                )
                val packageName = MediaPlayerData.smartspaceMediaData?.packageName ?: String()
                // In case of recommendations hits.
                // Check the playing status of media player and the package name.
                // To make sure we scroll to the right app's media player.
                if (
                    isReorderingAllowed ||
                        shouldScrollToKey &&
                            data.isPlaying == true &&
                            packageName == data.packageName
                ) {
                    reorderAllPlayers(curVisibleMediaKey, key)
                } else {
                    needsReordering = true
                }
                updatePageIndicator()
                mediaCarouselScrollHandler.onPlayersChanged()
                mediaFrame.requiresRemeasuring = true
            }
            return existingPlayer == null
        }

    private fun setupNewPlayer(
        key: String,
        data: MediaData,
        isSsReactivated: Boolean,
        curVisibleMediaKey: MediaPlayerData.MediaSortKey?,
    ) {
        backgroundExecutor.execute {
            val mediaViewHolder = createMediaViewHolderInBg()
            // Add the new player in the main thread.
            mainExecutor.execute {
                val newPlayer = mediaControlPanelFactory.get()
                newPlayer.attachPlayer(mediaViewHolder)
                newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
                val lp =
                    LinearLayout.LayoutParams(
@@ -651,35 +694,15 @@ constructor(
                } else {
                    needsReordering = true
                }
            } else {
                existingPlayer.bindPlayer(data, key)
                MediaPlayerData.addMediaPlayer(
                    key,
                    data,
                    existingPlayer,
                    systemClock,
                    isSsReactivated,
                    debugLogger
                )
                val packageName = MediaPlayerData.smartspaceMediaData?.packageName ?: String()
                // In case of recommendations hits.
                // Check the playing status of media player and the package name.
                // To make sure we scroll to the right app's media player.
                if (
                    isReorderingAllowed ||
                        shouldScrollToKey &&
                            data.isPlaying == true &&
                            packageName == data.packageName
                ) {
                    reorderAllPlayers(curVisibleMediaKey, key)
                } else {
                    needsReordering = true
                }
            }
                updatePageIndicator()
                mediaCarouselScrollHandler.onPlayersChanged()
                mediaFrame.requiresRemeasuring = true
            return existingPlayer == null
            }
        }
    }

    private fun createMediaViewHolderInBg(): MediaViewHolder {
        return MediaViewHolder.create(LayoutInflater.from(context), mediaContent)
    }

    private fun addSmartspaceMediaRecommendations(
@@ -714,15 +737,14 @@ constructor(
                    debugLogger.logPotentialMemoryLeak(existingSmartspaceMediaKey)
                }
            }

            val newRecs = mediaControlPanelFactory.get()
            newRecs.attachRecommendation(
            val recommendationViewHolder =
                RecommendationViewHolder.create(
                    LayoutInflater.from(context),
                    mediaContent,
                    mediaFlags.isRecommendationCardUpdateEnabled()
                )
            )
            newRecs.attachRecommendation(recommendationViewHolder)
            newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
            val lp =
                LinearLayout.LayoutParams(
@@ -746,17 +768,6 @@ constructor(
            reorderAllPlayers(curVisibleMediaKey)
            updatePageIndicator()
            mediaFrame.requiresRemeasuring = true
            // Check postcondition: mediaContent should have the same number of children as there
            // are
            // elements in mediaPlayers.
            if (MediaPlayerData.players().size != mediaContent.childCount) {
                Log.e(
                    TAG,
                    "Size of players list and number of views in carousel are out of sync. " +
                        "Players size is ${MediaPlayerData.players().size}. " +
                        "View count is ${mediaContent.childCount}."
                )
            }
        }

    fun removePlayer(
+114 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.media.controls.ui

import android.app.PendingIntent
import android.content.res.ColorStateList
import android.content.res.Configuration
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -26,9 +27,9 @@ import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -49,7 +50,7 @@ import com.android.systemui.qs.PageIndicator
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
@@ -89,7 +90,6 @@ class MediaCarouselControllerTest : SysuiTestCase() {
    @Mock lateinit var mediaHostStatesManager: MediaHostStatesManager
    @Mock lateinit var mediaHostState: MediaHostState
    @Mock lateinit var activityStarter: ActivityStarter
    @Mock @Main private lateinit var executor: DelayableExecutor
    @Mock lateinit var mediaDataManager: MediaDataManager
    @Mock lateinit var configurationController: ConfigurationController
    @Mock lateinit var falsingCollector: FalsingCollector
@@ -113,11 +113,15 @@ class MediaCarouselControllerTest : SysuiTestCase() {

    private val clock = FakeSystemClock()
    private lateinit var mediaCarouselController: MediaCarouselController
    private lateinit var mainExecutor: FakeExecutor
    private lateinit var backgroundExecutor: FakeExecutor

    @Before
    fun setup() {
        MockitoAnnotations.initMocks(this)
        transitionRepository = FakeKeyguardTransitionRepository()
        mainExecutor = FakeExecutor(clock)
        backgroundExecutor = FakeExecutor(clock)
        mediaCarouselController =
            MediaCarouselController(
                context,
@@ -126,7 +130,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {
                mediaHostStatesManager,
                activityStarter,
                clock,
                executor,
                mainExecutor,
                backgroundExecutor,
                mediaDataManager,
                configurationController,
                falsingCollector,
@@ -401,6 +406,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
                resumption = true
            )
        )
        runAllReady()

        assertEquals(
            MediaPlayerData.getMediaPlayerIndex("paused local"),
@@ -510,6 +516,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {
            false
        )
        mediaCarouselController.shouldScrollToKey = true
        runAllReady()

        // switching between media players.
        listener.value.onMediaDataLoaded(
            "playing local",
@@ -531,6 +539,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
                resumption = false
            )
        )
        runAllReady()

        assertEquals(
            MediaPlayerData.getMediaPlayerIndex("paused local"),
@@ -555,6 +564,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
                resumption = false
            )
        )
        runAllReady()

        var playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
        assertEquals(
@@ -577,6 +587,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {
                packageName = "PACKAGE_NAME"
            )
        )
        runAllReady()

        playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
        assertEquals(playerIndex, 0)
    }
@@ -674,6 +686,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {

    @Test
    fun testOnConfigChanged_playersAreAddedBack() {
        mediaCarouselController.pageIndicator = pageIndicator

        listener.value.onMediaDataLoaded(
            "playing local",
            null,
@@ -694,11 +708,15 @@ class MediaCarouselControllerTest : SysuiTestCase() {
                resumption = false
            )
        )
        runAllReady()

        val playersSize = MediaPlayerData.players().size

        configListener.value.onConfigChanged(Configuration())
        runAllReady()

        verify(pageIndicator).tintList =
            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
        assertEquals(playersSize, MediaPlayerData.players().size)
        assertEquals(
            MediaPlayerData.getMediaPlayerIndex("playing local"),
@@ -706,6 +724,93 @@ class MediaCarouselControllerTest : SysuiTestCase() {
        )
    }

    @Test
    fun testOnUiModeChanged_playersAreAddedBack() {
        mediaCarouselController.pageIndicator = pageIndicator

        listener.value.onMediaDataLoaded(
            "paused local",
            null,
            DATA.copy(
                active = true,
                isPlaying = false,
                playbackLocation = MediaData.PLAYBACK_LOCAL,
                resumption = false
            )
        )
        runAllReady()

        val playersSize = MediaPlayerData.players().size
        configListener.value.onUiModeChanged()
        runAllReady()

        verify(pageIndicator).tintList =
            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
        assertEquals(playersSize, MediaPlayerData.players().size)
        assertEquals(
            MediaPlayerData.getMediaPlayerIndex("paused local"),
            mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
        )
    }

    @Test
    fun testOnDensityOrFontScaleChanged_playersAreAddedBack() {
        mediaCarouselController.pageIndicator = pageIndicator

        listener.value.onMediaDataLoaded(
            "paused local",
            null,
            DATA.copy(
                active = true,
                isPlaying = false,
                playbackLocation = MediaData.PLAYBACK_LOCAL,
                resumption = false
            )
        )
        runAllReady()

        val playersSize = MediaPlayerData.players().size
        configListener.value.onDensityOrFontScaleChanged()
        runAllReady()

        verify(pageIndicator).tintList =
            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
        assertEquals(playersSize, MediaPlayerData.players().size)
        assertEquals(
            MediaPlayerData.getMediaPlayerIndex("paused local"),
            mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
        )
    }

    @Test
    fun testOnThemeChanged_playersAreAddedBack() {
        mediaCarouselController.pageIndicator = pageIndicator

        listener.value.onMediaDataLoaded(
            "paused local",
            null,
            DATA.copy(
                active = true,
                isPlaying = false,
                playbackLocation = MediaData.PLAYBACK_LOCAL,
                resumption = false
            )
        )
        runAllReady()

        val playersSize = MediaPlayerData.players().size
        configListener.value.onThemeChanged()
        runAllReady()

        verify(pageIndicator).tintList =
            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
        assertEquals(playersSize, MediaPlayerData.players().size)
        assertEquals(
            MediaPlayerData.getMediaPlayerIndex("paused local"),
            mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
        )
    }

    @Test
    fun testRecommendation_persistentEnabled_newSmartspaceLoaded_updatesSort() {
        testRecommendation_persistentEnabled_inactiveSmartspaceDataLoaded_isAdded()
@@ -832,4 +937,9 @@ class MediaCarouselControllerTest : SysuiTestCase() {
        // Verify that seekbar listening attribute in media control panel is set to false.
        verify(panel, times(MediaPlayerData.players().size)).listening = false
    }

    private fun runAllReady() {
        backgroundExecutor.runAllReady()
        mainExecutor.runAllReady()
    }
}