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

Commit e12b6f19 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add color scheme logic" into main

parents d1ef274f 90817b7b
Loading
Loading
Loading
Loading
+58 −14
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.remedia.data.model.MediaDataModel
import com.android.systemui.media.remedia.shared.model.MediaColorScheme
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -157,8 +158,14 @@ class MediaRepositoryTest : SysuiTestCase() {
            assertThat(underTest.currentMedia.size).isEqualTo(2)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingData.toDataModel(underTest.currentMedia[0].controller),
                    remoteData.toDataModel(underTest.currentMedia[1].controller),
                    playingData.toDataModel(
                        underTest.currentMedia[0].controller,
                        underTest.currentMedia[0].colorScheme,
                    ),
                    remoteData.toDataModel(
                        underTest.currentMedia[1].controller,
                        underTest.currentMedia[1].colorScheme,
                    ),
                )
                .inOrder()
        }
@@ -177,8 +184,14 @@ class MediaRepositoryTest : SysuiTestCase() {
            assertThat(underTest.currentMedia.size).isEqualTo(2)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingData1.toDataModel(underTest.currentMedia[0].controller),
                    playingData2.toDataModel(underTest.currentMedia[1].controller),
                    playingData1.toDataModel(
                        underTest.currentMedia[0].controller,
                        underTest.currentMedia[0].colorScheme,
                    ),
                    playingData2.toDataModel(
                        underTest.currentMedia[1].controller,
                        underTest.currentMedia[1].colorScheme,
                    ),
                )
                .inOrder()

@@ -191,8 +204,14 @@ class MediaRepositoryTest : SysuiTestCase() {
            assertThat(underTest.currentMedia.size).isEqualTo(2)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingData1.toDataModel(underTest.currentMedia[0].controller),
                    playingData2.toDataModel(underTest.currentMedia[1].controller),
                    playingData1.toDataModel(
                        underTest.currentMedia[0].controller,
                        underTest.currentMedia[0].colorScheme,
                    ),
                    playingData2.toDataModel(
                        underTest.currentMedia[1].controller,
                        underTest.currentMedia[1].colorScheme,
                    ),
                )
                .inOrder()

@@ -202,8 +221,14 @@ class MediaRepositoryTest : SysuiTestCase() {
            assertThat(underTest.currentMedia.size).isEqualTo(2)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingData2.toDataModel(underTest.currentMedia[0].controller),
                    playingData1.toDataModel(underTest.currentMedia[1].controller),
                    playingData2.toDataModel(
                        underTest.currentMedia[0].controller,
                        underTest.currentMedia[0].colorScheme,
                    ),
                    playingData1.toDataModel(
                        underTest.currentMedia[1].controller,
                        underTest.currentMedia[1].colorScheme,
                    ),
                )
                .inOrder()
        }
@@ -238,11 +263,26 @@ class MediaRepositoryTest : SysuiTestCase() {
            assertThat(underTest.currentMedia.size).isEqualTo(5)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingAndLocalData.toDataModel(underTest.currentMedia[0].controller),
                    playingAndRemoteData.toDataModel(underTest.currentMedia[1].controller),
                    stoppedAndRemoteData.toDataModel(underTest.currentMedia[2].controller),
                    stoppedAndLocalData.toDataModel(underTest.currentMedia[3].controller),
                    canResumeData.toDataModel(underTest.currentMedia[4].controller),
                    playingAndLocalData.toDataModel(
                        underTest.currentMedia[0].controller,
                        underTest.currentMedia[0].colorScheme,
                    ),
                    playingAndRemoteData.toDataModel(
                        underTest.currentMedia[1].controller,
                        underTest.currentMedia[1].colorScheme,
                    ),
                    stoppedAndRemoteData.toDataModel(
                        underTest.currentMedia[2].controller,
                        underTest.currentMedia[2].colorScheme,
                    ),
                    stoppedAndLocalData.toDataModel(
                        underTest.currentMedia[3].controller,
                        underTest.currentMedia[3].colorScheme,
                    ),
                    canResumeData.toDataModel(
                        underTest.currentMedia[4].controller,
                        underTest.currentMedia[4].colorScheme,
                    ),
                )
                .inOrder()
        }
