1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.media.controls.ui.util 18 19 import android.app.WallpaperColors 20 import android.content.Context 21 import android.content.pm.PackageManager 22 import android.graphics.Rect 23 import android.graphics.drawable.Drawable 24 import android.graphics.drawable.GradientDrawable 25 import android.graphics.drawable.Icon 26 import android.graphics.drawable.LayerDrawable 27 import android.util.Log 28 import com.android.systemui.Flags 29 import com.android.systemui.media.controls.ui.animation.backgroundEndFromScheme 30 import com.android.systemui.media.controls.ui.animation.backgroundFromScheme 31 import com.android.systemui.media.controls.ui.animation.backgroundStartFromScheme 32 import com.android.systemui.monet.ColorScheme 33 import com.android.systemui.monet.Style 34 import com.android.systemui.util.getColorWithAlpha 35 import kotlinx.coroutines.CoroutineDispatcher 36 import kotlinx.coroutines.withContext 37 38 object MediaArtworkHelper { 39 40 /** 41 * This method should be called from a background thread. WallpaperColors.fromBitmap takes a 42 * good amount of time. We do that work on the background executor to avoid stalling animations 43 * on the UI Thread. 44 */ 45 suspend fun getWallpaperColor( 46 applicationContext: Context, 47 backgroundDispatcher: CoroutineDispatcher, 48 artworkIcon: Icon?, 49 tag: String, 50 ): WallpaperColors? = 51 withContext(backgroundDispatcher) { 52 return@withContext artworkIcon?.let { 53 if (it.type == Icon.TYPE_BITMAP || it.type == Icon.TYPE_ADAPTIVE_BITMAP) { 54 // Avoids extra processing if this is already a valid bitmap 55 it.bitmap.let { artworkBitmap -> 56 if (artworkBitmap.isRecycled) { 57 Log.d(tag, "Cannot load wallpaper color from a recycled bitmap") 58 null 59 } else { 60 WallpaperColors.fromBitmap(artworkBitmap) 61 } 62 } 63 } else { 64 it.loadDrawable(applicationContext)?.let { artworkDrawable -> 65 WallpaperColors.fromDrawable(artworkDrawable) 66 } 67 } 68 } 69 } 70 71 /** 72 * Returns a scaled [Drawable] of a given [Icon] centered in [width]x[height] background size. 73 */ 74 fun getScaledBackground(context: Context, icon: Icon, width: Int, height: Int): Drawable? { 75 val drawable = icon.loadDrawable(context) 76 val bounds = Rect(0, 0, width, height) 77 if (bounds.width() > width || bounds.height() > height) { 78 val offsetX = (bounds.width() - width) / 2.0f 79 val offsetY = (bounds.height() - height) / 2.0f 80 bounds.offset(-offsetX.toInt(), -offsetY.toInt()) 81 } 82 drawable?.bounds = bounds 83 return drawable 84 } 85 86 /** Adds [gradient] on a given [albumArt] drawable using [colorScheme]. */ 87 fun setUpGradientColorOnDrawable( 88 albumArt: Drawable?, 89 gradient: GradientDrawable, 90 colorScheme: ColorScheme, 91 startAlpha: Float, 92 endAlpha: Float, 93 ): LayerDrawable { 94 val startColor = 95 if (Flags.mediaControlsA11yColors()) { 96 backgroundFromScheme(colorScheme) 97 } else { 98 backgroundStartFromScheme(colorScheme) 99 } 100 val endColor = 101 if (Flags.mediaControlsA11yColors()) { 102 startColor 103 } else { 104 backgroundEndFromScheme(colorScheme) 105 } 106 gradient.colors = 107 intArrayOf( 108 getColorWithAlpha(startColor, startAlpha), 109 getColorWithAlpha(endColor, endAlpha), 110 ) 111 return LayerDrawable(arrayOf(albumArt, gradient)) 112 } 113 114 /** Returns [ColorScheme] of media app given its [icon]. */ 115 fun getColorScheme(icon: Drawable, tag: String, darkTheme: Boolean): ColorScheme? { 116 return try { 117 ColorScheme(WallpaperColors.fromDrawable(icon), darkTheme, Style.CONTENT) 118 } catch (e: PackageManager.NameNotFoundException) { 119 Log.w(tag, "Fail to get media app info", e) 120 null 121 } 122 } 123 } 124