Twelve: Add picture type to thumbnail and add artwork data to MediaItem

Change-Id: I6a0fe3aacda771e3ec28c9c256acf86dbc38dbef
diff --git a/app/src/main/java/org/lineageos/twelve/datasources/LocalDataSource.kt b/app/src/main/java/org/lineageos/twelve/datasources/LocalDataSource.kt
index 3bdadd8..73dc995 100644
--- a/app/src/main/java/org/lineageos/twelve/datasources/LocalDataSource.kt
+++ b/app/src/main/java/org/lineageos/twelve/datasources/LocalDataSource.kt
@@ -70,7 +70,7 @@
                 uri, Size(512, 512), null
             )
         }.getOrNull()?.let {
-            Thumbnail(bitmap = it)
+            Thumbnail(bitmap = it, type = Thumbnail.Type.FRONT_COVER)
         }
 
         Album(
@@ -96,7 +96,7 @@
                 uri, Size(512, 512), null
             )
         }.getOrNull()?.let {
-            Thumbnail(bitmap = it)
+            Thumbnail(bitmap = it, type = Thumbnail.Type.BAND_ARTIST_LOGO)
         }
 
         Artist(
diff --git a/app/src/main/java/org/lineageos/twelve/ext/Bitmap.kt b/app/src/main/java/org/lineageos/twelve/ext/Bitmap.kt
new file mode 100644
index 0000000..5e5f846
--- /dev/null
+++ b/app/src/main/java/org/lineageos/twelve/ext/Bitmap.kt
@@ -0,0 +1,13 @@
+/*
+ * SPDX-FileCopyrightText: 2024 The LineageOS Project
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.lineageos.twelve.ext
+
+import android.graphics.Bitmap
+import java.nio.ByteBuffer
+
+fun Bitmap.toByteArray(): ByteArray = ByteBuffer.allocate(rowBytes * height).apply {
+    copyPixelsToBuffer(this)
+}.array()
diff --git a/app/src/main/java/org/lineageos/twelve/ext/MediaItem.kt b/app/src/main/java/org/lineageos/twelve/ext/MediaItem.kt
index 9f513b1..ce8276a 100644
--- a/app/src/main/java/org/lineageos/twelve/ext/MediaItem.kt
+++ b/app/src/main/java/org/lineageos/twelve/ext/MediaItem.kt
@@ -20,7 +20,9 @@
     genre: String? = null,
     sourceUri: Uri? = null,
     mimeType: String? = null,
-    imageUri: Uri? = null
+    artworkData: ByteArray? = null,
+    artworkType: @MediaMetadata.PictureType Int? = null,
+    artworkUri: Uri? = null,
 ): MediaItem {
     val metadata =
         MediaMetadata.Builder()
@@ -30,7 +32,8 @@
             .setGenre(genre)
             .setIsBrowsable(isBrowsable)
             .setIsPlayable(isPlayable)
-            .setArtworkUri(imageUri)
+            .setArtworkData(artworkData, artworkType)
+            .setArtworkUri(artworkUri)
             .setMediaType(mediaType)
             .build()
 
diff --git a/app/src/main/java/org/lineageos/twelve/models/Album.kt b/app/src/main/java/org/lineageos/twelve/models/Album.kt
index ab9147e..03545e6 100644
--- a/app/src/main/java/org/lineageos/twelve/models/Album.kt
+++ b/app/src/main/java/org/lineageos/twelve/models/Album.kt
@@ -8,6 +8,7 @@
 import android.net.Uri
 import androidx.media3.common.MediaMetadata
 import org.lineageos.twelve.ext.buildMediaItem
+import org.lineageos.twelve.ext.toByteArray
 
 /**
  * An album.
@@ -43,6 +44,9 @@
         isBrowsable = true,
         mediaType = MediaMetadata.MEDIA_TYPE_ALBUM,
         sourceUri = uri,
+        artworkData = thumbnail?.bitmap?.toByteArray(),
+        artworkType = thumbnail?.type?.media3Value,
+        artworkUri = thumbnail?.uri,
     )
 
     companion object {
diff --git a/app/src/main/java/org/lineageos/twelve/models/Artist.kt b/app/src/main/java/org/lineageos/twelve/models/Artist.kt
index 36c8af3..d195887 100644
--- a/app/src/main/java/org/lineageos/twelve/models/Artist.kt
+++ b/app/src/main/java/org/lineageos/twelve/models/Artist.kt
@@ -8,6 +8,7 @@
 import android.net.Uri
 import androidx.media3.common.MediaMetadata
 import org.lineageos.twelve.ext.buildMediaItem
+import org.lineageos.twelve.ext.toByteArray
 
 /**
  * An artist.
@@ -34,6 +35,9 @@
         isBrowsable = true,
         mediaType = MediaMetadata.MEDIA_TYPE_ARTIST,
         sourceUri = uri,
+        artworkData = thumbnail?.bitmap?.toByteArray(),
+        artworkType = thumbnail?.type?.media3Value,
+        artworkUri = thumbnail?.uri,
     )
 
     companion object {
diff --git a/app/src/main/java/org/lineageos/twelve/models/Thumbnail.kt b/app/src/main/java/org/lineageos/twelve/models/Thumbnail.kt
index 8cb272c..e7612e7 100644
--- a/app/src/main/java/org/lineageos/twelve/models/Thumbnail.kt
+++ b/app/src/main/java/org/lineageos/twelve/models/Thumbnail.kt
@@ -7,6 +7,7 @@
 
 import android.graphics.Bitmap
 import android.net.Uri
+import androidx.media3.common.MediaMetadata
 
 /**
  * A thumbnail for a media item. It can be a URI or a bitmap. Both can be defined, in that case the
@@ -14,11 +15,130 @@
  *
  * @param uri The URI of the thumbnail.
  * @param bitmap The bitmap of the thumbnail.
+ * @param type the type of the thumbnail.
  */
 data class Thumbnail(
     val uri: Uri? = null,
     val bitmap: Bitmap? = null,
+    val type: Type = Type.OTHER,
 ) : Comparable<Thumbnail> {
+    /**
+     * ID3-like picture types.
+     */
+    enum class Type(val media3Value: @MediaMetadata.PictureType Int) {
+        /**
+         * Other.
+         */
+        OTHER(MediaMetadata.PICTURE_TYPE_OTHER),
+
+        /**
+         * 32x32 pixels 'file icon' (PNG only).
+         */
+        FILE_ICON(MediaMetadata.PICTURE_TYPE_FILE_ICON),
+
+        /**
+         * Other file icon.
+         */
+        FILE_ICON_OTHER(MediaMetadata.PICTURE_TYPE_FILE_ICON_OTHER),
+
+        /**
+         * Cover (front).
+         */
+        FRONT_COVER(MediaMetadata.PICTURE_TYPE_FRONT_COVER),
+
+        /**
+         * Cover (back).
+         */
+        BACK_COVER(MediaMetadata.PICTURE_TYPE_BACK_COVER),
+
+        /**
+         * Leaflet page.
+         */
+        LEAFLET_PAGE(MediaMetadata.PICTURE_TYPE_LEAFLET_PAGE),
+
+        /**
+         * Media (e.g. label side of CD).
+         */
+        MEDIA(MediaMetadata.PICTURE_TYPE_MEDIA),
+
+        /**
+         * Lead artist/lead performer/soloist.
+         */
+        LEAD_ARTIST_PERFORMER(MediaMetadata.PICTURE_TYPE_LEAD_ARTIST_PERFORMER),
+
+        /**
+         * Artist/performer.
+         */
+        ARTIST_PERFORMER(MediaMetadata.PICTURE_TYPE_ARTIST_PERFORMER),
+
+        /**
+         * Conductor.
+         */
+        CONDUCTOR(MediaMetadata.PICTURE_TYPE_CONDUCTOR),
+
+        /**
+         * Band/Orchestra.
+         */
+        BAND_ORCHESTRA(MediaMetadata.PICTURE_TYPE_BAND_ORCHESTRA),
+
+        /**
+         * Composer.
+         */
+        COMPOSER(MediaMetadata.PICTURE_TYPE_COMPOSER),
+
+        /**
+         * Lyricist/text writer.
+         */
+        LYRICIST(MediaMetadata.PICTURE_TYPE_LYRICIST),
+
+        /**
+         * Recording Location.
+         */
+        RECORDING_LOCATION(MediaMetadata.PICTURE_TYPE_RECORDING_LOCATION),
+
+        /**
+         * During recording.
+         */
+        DURING_RECORDING(MediaMetadata.PICTURE_TYPE_DURING_RECORDING),
+
+        /**
+         * During performance.
+         */
+        DURING_PERFORMANCE(MediaMetadata.PICTURE_TYPE_DURING_PERFORMANCE),
+
+        /**
+         * Movie/video screen capture.
+         */
+        MOVIE_VIDEO_SCREEN_CAPTURE(MediaMetadata.PICTURE_TYPE_MOVIE_VIDEO_SCREEN_CAPTURE),
+
+        /**
+         * A bright coloured fish.
+         * [what?](https://musicfans.stackexchange.com/questions/14446/reason-for-id3-bright-colored-fish)
+         */
+        A_BRIGHT_COLORED_FISH(MediaMetadata.PICTURE_TYPE_A_BRIGHT_COLORED_FISH),
+
+        /**
+         * Illustration.
+         */
+        ILLUSTRATION(MediaMetadata.PICTURE_TYPE_ILLUSTRATION),
+
+        /**
+         * Band/artist logotype.
+         */
+        BAND_ARTIST_LOGO(MediaMetadata.PICTURE_TYPE_BAND_ARTIST_LOGO),
+
+        /**
+         * Publisher/Studio logotype.
+         */
+        PUBLISHER_STUDIO_LOGO(MediaMetadata.PICTURE_TYPE_PUBLISHER_STUDIO_LOGO);
+
+        companion object {
+            fun fromMedia3Value(value: @MediaMetadata.PictureType Int) = entries.firstOrNull {
+                it.media3Value == value
+            } ?: throw Exception("Unknown picture type $value")
+        }
+    }
+
     init {
         require(uri != null || bitmap != null) {
             "At least one of the fields should be non-null"
@@ -28,6 +148,7 @@
     override fun compareTo(other: Thumbnail) = compareValuesBy(
         this, other,
         Thumbnail::uri,
+        Thumbnail::type,
     ).let {
         if (it == 0) {
             return@let when (this.bitmap?.sameAs(other.bitmap)) {