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

Commit 6c18b5c3 authored by Etienne Ruffieux's avatar Etienne Ruffieux
Browse files

Fill AVRCP queue Metadata with MediaController Metadata

When retrieving the Media metadata using
MediaSession#QueueItem, we can loose some information such
as media duration. To prevent this, we need to add to the
the stored QueueItem metadata the data retrieved from the
MediaController for the current playing media.

Now that the other media metadata is available for current
media QueueItem, we also need to update the equals overload
of the Metadata class to reflect these changes.

Modified and added tests accordingly.

Bug: 235637427
Tag: #feature
Test: MediaPlayerWrapperTest
Change-Id: Iefc7de8767ffab8fa14f9cf1f120ef4804791cd1
parent c2d30b8e
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -131,6 +131,23 @@ public class MediaPlayerWrapper {
    }

    List<Metadata> getCurrentQueue() {
        // MediaSession#QueueItem's MediaDescription doesn't necessarily include media duration,
        // so the playing media info metadata should be obtained by the MediaController.
        // MediaSession doesn't include the Playlist Metadata, only the current song one.
        Metadata mediaPlayingMetadata = getCurrentMetadata();

        // The queue metadata is built with QueueId in place of MediaId, so we can't compare it.
        // MediaDescription is usually compared via its title, artist and album.
        if (mediaPlayingMetadata != null) {
            for (Metadata metadata : mCurrentData.queue) {
                if (metadata.title.equals(mediaPlayingMetadata.title)
                        && metadata.artist.equals(mediaPlayingMetadata.artist)
                        && metadata.album.equals(mediaPlayingMetadata.album)) {
                    // Replace default values by MediaController non default values.
                    metadata.replaceDefaults(mediaPlayingMetadata);
                }
            }
        }
        return mCurrentData.queue;
    }

+47 −0
Original line number Diff line number Diff line
@@ -64,6 +64,14 @@ public class Metadata implements Cloneable {
        if (!Objects.equals(album, m.album)) return false;
        if (!Objects.equals(trackNum, m.trackNum)) return false;
        if (!Objects.equals(numTracks, m.numTracks)) return false;
        if (!Objects.equals(genre, m.genre)) return false;
        if (!Objects.equals(duration, m.duration)) return false;
        // Actual image comparisons have shown to be very expensive. Since it's rare that
        // an application changes the cover artwork between multiple images once it's not
        // null anymore, we just look for changes between "something" and "nothing".
        if ((image == null && m.image != null) || (image != null && m.image == null)) {
            return false;
        }
        return true;
    }

@@ -80,6 +88,45 @@ public class Metadata implements Cloneable {
                + " trackPosition=" + trackNum + "/" + numTracks + " image=" + image + " }";
    }

    /**
     * Replaces default values by {@code filledMetadata} non default values.
     */
    public void replaceDefaults(Metadata filledMetadata) {
        if (filledMetadata == null) {
            return;
        }

        Metadata empty = Util.empty_data();

        if (empty.mediaId.equals(mediaId)) {
            mediaId = filledMetadata.mediaId;
        }
        if (empty.title.equals(title)) {
            title = filledMetadata.title;
        }
        if (empty.artist.equals(artist)) {
            artist = filledMetadata.artist;
        }
        if (empty.album.equals(album)) {
            album = filledMetadata.album;
        }
        if (empty.trackNum.equals(trackNum)) {
            trackNum = filledMetadata.trackNum;
        }
        if (empty.numTracks.equals(numTracks)) {
            numTracks = filledMetadata.numTracks;
        }
        if (empty.genre.equals(genre)) {
            genre = filledMetadata.genre;
        }
        if (empty.duration.equals(duration)) {
            duration = filledMetadata.duration;
        }
        if (image == null) {
            image = filledMetadata.image;
        }
    }

    /**
     * A Builder object to populate a Metadata from various different Media Framework objects
     */
+29 −2
Original line number Diff line number Diff line
@@ -412,17 +412,44 @@ public class MediaPlayerWrapperTest {
                MediaPlayerWrapperFactory.wrap(mMockContext, mMockController, mThread.getLooper());
        wrapper.registerCallback(mTestCbs);

        // Remove the current metadata so it does not override the default duration.
        doReturn(null).when(mMockController).getMetadata();

        // Call getCurrentQueue() multiple times.
        for (int i = 0; i < 3; i++) {
            Assert.assertEquals(wrapper.getCurrentQueue(),
                    Util.toMetadataList(mMockContext, getQueueFromDescriptions(mTestQueue)));
            Assert.assertEquals(
                    Util.toMetadataList(mMockContext, getQueueFromDescriptions(mTestQueue)),
                    wrapper.getCurrentQueue());
        }

        doReturn(mTestMetadata.build()).when(mMockController).getMetadata();

        // Verify that getQueue() was only called twice. Once on creation and once during
        // registration
        verify(mMockController, times(2)).getQueue();
    }

    /*
     * This test checks if the currently playing song queue duration is completed
     * by the MediaController Metadata.
     */
    @Test
    public void testQueueMetadata() {
        MediaPlayerWrapper wrapper =
                MediaPlayerWrapperFactory.wrap(mMockContext, mMockController, mThread.getLooper());

        doReturn(null).when(mMockController).getMetadata();
        Assert.assertFalse(Util.toMetadata(mMockContext, mTestMetadata.build()).duration
                .equals(wrapper.getCurrentQueue().get(0).duration));
        doReturn(mTestMetadata.build()).when(mMockController).getMetadata();
        Assert.assertEquals(Util.toMetadata(mMockContext, mTestMetadata.build()).duration,
                wrapper.getCurrentQueue().get(0).duration);
        // The MediaController Metadata should still not be equal to the queue
        // as the track count is different and should not be overridden.
        Assert.assertFalse(Util.toMetadata(mMockContext, mTestMetadata.build())
                .equals(wrapper.getCurrentQueue().get(0)));
    }

    /*
     * This test sends repeated Playback State updates that only have a short
     * position update change to see if they get debounced.