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

Commit aa80478e authored by Caitlin Shkuratov's avatar Caitlin Shkuratov Committed by Android (Google) Code Review
Browse files

Merge "[SB] Fix status bar icon when a layer-list contains some level-lists." into main

parents 60a40b0b dbf371ee
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ class DrawableSizeTest : SysuiTestCase() {
        val drawable =
            BitmapDrawable(
                resources,
                Bitmap.createBitmap(resources.displayMetrics, 150, 150, Bitmap.Config.ARGB_8888)
                Bitmap.createBitmap(resources.displayMetrics, 150, 150, Bitmap.Config.ARGB_8888),
            )
        val result = DrawableSize.downscaleToSize(resources, drawable, 300, 300)
        assertThat(result).isSameInstanceAs(drawable)
@@ -48,7 +48,7 @@ class DrawableSizeTest : SysuiTestCase() {
        val drawable =
            BitmapDrawable(
                resources,
                Bitmap.createBitmap(resources.displayMetrics, 150, 75, Bitmap.Config.ARGB_8888)
                Bitmap.createBitmap(resources.displayMetrics, 150, 75, Bitmap.Config.ARGB_8888),
            )

        val result = DrawableSize.downscaleToSize(resources, drawable, 75, 75)
@@ -64,4 +64,31 @@ class DrawableSizeTest : SysuiTestCase() {
        val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
        assertThat(result).isSameInstanceAs(drawable)
    }

    @Test
    fun testDownscaleToSize_layerDrawable_allLayersSameType_resized() {
        val drawable =
            resources.getDrawable(
                com.android.systemui.tests.R.drawable.layer_drawable_all_same_type,
                resources.newTheme(),
            )

        val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)

        assertThat(result).isNotSameInstanceAs(drawable)
    }

    /** Regression test for b/244282477. */
    @Test
    fun testDownscaleToSize_layerDrawable_layersAreDifferentTypes_unchanged() {
        val drawable =
            resources.getDrawable(
                com.android.systemui.tests.R.drawable.layer_drawable_different_types,
                resources.newTheme(),
            )

        val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)

        assertThat(result).isSameInstanceAs(drawable)
    }
}
+59 −24
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ import android.graphics.drawable.AnimatedStateListDrawable
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.util.Log
import androidx.annotation.Px
import com.android.app.tracing.traceSection
@@ -22,18 +23,17 @@ class DrawableSize {
        const val TAG = "SysUiDrawableSize"

        /**
         * Downscales passed Drawable to set maximum width and height. This will only
         * be done for Drawables that can be downscaled non-destructively - e.g. animated
         * and stateful drawables will no be downscaled.
         * Downscales passed Drawable to set maximum width and height. This will only be done for
         * Drawables that can be downscaled non-destructively - e.g. animated drawables, stateful
         * drawables, and drawables with mixed-type layers will not be downscaled.
         *
         * Downscaling will keep the aspect ratio.
         * This method will not touch drawables that already fit into size specification.
         * Downscaling will keep the aspect ratio. This method will not touch drawables that already
         * fit into size specification.
         *
         * @param resources Resources on which to base the density of resized drawable.
         * @param drawable Drawable to downscale.
         * @param maxWidth Maximum width of the downscaled drawable.
         * @param maxHeight Maximum height of the downscaled drawable.
         *
         * @return returns downscaled drawable if it's possible to downscale it or original if it's
         *   not.
         */
@@ -42,16 +42,16 @@ class DrawableSize {
            res: Resources,
            drawable: Drawable,
            @Px maxWidth: Int,
            @Px maxHeight: Int
            @Px maxHeight: Int,
        ): Drawable {
            traceSection("DrawableSize#downscaleToSize") {
                // Bitmap drawables can contain big bitmaps as their content while sneaking it past
                // us using density scaling. Inspect inside the Bitmap drawables for actual bitmap
                // size for those.
                val originalWidth = (drawable as? BitmapDrawable)?.bitmap?.width
                                    ?: drawable.intrinsicWidth
                val originalHeight = (drawable as? BitmapDrawable)?.bitmap?.height
                                    ?: drawable.intrinsicHeight
                val originalWidth =
                    (drawable as? BitmapDrawable)?.bitmap?.width ?: drawable.intrinsicWidth
                val originalHeight =
                    (drawable as? BitmapDrawable)?.bitmap?.height ?: drawable.intrinsicHeight

                // Don't touch drawable if we can't resolve sizes for whatever reason.
                if (originalWidth <= 0 || originalHeight <= 0) {
@@ -61,14 +61,18 @@ class DrawableSize {
                // Do not touch drawables that are already within bounds.
                if (originalWidth < maxWidth && originalHeight < maxHeight) {
                    if (Log.isLoggable(TAG, Log.DEBUG)) {
                        Log.d(TAG, "Not resizing $originalWidth x $originalHeight" + " " +
                                "to $maxWidth x $maxHeight")
                        Log.d(
                            TAG,
                            "Not resizing $originalWidth x $originalHeight" +
                                " " +
                                "to $maxWidth x $maxHeight",
                        )
                    }

                    return drawable
                }

                if (!isSimpleBitmap(drawable)) {
                if (isComplicatedBitmap(drawable)) {
                    return drawable
                }

@@ -80,19 +84,25 @@ class DrawableSize {
                val height = (originalHeight * scale).toInt()

                if (width <= 0 || height <= 0) {
                    Log.w(TAG, "Attempted to resize ${drawable.javaClass.simpleName} " +
                            "from $originalWidth x $originalHeight to invalid $width x $height.")
                    Log.w(
                        TAG,
                        "Attempted to resize ${drawable.javaClass.simpleName} " +
                            "from $originalWidth x $originalHeight to invalid $width x $height.",
                    )
                    return drawable
                }

                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "Resizing large drawable (${drawable.javaClass.simpleName}) " +
                            "from $originalWidth x $originalHeight to $width x $height")
                    Log.d(
                        TAG,
                        "Resizing large drawable (${drawable.javaClass.simpleName}) " +
                            "from $originalWidth x $originalHeight to $width x $height",
                    )
                }

                // We want to keep existing config if it's more efficient than 32-bit RGB.
                val config = (drawable as? BitmapDrawable)?.bitmap?.config
                        ?: Bitmap.Config.ARGB_8888
                val config =
                    (drawable as? BitmapDrawable)?.bitmap?.config ?: Bitmap.Config.ARGB_8888
                val scaledDrawableBitmap = Bitmap.createBitmap(width, height, config)
                val canvas = Canvas(scaledDrawableBitmap)

@@ -105,8 +115,8 @@ class DrawableSize {
            }
        }

        private fun isSimpleBitmap(drawable: Drawable): Boolean {
            return !(drawable.isStateful || isAnimated(drawable))
        private fun isComplicatedBitmap(drawable: Drawable): Boolean {
            return drawable.isStateful || isAnimated(drawable) || hasComplicatedLayers(drawable)
        }

        private fun isAnimated(drawable: Drawable): Boolean {
@@ -119,5 +129,30 @@ class DrawableSize {
                drawable is AnimatedStateListDrawable ||
                drawable is AnimatedVectorDrawable
        }

        private fun hasComplicatedLayers(drawable: Drawable): Boolean {
            if (drawable !is LayerDrawable) {
                return false
            }
            if (drawable.numberOfLayers == 1) {
                return false
            }

            val firstLayerType = drawable.getDrawable(0).javaClass
            for (i in 1..<drawable.numberOfLayers) {
                val layer = drawable.getDrawable(i)
                if (layer.javaClass != firstLayerType) {
                    // If different layers have different drawable types, we shouldn't scale it down
                    // because we may lose the level information if one of the layers is a bitmap
                    // and another layer is a level-list. See b/244282477.
                    return true
                }
                if (isComplicatedBitmap(layer)) {
                    return true
                }
            }

            return false
        }
    }
}
+19 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?><!--
  ~ Copyright (C) 2024 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.
  -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:drawable="@drawable/ic_brightness"/>
    <item android:drawable="@drawable/ic_brightness"/>
</layer-list>
+20 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?><!--
  ~ Copyright (C) 2024 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.
  -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- dessert_flan is a PNG while ic_brightness is a level-list. -->
    <item android:drawable="@drawable/dessert_flan"/>
    <item android:drawable="@drawable/ic_brightness"/>
</layer-list>