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

Commit 01c53614 authored by Cecilia Hong's avatar Cecilia Hong Committed by Android (Google) Code Review
Browse files

Merge "Always show media recommendation on headphones connection." into sc-dev

parents 12643671 9cbca1a6
Loading
Loading
Loading
Loading
+19 −8
Original line number Diff line number Diff line
@@ -208,9 +208,13 @@ class MediaCarouselController @Inject constructor(
                }
            }

            override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
            override fun onSmartspaceMediaDataLoaded(
                key: String,
                data: SmartspaceTarget,
                shouldPrioritize: Boolean
            ) {
                Log.d(TAG, "My Smartspace media update is here")
                addSmartspaceMediaRecommendations(key, data)
                addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
                MediaPlayerData.getMediaPlayer(key, null)?.let {
                    logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
                            it.mInstanceId,
@@ -327,7 +331,11 @@ class MediaCarouselController @Inject constructor(
        return existingPlayer == null
    }

    private fun addSmartspaceMediaRecommendations(key: String, data: SmartspaceTarget) {
    private fun addSmartspaceMediaRecommendations(
        key: String,
        data: SmartspaceTarget,
        shouldPrioritize: Boolean
    ) {
        Log.d(TAG, "Updating smartspace target in carousel")
        if (MediaPlayerData.getMediaPlayer(key, null) != null) {
            Log.w(TAG, "Skip adding smartspace target in carousel")
@@ -342,7 +350,7 @@ class MediaCarouselController @Inject constructor(
            ViewGroup.LayoutParams.WRAP_CONTENT)
        newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
        newRecs.bindRecommendation(data, bgColor)
        MediaPlayerData.addMediaRecommendation(key, newRecs)
        MediaPlayerData.addMediaRecommendation(key, newRecs, shouldPrioritize)
        updatePlayerToState(newRecs, noAnimation = true)
        reorderAllPlayers()
        updatePageIndicator()
@@ -671,17 +679,19 @@ class MediaCarouselController @Inject constructor(
internal object MediaPlayerData {
    private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null,
        emptyList(), emptyList(), "INVALID", null, null, null, true, null)
    // Whether should prioritize Smartspace card.
    private var shouldPrioritizeSs: Boolean = false

    data class MediaSortKey(
        // Is Smartspace media recommendation. When the Smartspace media is present, it should
        // always be the first card in carousel.
        // Whether the item represents a Smartspace media recommendation.
        val isSsMediaRec: Boolean,
        val data: MediaData,
        val updateTime: Long = 0
    )

    private val comparator =
        compareByDescending<MediaSortKey> { it.isSsMediaRec }
        compareByDescending<MediaSortKey>
            { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
            .thenByDescending { it.data.isPlaying }
            .thenByDescending { it.data.isLocalSession }
            .thenByDescending { !it.data.resumption }
@@ -697,7 +707,8 @@ internal object MediaPlayerData {
        mediaPlayers.put(sortKey, player)
    }

    fun addMediaRecommendation(key: String, player: MediaControlPanel) {
    fun addMediaRecommendation(key: String, player: MediaControlPanel, shouldPrioritize: Boolean) {
        shouldPrioritizeSs = shouldPrioritize
        removeMediaPlayer(key)
        val sortKey = MediaSortKey(isSsMediaRec = true, EMPTY, System.currentTimeMillis())
        mediaData.put(key, sortKey)
+5 −1
Original line number Diff line number Diff line
@@ -38,7 +38,11 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
        }
    }

    override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
    override fun onSmartspaceMediaDataLoaded(
        key: String,
        data: SmartspaceTarget,
        shouldPrioritize: Boolean
    ) {
        listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, data) }
    }

+46 −22
Original line number Diff line number Diff line
@@ -26,9 +26,11 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.util.time.SystemClock
import java.util.SortedMap
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.collections.LinkedHashMap

private const val TAG = "MediaDataFilter"
private const val DEBUG = true
@@ -39,7 +41,7 @@ private const val DEBUG = true
 */
@VisibleForTesting
internal val SMARTSPACE_MAX_AGE = SystemProperties
        .getLong("debug.sysui.smartspace_max_age", TimeUnit.HOURS.toMillis(3))
        .getLong("debug.sysui.smartspace_max_age", TimeUnit.MINUTES.toMillis(30))

/**
 * Filters data updates from [MediaDataCombineLatest] based on the current user ID, and handles user
@@ -65,7 +67,8 @@ class MediaDataFilter @Inject constructor(
    private val allEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
    // The filtered userEntries, which will be a subset of all userEntries in MediaDataManager
    private val userEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
    private var hasSmartspace: Boolean = false
    var hasSmartspace: Boolean = false
        private set
    private var reactivatedKey: String? = null

    init {
@@ -99,20 +102,21 @@ class MediaDataFilter @Inject constructor(
        }
    }

    override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
    override fun onSmartspaceMediaDataLoaded(
        key: String,
        data: SmartspaceTarget,
        shouldPrioritize: Boolean
    ) {
        var shouldPrioritizeMutable = shouldPrioritize
        hasSmartspace = true

        // Before forwarding the smartspace target, first check if we have recently inactive media
        val now = systemClock.elapsedRealtime()
        val sorted = userEntries.toSortedMap(compareBy {
            userEntries.get(it)?.lastActive ?: -1
        })
        if (sorted.size > 0) {
            val lastActiveKey = sorted.lastKey() // most recently active
            val timeSinceActive = sorted.get(lastActiveKey)?.let {
                now - it.lastActive
            } ?: Long.MAX_VALUE
        val timeSinceActive = timeSinceActiveForMostRecentMedia(sorted)
        if (timeSinceActive < SMARTSPACE_MAX_AGE) {
            val lastActiveKey = sorted.lastKey() // most recently active
            // Notify listeners to consider this media active
            Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
            reactivatedKey = lastActiveKey
@@ -120,18 +124,17 @@ class MediaDataFilter @Inject constructor(
            listeners.forEach {
                it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData)
            }
                return
            }
        } else {
            // Mark to prioritize Smartspace card if no recent media.
            shouldPrioritizeMutable = true
        }

        // If no recent media, continue with smartspace update
        // Only proceed with the Smartspace update if the recommendation is not empty.
        if (isMediaRecommendationEmpty(data)) {
            Log.d(TAG, "Empty media recommendations. Skip showing the card")
            return
        }

        // Proceed only if the Smartspace recommendation is not empty.
        listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data) }
        listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable) }
    }

    override fun onMediaDataRemoved(key: String) {
@@ -158,7 +161,6 @@ class MediaDataFilter @Inject constructor(
                    it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData)
                }
            }
            return
        }

        listeners.forEach { it.onSmartspaceMediaDataRemoved(key) }
@@ -230,4 +232,26 @@ class MediaDataFilter @Inject constructor(
        val mediaRecommendationList: List<SmartspaceAction> = data.getIconGrid()
        return mediaRecommendationList == null || mediaRecommendationList.isEmpty()
    }

    /**
     * Return the time since last active for the most-recent media.
     *
     * @param sortedEntries userEntries sorted from the earliest to the most-recent.
     *
     * @return The duration in milliseconds from the most-recent media's last active timestamp to
     * the present. MAX_VALUE will be returned if there is no media.
     */
    private fun timeSinceActiveForMostRecentMedia(
        sortedEntries: SortedMap<String, MediaData>
    ): Long {
        if (sortedEntries.isEmpty()) {
            return Long.MAX_VALUE
        }

        val now = systemClock.elapsedRealtime()
        val lastActiveKey = sortedEntries.lastKey() // most recently active
        return sortedEntries.get(lastActiveKey)?.let {
            now - it.lastActive
        } ?: Long.MAX_VALUE
    }
}
+11 −2
Original line number Diff line number Diff line
@@ -817,8 +817,17 @@ class MediaDataManager(
         */
        fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {}

        /** Called whenever there's new Smartspace media data loaded. */
        fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {}
        /**
         * Called whenever there's new Smartspace media data loaded.
         *
         * shouldPrioritize indicates the sorting priority of the Smartspace card. If true, it will
         * be prioritized as the first card. Otherwise, it will show up as the last card as default.
         */
        fun onSmartspaceMediaDataLoaded(
            key: String,
            data: SmartspaceTarget,
            shouldPrioritize: Boolean = false
        ) {}

        /**
         * Called whenever a previously existing Media notification was removed
+5 −1
Original line number Diff line number Diff line
@@ -56,7 +56,11 @@ class MediaHost constructor(
            updateViewVisibility()
        }

        override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
        override fun onSmartspaceMediaDataLoaded(
            key: String,
            data: SmartspaceTarget,
            shouldPrioritize: Boolean
        ) {
            updateViewVisibility()
        }

Loading