1 /* 2 * Copyright (C) 2019 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.statusbar 18 19 import android.content.Context 20 import android.graphics.Bitmap 21 import android.graphics.Canvas 22 import android.graphics.Point 23 import android.graphics.Rect 24 import android.renderscript.Allocation 25 import android.renderscript.Element 26 import android.renderscript.RenderScript 27 import android.renderscript.ScriptIntrinsicBlur 28 import android.util.Log 29 import android.util.MathUtils 30 import com.android.internal.graphics.ColorUtils 31 import com.android.systemui.statusbar.notification.MediaNotificationProcessor 32 33 import javax.inject.Inject 34 import javax.inject.Singleton 35 36 private const val TAG = "MediaArtworkProcessor" 37 private const val COLOR_ALPHA = (255 * 0.7f).toInt() 38 private const val BLUR_RADIUS = 25f 39 private const val DOWNSAMPLE = 6 40 41 @Singleton 42 class MediaArtworkProcessor @Inject constructor() { 43 44 private val mTmpSize = Point() 45 private var mArtworkCache: Bitmap? = null 46 processArtworknull47 fun processArtwork(context: Context, artwork: Bitmap): Bitmap? { 48 if (mArtworkCache != null) { 49 return mArtworkCache 50 } 51 val renderScript = RenderScript.create(context) 52 val blur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript)) 53 var input: Allocation? = null 54 var output: Allocation? = null 55 var inBitmap: Bitmap? = null 56 try { 57 context.display.getSize(mTmpSize) 58 val rect = Rect(0, 0, artwork.width, artwork.height) 59 MathUtils.fitRect(rect, Math.max(mTmpSize.x / DOWNSAMPLE, mTmpSize.y / DOWNSAMPLE)) 60 inBitmap = Bitmap.createScaledBitmap(artwork, rect.width(), rect.height(), 61 true /* filter */) 62 // Render script blurs only support ARGB_8888, we need a conversion if we got a 63 // different bitmap config. 64 if (inBitmap.config != Bitmap.Config.ARGB_8888) { 65 val oldIn = inBitmap 66 inBitmap = oldIn.copy(Bitmap.Config.ARGB_8888, false /* isMutable */) 67 oldIn.recycle() 68 } 69 val outBitmap = Bitmap.createBitmap(inBitmap.width, inBitmap.height, 70 Bitmap.Config.ARGB_8888) 71 72 input = Allocation.createFromBitmap(renderScript, inBitmap, 73 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_GRAPHICS_TEXTURE) 74 output = Allocation.createFromBitmap(renderScript, outBitmap) 75 76 blur.setRadius(BLUR_RADIUS) 77 blur.setInput(input) 78 blur.forEach(output) 79 output.copyTo(outBitmap) 80 81 val swatch = MediaNotificationProcessor.findBackgroundSwatch(artwork) 82 83 val canvas = Canvas(outBitmap) 84 canvas.drawColor(ColorUtils.setAlphaComponent(swatch.rgb, COLOR_ALPHA)) 85 return outBitmap 86 } catch (ex: IllegalArgumentException) { 87 Log.e(TAG, "error while processing artwork", ex) 88 return null 89 } finally { 90 input?.destroy() 91 output?.destroy() 92 blur.destroy() 93 inBitmap?.recycle() 94 } 95 } 96 clearCachenull97 fun clearCache() { 98 mArtworkCache?.recycle() 99 mArtworkCache = null 100 } 101 }