Loading packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +19 −8 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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") Loading @@ -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() Loading Loading @@ -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 } Loading @@ -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) Loading packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt +5 −1 Original line number Diff line number Diff line Loading @@ -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) } } Loading packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt +46 −22 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 { Loading Loading @@ -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 Loading @@ -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) { Loading @@ -158,7 +161,6 @@ class MediaDataFilter @Inject constructor( it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData) } } return } listeners.forEach { it.onSmartspaceMediaDataRemoved(key) } Loading Loading @@ -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 } } packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +11 −2 Original line number Diff line number Diff line Loading @@ -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 Loading packages/SystemUI/src/com/android/systemui/media/MediaHost.kt +5 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +19 −8 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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") Loading @@ -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() Loading Loading @@ -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 } Loading @@ -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) Loading
packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt +5 −1 Original line number Diff line number Diff line Loading @@ -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) } } Loading
packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt +46 −22 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 { Loading Loading @@ -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 Loading @@ -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) { Loading @@ -158,7 +161,6 @@ class MediaDataFilter @Inject constructor( it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData) } } return } listeners.forEach { it.onSmartspaceMediaDataRemoved(key) } Loading Loading @@ -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 } }
packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +11 −2 Original line number Diff line number Diff line Loading @@ -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 Loading
packages/SystemUI/src/com/android/systemui/media/MediaHost.kt +5 −1 Original line number Diff line number Diff line Loading @@ -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