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

Commit 9f897f56 authored by Beth Thibodeau's avatar Beth Thibodeau
Browse files

Prevent NPE issues when removing media

Instead of relying on notificationKey to be non-null, pass the key
explicitly when handling a removal

Fixes: 268663513
Test: atest MediaDataManagerTest
Change-Id: I2dfaa601b352a1fe626ade409db5527178822ecc
parent c0511060
Loading
Loading
Loading
Loading
+10 −8
Original line number Diff line number Diff line
@@ -1343,9 +1343,9 @@ class MediaDataManager(
        if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) {
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
        } else if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) {
            convertToResumePlayer(removed)
            convertToResumePlayer(key, removed)
        } else if (mediaFlags.isRetainingPlayersEnabled()) {
            handlePossibleRemoval(removed, notificationRemoved = true)
            handlePossibleRemoval(key, removed, notificationRemoved = true)
        } else {
            notifyMediaDataRemoved(key)
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
@@ -1359,7 +1359,7 @@ class MediaDataManager(
        val entry = mediaEntries.remove(key) ?: return
        // Clear token since the session is no longer valid
        val updated = entry.copy(token = null)
        handlePossibleRemoval(updated)
        handlePossibleRemoval(key, updated)
    }

    /**
@@ -1368,8 +1368,11 @@ class MediaDataManager(
     * if it was removed before becoming inactive. (Assumes that [removed] was removed from
     * [mediaEntries] before this function was called)
     */
    private fun handlePossibleRemoval(removed: MediaData, notificationRemoved: Boolean = false) {
        val key = removed.notificationKey!!
    private fun handlePossibleRemoval(
        key: String,
        removed: MediaData,
        notificationRemoved: Boolean = false
    ) {
        val hasSession = removed.token != null
        if (hasSession && removed.semanticActions != null) {
            // The app was using session actions, and the session is still valid: keep player
@@ -1395,13 +1398,12 @@ class MediaDataManager(
                        "($hasSession) gone for inactive player $key"
                )
            }
            convertToResumePlayer(removed)
            convertToResumePlayer(key, removed)
        }
    }

    /** Set the given [MediaData] as a resume state player and notify listeners */
    private fun convertToResumePlayer(data: MediaData) {
        val key = data.notificationKey!!
    private fun convertToResumePlayer(key: String, data: MediaData) {
        if (DEBUG) Log.d(TAG, "Converting $key to resume")
        // Move to resume key (aka package name) if that key doesn't already exist.
        val resumeAction = data.resumeAction?.let { getResumeMediaAction(it) }
+14 −0
Original line number Diff line number Diff line
@@ -1897,6 +1897,20 @@ class MediaDataManagerTest : SysuiTestCase() {
            .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
    }

    @Test
    fun testSessionDestroyed_noNotificationKey_stillRemoved() {
        whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)

        // When a notiifcation is added and then removed before it is fully processed
        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
        backgroundExecutor.runAllReady()
        mediaDataManager.onNotificationRemoved(KEY)

        // We still make sure to remove it
        verify(listener).onMediaDataRemoved(eq(KEY))
    }

    /** Helper function to add a media notification and capture the resulting MediaData */
    private fun addNotificationAndLoad() {
        mediaDataManager.onNotificationAdded(KEY, mediaNotification)