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

Commit 9d586817 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 13764426 from 17641910 to 25Q4-release

Change-Id: I0926fbe06c5b46e1e45a7662e3237bd8889b22ee
parents 98f51d1e 17641910
Loading
Loading
Loading
Loading
+51 −0
Original line number Diff line number Diff line
@@ -21,9 +21,15 @@ import android.hardware.display.DisplayManager.DisplayListener
import android.hardware.display.DisplayManager.EVENT_TYPE_DISPLAY_ADDED
import android.hardware.display.DisplayManager.EVENT_TYPE_DISPLAY_CHANGED
import android.hardware.display.DisplayManager.EVENT_TYPE_DISPLAY_REMOVED
import android.hardware.display.DisplayManager.EXTERNAL_DISPLAY_CONNECTION_PREFERENCE_ASK
import android.hardware.display.DisplayManager.EXTERNAL_DISPLAY_CONNECTION_PREFERENCE_DESKTOP
import android.hardware.display.DisplayManager.EXTERNAL_DISPLAY_CONNECTION_PREFERENCE_MIRROR
import android.os.Handler
import android.util.Log
import android.view.Display
import com.android.app.displaylib.ExternalDisplayConnectionType.DESKTOP
import com.android.app.displaylib.ExternalDisplayConnectionType.MIRROR
import com.android.app.displaylib.ExternalDisplayConnectionType.NOT_SPECIFIED
import com.android.app.tracing.FlowTracing.traceEach
import com.android.app.tracing.traceSection
import javax.inject.Inject
@@ -113,6 +119,20 @@ interface DisplayRepository {
        /** Id of the pending display. */
        val id: Int

        /**
         * The saved connection preference for the display, either desktop, mirroring or show the
         * dialog. Defaults to [ExternalDisplayConnectionType.NOT_SPECIFIED], if no value saved.
         */
        val connectionType: ExternalDisplayConnectionType

        /**
         * Updates the saved connection preference for the display, triggered by the connection
         * dialog's "remember my choice" checkbox
         *
         * @see com.android.systemui.display.ui.viewmodel.ConnectingDisplayViewModel
         */
        suspend fun updateConnectionPreference(connectionType: ExternalDisplayConnectionType)

        /** Enables the display, making it available to the system. */
        suspend fun enable()

@@ -353,8 +373,28 @@ constructor(
        pendingDisplayId
            .map { displayId ->
                val id = displayId ?: return@map null
                val pendingDisplay = getDisplay(id) ?: displayManager.getDisplay(id)
                val uniqueId = pendingDisplay?.uniqueId ?: return@map null
                val connectionPreference =
                    displayManager.getExternalDisplayConnectionPreference(uniqueId)

                object : DisplayRepository.PendingDisplay {
                    override val id = id
                    override val connectionType: ExternalDisplayConnectionType =
                        when (connectionPreference) {
                            EXTERNAL_DISPLAY_CONNECTION_PREFERENCE_DESKTOP -> DESKTOP
                            EXTERNAL_DISPLAY_CONNECTION_PREFERENCE_MIRROR -> MIRROR
                            else -> NOT_SPECIFIED
                        }

                    override suspend fun updateConnectionPreference(
                        connectionType: ExternalDisplayConnectionType
                    ) {
                        displayManager.setExternalDisplayConnectionPreference(
                            uniqueId,
                            connectionType.preference,
                        )
                    }

                    override suspend fun enable() {
                        traceSection("DisplayRepository#enable($id)") {
@@ -459,6 +499,17 @@ constructor(
    }
}

/**
 * Possible connection types for an external display.
 *
 * @property preference The integer value that represents the connection type in the system.
 */
enum class ExternalDisplayConnectionType(val preference: Int) {
    NOT_SPECIFIED(EXTERNAL_DISPLAY_CONNECTION_PREFERENCE_ASK),
    DESKTOP(EXTERNAL_DISPLAY_CONNECTION_PREFERENCE_DESKTOP),
    MIRROR(EXTERNAL_DISPLAY_CONNECTION_PREFERENCE_MIRROR),
}

/** Used to provide default implementations for all methods. */
private interface DisplayConnectionListener : DisplayListener {

+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)

+1 −1
Original line number Diff line number Diff line
@@ -213,7 +213,7 @@ data class BitmapInfo(
    companion object {
        const val TAG: String = "BitmapInfo"

        // BitmapInfo flags
        // Persisted BitmapInfo flags. Reset the cache whenever making any changes here.
        const val FLAG_WORK: Int = 1 shl 0
        const val FLAG_INSTANT: Int = 1 shl 1
        const val FLAG_CLONE: Int = 1 shl 2
+1 −1
Original line number Diff line number Diff line
@@ -653,7 +653,7 @@ constructor(
            ComponentKey(ComponentName(packageName, packageName + EMPTY_CLASS_NAME), user)

        // Ensures themed bitmaps in the icon cache are invalidated
        @JvmField val RELEASE_VERSION = if (Flags.enableLauncherIconShapes()) 13 else 12
        @JvmField val RELEASE_VERSION = if (Flags.enableLauncherIconShapes()) 14 else 12

        @JvmField val TABLE_NAME = "icons"
        @JvmField val COLUMN_ROWID = "rowid"
+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,
        )
}
Loading