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

Commit 887bbeda authored by Cecilia Hong's avatar Cecilia Hong Committed by Automerger Merge Worker
Browse files

Merge "Always show media recommendation on headphones connection." into sc-dev am: 01c53614

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14525326

Change-Id: Ic9f1e3649a388aa24fe20cd90f1afb7b2aa713a6
parents 34780b9e 01c53614
Loading
Loading
Loading
Loading
+19 −8
Original line number Original line 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")
                Log.d(TAG, "My Smartspace media update is here")
                addSmartspaceMediaRecommendations(key, data)
                addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
                MediaPlayerData.getMediaPlayer(key, null)?.let {
                MediaPlayerData.getMediaPlayer(key, null)?.let {
                    logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
                    logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
                            it.mInstanceId,
                            it.mInstanceId,
@@ -327,7 +331,11 @@ class MediaCarouselController @Inject constructor(
        return existingPlayer == null
        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")
        Log.d(TAG, "Updating smartspace target in carousel")
        if (MediaPlayerData.getMediaPlayer(key, null) != null) {
        if (MediaPlayerData.getMediaPlayer(key, null) != null) {
            Log.w(TAG, "Skip adding smartspace target in carousel")
            Log.w(TAG, "Skip adding smartspace target in carousel")
@@ -342,7 +350,7 @@ class MediaCarouselController @Inject constructor(
            ViewGroup.LayoutParams.WRAP_CONTENT)
            ViewGroup.LayoutParams.WRAP_CONTENT)
        newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
        newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
        newRecs.bindRecommendation(data, bgColor)
        newRecs.bindRecommendation(data, bgColor)
        MediaPlayerData.addMediaRecommendation(key, newRecs)
        MediaPlayerData.addMediaRecommendation(key, newRecs, shouldPrioritize)
        updatePlayerToState(newRecs, noAnimation = true)
        updatePlayerToState(newRecs, noAnimation = true)
        reorderAllPlayers()
        reorderAllPlayers()
        updatePageIndicator()
        updatePageIndicator()
@@ -671,17 +679,19 @@ class MediaCarouselController @Inject constructor(
internal object MediaPlayerData {
internal object MediaPlayerData {
    private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null,
    private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null,
        emptyList(), emptyList(), "INVALID", null, null, null, true, null)
        emptyList(), emptyList(), "INVALID", null, null, null, true, null)
    // Whether should prioritize Smartspace card.
    private var shouldPrioritizeSs: Boolean = false


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


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


    fun addMediaRecommendation(key: String, player: MediaControlPanel) {
    fun addMediaRecommendation(key: String, player: MediaControlPanel, shouldPrioritize: Boolean) {
        shouldPrioritizeSs = shouldPrioritize
        removeMediaPlayer(key)
        removeMediaPlayer(key)
        val sortKey = MediaSortKey(isSsMediaRec = true, EMPTY, System.currentTimeMillis())
        val sortKey = MediaSortKey(isSsMediaRec = true, EMPTY, System.currentTimeMillis())
        mediaData.put(key, sortKey)
        mediaData.put(key, sortKey)
+5 −1
Original line number Original line 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) }
        listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, data) }
    }
    }


+46 −22
Original line number Original line 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.settings.CurrentUserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.util.time.SystemClock
import com.android.systemui.util.time.SystemClock
import java.util.SortedMap
import java.util.concurrent.Executor
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Inject
import kotlin.collections.LinkedHashMap


private const val TAG = "MediaDataFilter"
private const val TAG = "MediaDataFilter"
private const val DEBUG = true
private const val DEBUG = true
@@ -39,7 +41,7 @@ private const val DEBUG = true
 */
 */
@VisibleForTesting
@VisibleForTesting
internal val SMARTSPACE_MAX_AGE = SystemProperties
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
 * 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()
    private val allEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
    // The filtered userEntries, which will be a subset of all userEntries in MediaDataManager
    // The filtered userEntries, which will be a subset of all userEntries in MediaDataManager
    private val userEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
    private val userEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
    private var hasSmartspace: Boolean = false
    var hasSmartspace: Boolean = false
        private set
    private var reactivatedKey: String? = null
    private var reactivatedKey: String? = null


    init {
    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
        hasSmartspace = true


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

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


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


        listeners.forEach { it.onSmartspaceMediaDataRemoved(key) }
        listeners.forEach { it.onSmartspaceMediaDataRemoved(key) }
@@ -230,4 +232,26 @@ class MediaDataFilter @Inject constructor(
        val mediaRecommendationList: List<SmartspaceAction> = data.getIconGrid()
        val mediaRecommendationList: List<SmartspaceAction> = data.getIconGrid()
        return mediaRecommendationList == null || mediaRecommendationList.isEmpty()
        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 Original line Diff line number Diff line
@@ -817,8 +817,17 @@ class MediaDataManager(
         */
         */
        fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {}
        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
         * Called whenever a previously existing Media notification was removed
+5 −1
Original line number Original line Diff line number Diff line
@@ -56,7 +56,11 @@ class MediaHost constructor(
            updateViewVisibility()
            updateViewVisibility()
        }
        }


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


Loading