@@ -270,7 +310,10 @@ class MediaRepositoryTest : SysuiTestCase() {
        )
    }

    private fun MediaData.toDataModel(mediaController: MediaController): MediaDataModel {
    private fun MediaData.toDataModel(
        mediaController: MediaController,
        colorScheme: MediaColorScheme?,
    ): MediaDataModel {
        return MediaDataModel(
            instanceId = instanceId,
            appUid = appUid,
@@ -280,6 +323,7 @@ class MediaRepositoryTest : SysuiTestCase() {
            background = null,
            title = song.toString(),
            subtitle = artist.toString(),
            colorScheme = colorScheme,
            notificationActions = actions,
            playbackStateActions = semanticActions,
            outputDevice = device,
+2 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import com.android.systemui.common.shared.model.Icon
import com.android.systemui.media.controls.shared.model.MediaButton
import com.android.systemui.media.controls.shared.model.MediaDeviceData
import com.android.systemui.media.controls.shared.model.MediaNotificationAction
import com.android.systemui.media.remedia.shared.model.MediaColorScheme

/** Data model representing a media data. */
data class MediaDataModel(
@@ -37,6 +38,7 @@ data class MediaDataModel(
    val background: Icon?,
    val title: String,
    val subtitle: String,
    val colorScheme: MediaColorScheme?,
    /** List of generic action buttons for the media player, based on notification actions */
    val notificationActions: List<MediaNotificationAction>,
    /**
+112 −32
Original line number Diff line number Diff line
@@ -16,10 +16,14 @@

package com.android.systemui.media.remedia.data.repository

import android.app.WallpaperColors
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.media.session.MediaController
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import com.android.internal.logging.InstanceId
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -31,6 +35,9 @@ import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.media.controls.data.model.MediaSortKeyModel
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.remedia.data.model.MediaDataModel
import com.android.systemui.media.remedia.shared.model.MediaColorScheme
import com.android.systemui.monet.ColorScheme
import com.android.systemui.monet.Style
import com.android.systemui.res.R
import com.android.systemui.util.time.SystemClock
import java.util.TreeMap
@@ -130,15 +137,9 @@ constructor(
                        systemClock.currentTimeMillis(),
                        instanceId,
                    )
                val controller =
                    if (currentModel != null && currentModel.controller.sessionToken == token) {
                        currentModel.controller
                    } else {
                        MediaController(applicationContext, token!!)
                    }

                applicationScope.launch {
                    val mediaModel = toDataModel(controller)
                    val mediaModel = toDataModel(currentModel)
                    sortedMap[sortKey] = mediaModel

                    var isNewToCurrentMedia = true
@@ -173,10 +174,17 @@ constructor(
            TreeMap(sortedMedia.filter { (keyModel, _) -> keyModel.instanceId != data.instanceId })
    }

    private suspend fun MediaData.toDataModel(controller: MediaController): MediaDataModel {
    private suspend fun MediaData.toDataModel(currentModel: MediaDataModel?): MediaDataModel {
        return withContext(backgroundDispatcher) {
            val controller =
                if (currentModel != null && currentModel.controller.sessionToken == token) {
                    currentModel.controller
                } else {
                    MediaController(applicationContext, token!!)
                }
            val icon = appIcon?.loadDrawable(applicationContext)
            val background = artwork?.loadDrawable(applicationContext)
        return MediaDataModel(
            MediaDataModel(
                instanceId = instanceId,
                appUid = appUid,
                packageName = packageName,
@@ -187,6 +195,7 @@ constructor(
                background = background?.let { Icon.Loaded(background, null) },
                title = song.toString(),
                subtitle = artist.toString(),
                colorScheme = getScheme(artwork, packageName),
                notificationActions = actions,
                playbackStateActions = semanticActions,
                outputDevice = device,
@@ -199,6 +208,30 @@ constructor(
                isExplicit = isExplicit,
            )
        }
    }

    private suspend fun getScheme(
        artwork: android.graphics.drawable.Icon?,
        packageName: String,
    ): MediaColorScheme? {
        val wallpaperColors = getWallpaperColor(applicationContext, backgroundDispatcher, artwork)
        val colorScheme =
            wallpaperColors?.let { ColorScheme(it, false, Style.CONTENT) }
                ?: let {
                    val launcherIcon = getAltIcon(packageName)
                    if (launcherIcon is Icon.Loaded) {
                        getColorScheme(launcherIcon.drawable)
                    } else {
                        null
                    }
                }
        return colorScheme?.run {
            MediaColorScheme(
                Color(colorScheme.materialScheme.getPrimaryFixed()),
                Color(colorScheme.materialScheme.getOnPrimaryFixed()),
            )
        }
    }

    private suspend fun getAltIcon(packageName: String): Icon {
        return withContext(backgroundDispatcher) {
@@ -210,4 +243,51 @@ constructor(
            }
        }
    }

    /**
     * This method should be called from a background thread. WallpaperColors.fromBitmap is a
     * blocking call.
     */
    private suspend fun getWallpaperColor(
        applicationContext: Context,
        backgroundDispatcher: CoroutineDispatcher,
        artworkIcon: android.graphics.drawable.Icon?,
    ): WallpaperColors? {
        return withContext(backgroundDispatcher) {
            artworkIcon?.let {
                if (
                    it.type == android.graphics.drawable.Icon.TYPE_BITMAP ||
                        it.type == android.graphics.drawable.Icon.TYPE_ADAPTIVE_BITMAP
                ) {
                    // Avoids extra processing if this is already a valid bitmap
                    it.bitmap.let { artworkBitmap ->
                        if (artworkBitmap.isRecycled) {
                            Log.d(TAG, "Cannot load wallpaper color from a recycled bitmap")
                            null
                        } else {
                            WallpaperColors.fromBitmap(artworkBitmap)
                        }
                    }
                } else {
                    it.loadDrawable(applicationContext)?.let { artworkDrawable ->
                        WallpaperColors.fromDrawable(artworkDrawable)
                    }
                }
            }
        }
    }

    /** Returns [ColorScheme] of media app given its [icon]. */
    private fun getColorScheme(icon: Drawable): ColorScheme? {
        return try {
            ColorScheme(WallpaperColors.fromDrawable(icon), false, Style.CONTENT)
        } catch (e: PackageManager.NameNotFoundException) {
            Log.w(TAG, "Fail to get media app info", e)
            null
        }
    }

    companion object {
        private const val TAG = "MediaRepository"
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -91,8 +91,8 @@ constructor(@Application val applicationContext: Context, val repository: MediaR
                        (it as Icon.Loaded).drawable.toBitmap()?.asImageBitmap()
                    }

            override val colorScheme: MediaColorScheme
                get() = TODO("Not yet implemented")
            override val colorScheme: MediaColorScheme?
                get() = dataModel.colorScheme

            override val title: String
                get() = dataModel.title
+1 −1
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ interface MediaSessionModel {

    val background: ImageBitmap?

    val colorScheme: MediaColorScheme
    val colorScheme: MediaColorScheme?

    val title: String

Loading