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

Commit a966ce15 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Fixing alpha flag is not retained for fullbleed icons

Bug: 430614471
Test: atest BaseIconFactoryTest
Flag: EXEMPT bugfix
Change-Id: I20754cfb1facc9305660f2237e40c69c06a944b0
parent 1367a127
Loading
Loading
Loading
Loading
+16 −9
Original line number Diff line number Diff line
@@ -178,12 +178,16 @@ constructor(
        }
        if (options.wrapNonAdaptiveIcon) tempIcon = wrapToAdaptiveIcon(tempIcon, options)

        val bitmap = drawableToBitmap(tempIcon, options)
        val drawFullBleed = options.drawFullBleed ?: drawFullBleedIcons
        val bitmap = drawableToBitmap(tempIcon, drawFullBleed, options)
        icon.bounds = oldBounds

        val color = options.extractedColor ?: findDominantColorByHue(bitmap)
        var flagOp = getBitmapFlagOp(options)
        if (drawFullBleedIcons) flagOp = flagOp.addFlag(BitmapInfo.FLAG_FULL_BLEED)
        if (drawFullBleed) {
            flagOp = flagOp.addFlag(BitmapInfo.FLAG_FULL_BLEED)
            bitmap.setHasAlpha(false)
        }

        var info =
            BitmapInfo(
@@ -273,14 +277,16 @@ constructor(
                )
                .apply { setBounds(0, 0, 1, 1) }

    private fun drawableToBitmap(icon: Drawable, options: IconOptions): Bitmap {
        val isFullBleedEnabled = options.drawFullBleed ?: drawFullBleedIcons

    private fun drawableToBitmap(
        icon: Drawable,
        drawFullBleed: Boolean,
        options: IconOptions,
    ): Bitmap {
        if (icon is AdaptiveIconDrawable) {
            // We are ignoring KEY_SHADOW_DISTANCE because regular icons ignore this at the
            // moment b/298203449
            val offset =
                if (isFullBleedEnabled) 0
                if (drawFullBleed) 0
                else
                    max(
                        (ceil(BLUR_FACTOR * iconBitmapSize)).toInt(),
@@ -292,11 +298,11 @@ constructor(
            return createBitmap(options) { canvas, _ ->
                canvas.transformed {
                    translate(offset.toFloat(), offset.toFloat())
                    if (options.addShadows && !isFullBleedEnabled)
                    if (options.addShadows && !drawFullBleed)
                        shadowGenerator.addPathShadow(icon.iconMask, canvas)
                    if (icon is Extender) icon.drawForPersistence()

                    if (isFullBleedEnabled) {
                    if (drawFullBleed) {
                        drawColor(Color.BLACK)
                        icon.background?.draw(canvas)
                        icon.foreground?.draw(canvas)
@@ -316,9 +322,10 @@ constructor(
            iconToDraw.setBounds(0, 0, iconBitmapSize, iconBitmapSize)

            return createBitmap(options) { canvas, bitmap ->
                if (drawFullBleed) canvas.drawColor(Color.BLACK)
                iconToDraw.draw(canvas)

                if (options.addShadows && bitmap != null) {
                if (options.addShadows && bitmap != null && !drawFullBleed) {
                    // Shadow extraction only works in software mode
                    shadowGenerator.drawShadow(bitmap, canvas)

+87 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.launcher3.icons

import android.content.Context
import android.graphics.Color
import android.graphics.drawable.AdaptiveIconDrawable
import android.graphics.drawable.ColorDrawable
import androidx.test.core.app.ApplicationProvider
import com.android.launcher3.icons.BaseIconFactory.IconOptions
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class BaseIconFactoryTest {

    private val context: Context = ApplicationProvider.getApplicationContext()

    @Test
    fun fullBleed_has_no_alpha() {
        val info =
            factory(drawFullBleedIcons = true)
                .createBadgedIconBitmap(AdaptiveIconDrawable(ColorDrawable(Color.RED), null))

        assertFalse(info.icon.hasAlpha())
        assertEquals(BitmapInfo.FLAG_FULL_BLEED, info.flags and BitmapInfo.FLAG_FULL_BLEED)
    }

    @Test
    fun non_fullBleed_has_alpha() {
        val info =
            factory(drawFullBleedIcons = false)
                .createBadgedIconBitmap(AdaptiveIconDrawable(ColorDrawable(Color.RED), null))
        assertTrue(info.icon.hasAlpha())
        assertEquals(0, info.flags and BitmapInfo.FLAG_FULL_BLEED)
    }

    @Test
    fun icon_options_overrides_fullBleed() {
        val info =
            factory(drawFullBleedIcons = false)
                .createBadgedIconBitmap(
                    AdaptiveIconDrawable(ColorDrawable(Color.RED), null),
                    IconOptions().setDrawFullBleed(true),
                )
        assertFalse(info.icon.hasAlpha())
        assertEquals(BitmapInfo.FLAG_FULL_BLEED, info.flags and BitmapInfo.FLAG_FULL_BLEED)

        val info2 =
            factory(drawFullBleedIcons = true)
                .createBadgedIconBitmap(
                    AdaptiveIconDrawable(ColorDrawable(Color.RED), null),
                    IconOptions().setDrawFullBleed(false),
                )
        assertTrue(info2.icon.hasAlpha())
        assertEquals(0, info2.flags and BitmapInfo.FLAG_FULL_BLEED)
    }

    private fun factory(
        fullResIconDpi: Int = context.resources.displayMetrics.densityDpi,
        iconBitmapSize: Int = 64,
        drawFullBleedIcons: Boolean = false,
        themeController: IconThemeController? = null,
    ) =
        BaseIconFactory(
            context = context,
            fullResIconDpi = fullResIconDpi,
            iconBitmapSize = iconBitmapSize,
            drawFullBleedIcons = drawFullBleedIcons,
            themeController = themeController,
        )
}