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

Commit 890914ac authored by Jeff DeCew's avatar Jeff DeCew Committed by Android (Google) Code Review
Browse files

Merge "Bundle header tweaks" into main

parents 4a94e6fd f9162723
Loading
Loading
Loading
Loading
+3 −8
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -37,7 +36,6 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
@@ -225,7 +223,8 @@ private fun ContentScope.BundlePreviewIcons(
    check(previewDrawables.isNotEmpty())
    val iconSize = 32.dp

    val borderWidth = 2.5.dp
    // The design stroke width is 2.5dp but there is a ~4% padding inside app icons; ~1.25dp here.
    val borderWidth = 1.25.dp
    HalfOverlappingReversedRow(
        modifier =
            modifier.graphicsLayer {
@@ -275,14 +274,10 @@ private fun PreviewIcon(drawable: Drawable, modifier: Modifier = Modifier, borde
                drawContent()
            }
    ) {
        val surfaceColor = notificationElementSurfaceColor()
        Image(
            painter = rememberDrawablePainter(drawable),
            contentDescription = null,
            modifier =
                Modifier.fillMaxSize()
                    .clip(CircleShape)
                    .background(color = surfaceColor, shape = CircleShape),
            modifier = Modifier.fillMaxSize(),
            contentScale = ContentScale.Fit,
        )
    }
+58 −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.systemui.notifications.ui.composable.row

import androidx.annotation.FloatRange
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.graphics.Color

@Composable
@ReadOnlyComposable
fun notificationProtectionColor(): Color {
    // Per android.app.Notification.Colors, this is a 90% blend
    // of materialColorOnSurface over materialColorSurfaceContainerHigh
    val background = MaterialTheme.colorScheme.surfaceContainerHigh
    val primaryText = MaterialTheme.colorScheme.onSurface
    return blendARGB(primaryText, background, 0.9f)
}

/**
 * Blend between two ARGB colors using the given ratio.
 *
 * A blend ratio of 0.0 will result in [color1], 0.5 will give an even blend, 1.0 will result in
 * [color2].
 *
 * @param color1 the first ARGB color
 * @param color2 the second ARGB color
 * @param ratio the blend ratio of [color1] to [color2]
 * @see [com.android.internal.graphics.ColorUtils.blendARGB]
 */
private fun blendARGB(
    color1: Color,
    color2: Color,
    @FloatRange(from = 0.0, to = 1.0) ratio: Float,
): Color {
    val inverseRatio = 1 - ratio
    return Color(
        red = color1.red * inverseRatio + color2.red * ratio,
        green = color1.green * inverseRatio + color2.green * ratio,
        blue = color1.blue * inverseRatio + color2.blue * ratio,
        alpha = color1.alpha * inverseRatio + color2.alpha * ratio,
    )
}
+3 −15
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.systemui.notifications.ui.composable.row
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
@@ -33,7 +32,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -68,8 +66,8 @@ object NotificationRowPrimitives {
/** The Icon displayed at the start of any notification row. */
@Composable
fun BundleIcon(@DrawableRes drawable: Int?, modifier: Modifier = Modifier) {
    val surfaceColor = notificationElementSurfaceColor()
    Box(modifier = modifier.size(40.dp).background(color = surfaceColor, shape = CircleShape)) {
    val iconBackground = notificationProtectionColor()
    Box(modifier = modifier.size(40.dp).background(color = iconBackground, shape = CircleShape)) {
        if (drawable == null) return@Box
        Image(
            painter = painterResource(drawable),
@@ -115,7 +113,7 @@ fun ContentScope.ExpansionControl(

@Composable
private fun ContentScope.PillBackground(modifier: Modifier = Modifier) {
    val surfaceColor = notificationElementSurfaceColor()
    val surfaceColor = notificationProtectionColor()
    // Needs to be a shared element so it does not overlap while animating
    ElementWithValues(NotificationRowPrimitives.Elements.PillBackground, modifier) {
        Box(
@@ -130,16 +128,6 @@ private fun ContentScope.PillBackground(modifier: Modifier = Modifier) {
    }
}

@Composable
@ReadOnlyComposable
fun notificationElementSurfaceColor(): Color {
    return if (isSystemInDarkTheme()) {
        Color.White.copy(alpha = 0.15f)
    } else {
        MaterialTheme.colorScheme.surfaceContainerHighest
    }
}

@Composable
private fun ContentScope.Chevron(collapsed: Boolean, color: Color, modifier: Modifier = Modifier) {
    val key = NotificationRowPrimitives.Elements.Chevron
+16 −2
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.UserHandle
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.internal.R
import com.android.launcher3.icons.BaseIconFactory
import com.android.launcher3.icons.BaseIconFactory.IconOptions
@@ -211,13 +212,26 @@ constructor(
        return iconFactory.createBadgedIconBitmap(icon, options)
    }

    @VisibleForTesting
    fun createAppIconForTest(packageName: String, @UserIconInfo.UserType userType: Int): Drawable {
        val pm = sysuiContext.packageManager
        val userHandle = UserHandle.of(pm.userId)
        val icon = pm.getApplicationInfo(packageName, 0).loadUnbadgedIcon(pm)
        val options = iconOptions(UserIconInfo(userHandle, userType))
        val bitmapInfo = standardIconFactory.createBadgedIconBitmap(icon, options)
        return bitmapInfo.createIconDrawable(themed = false)
    }

    private fun BitmapInfo.createIconDrawable(themed: Boolean): Drawable =
        newIcon(context = sysuiContext, creationFlags = if (themed) BitmapInfo.FLAG_THEMED else 0)
            .apply { isAnimationEnabled = false }

    private fun iconOptions(userHandle: UserHandle, allowProfileBadge: Boolean): IconOptions {
    private fun iconOptions(userHandle: UserHandle, allowProfileBadge: Boolean): IconOptions =
        iconOptions(userIconInfo(userHandle, allowProfileBadge = allowProfileBadge))

    private fun iconOptions(userIconInfo: UserIconInfo): IconOptions {
        return IconOptions().apply {
            setUser(userIconInfo(userHandle, allowProfileBadge = allowProfileBadge))
            setUser(userIconInfo)
            setBitmapGenerationMode(BaseIconFactory.MODE_HARDWARE)
            // This color will not be used, but we're just setting it so that the icon factory
            // doesn't try to extract colors from our bitmap (since it won't work, given it's a