diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt index 4cc041074a8d8..fa4211487d1d0 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt @@ -49,6 +49,7 @@ import android.service.notification.StatusBarNotification import android.support.v4.media.MediaMetadataCompat import android.text.TextUtils import android.util.Log +import android.util.Pair as APair import androidx.media.utils.MediaConstants import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor @@ -217,6 +218,13 @@ class MediaDataManager( private var smartspaceSession: SmartspaceSession? = null private var allowMediaRecommendations = allowMediaRecommendations(context) + private val artworkWidth = + context.resources.getDimensionPixelSize( + com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize + ) + private val artworkHeight = + context.resources.getDimensionPixelSize(R.dimen.qs_media_session_height_expanded) + /** Check whether this notification is an RCN */ private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean { return sbn.notification.extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE) @@ -1250,9 +1258,21 @@ class MediaDataManager( return null } - val source = ImageDecoder.createSource(context.getContentResolver(), uri) + val source = ImageDecoder.createSource(context.contentResolver, uri) return try { - ImageDecoder.decodeBitmap(source) { decoder, _, _ -> + ImageDecoder.decodeBitmap(source) { decoder, info, _ -> + val width = info.size.width + val height = info.size.height + val scale = + MediaDataUtils.getScaleFactor( + APair(width, height), + APair(artworkWidth, artworkHeight) + ) + + // Downscale if needed + if (scale != 0f && scale < 1) { + decoder.setTargetSize((scale * width).toInt(), (scale * height).toInt()) + } decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE } } catch (e: IOException) { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index cb1f12cf412fa..40027a1d8f2c0 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -56,6 +56,7 @@ import android.os.Process; import android.os.Trace; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -122,6 +123,11 @@ import com.android.systemui.util.animation.TransitionLayout; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.time.SystemClock; +import dagger.Lazy; + +import kotlin.Triple; +import kotlin.Unit; + import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; @@ -129,10 +135,6 @@ import java.util.concurrent.Executor; import javax.inject.Inject; -import dagger.Lazy; -import kotlin.Triple; -import kotlin.Unit; - /** * A view controller used for Media Playback. */ @@ -1000,18 +1002,9 @@ public class MediaControlPanel { int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); - if (width == 0 || height == 0 || targetWidth == 0 || targetHeight == 0) { - return; - } - - float scale; - if ((width / (float) height) > (targetWidth / (float) targetHeight)) { - // Drawable is wider than target view, scale to match height - scale = targetHeight / (float) height; - } else { - // Drawable is taller than target view, scale to match width - scale = targetWidth / (float) width; - } + float scale = MediaDataUtils.getScaleFactor(new Pair(width, height), + new Pair(targetWidth, targetHeight)); + if (scale == 0) return; transitionDrawable.setLayerSize(layer, (int) (scale * width), (int) (scale * height)); } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java index e95106e0987a3..0239d367e52d7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java @@ -22,6 +22,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; import android.text.TextUtils; +import android.util.Pair; import androidx.core.math.MathUtils; import androidx.media.utils.MediaConstants; @@ -87,4 +88,32 @@ public class MediaDataUtils { } return null; } + + /** + * Calculate a scale factor that will allow the input to fill the target size. + * + * @param input width, height of the input view + * @param target width, height of the target view + * @return the scale factor; 0 if any given dimension is 0 + */ + public static float getScaleFactor(Pair input, + Pair target) { + float width = (float) input.first; + float height = (float) input.second; + + float targetWidth = (float) target.first; + float targetHeight = (float) target.second; + + if (width == 0 || height == 0 || targetWidth == 0 || targetHeight == 0) { + return 0f; + } + + if ((width / height) > (targetWidth / targetHeight)) { + // Input is wider than target view, scale to match height + return targetHeight / height; + } else { + // Input is taller than target view, scale to match width + return targetWidth / width; + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt new file mode 100644 index 0000000000000..86f3062bca352 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media.controls.util + +import android.testing.AndroidTestingRunner +import android.util.Pair as APair +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class MediaDataUtilsTest : SysuiTestCase() { + + @Test + fun testScaleFactor_zeroInput_returnsZero() { + val input = APair(0, 0) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(0f) + } + + @Test + fun testScaleFactor_tooWide_scaleDown() { + val input = APair(400, 200) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(0.5f) + } + + @Test + fun testScaleFactor_tooTall_scaleDown() { + val input = APair(200, 400) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(0.5f) + } + + @Test + fun testScaleFactor_lessWide_scaleUp() { + val input = APair(50, 100) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(2f) + } + + @Test + fun testScaleFactor_lessTall_scaleUp() { + val input = APair(100, 50) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(2f) + } +}