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

Commit cf722565 authored by Fabio Muratori's avatar Fabio Muratori Committed by Android (Google) Code Review
Browse files

Merge "Hover/Ripple effect update for window actions of Handle Menu windowing...

Merge "Hover/Ripple effect update for window actions of Handle Menu windowing decoration:" into main
parents 3a7aace0 433101bc
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -618,6 +618,15 @@
    <!-- The vertical inset to apply to the app chip's ripple drawable -->
    <dimen name="desktop_mode_header_app_chip_ripple_inset_vertical">4dp</dimen>

     <!-- The corner radius of the windowing actions pill buttons's ripple drawable -->
     <dimen name="desktop_mode_handle_menu_windowing_action_ripple_radius">24dp</dimen>
     <!-- The horizontal/vertical inset to apply to the ripple drawable effect of windowing
     actions pill central buttons -->
     <dimen name="desktop_mode_handle_menu_windowing_action_ripple_inset_base">2dp</dimen>
     <!-- The horizontal/vertical vertical inset to apply to the ripple drawable effect of windowing
     actions pill edge buttons -->
     <dimen name="desktop_mode_handle_menu_windowing_action_ripple_inset_shift">4dp</dimen>

    <!-- The corner radius of the minimize button's ripple drawable -->
    <dimen name="desktop_mode_header_minimize_ripple_radius">18dp</dimen>
    <!-- The vertical inset to apply to the minimize button's ripple drawable -->
+74 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.Accessibilit
import androidx.core.view.isGone
import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.bubbles.ContextUtils.isRtl
import com.android.wm.shell.shared.annotations.ShellBackgroundThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper
@@ -60,6 +61,8 @@ import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewCo
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
import com.android.wm.shell.windowdecor.common.calculateMenuPosition
import com.android.wm.shell.windowdecor.common.DrawableInsets
import com.android.wm.shell.windowdecor.common.createRippleDrawable
import com.android.wm.shell.windowdecor.extension.isFullscreen
import com.android.wm.shell.windowdecor.extension.isMultiWindow
import com.android.wm.shell.windowdecor.extension.isPinned
@@ -71,6 +74,7 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext


/**
 * Handle menu opened when the appropriate button is clicked on.
 *
@@ -467,6 +471,33 @@ class HandleMenu(
        val rootView = LayoutInflater.from(context)
            .inflate(R.layout.desktop_mode_window_decor_handle_menu, null /* root */) as View

        private val windowingButtonRippleRadius = context.resources
            .getDimensionPixelSize(R.dimen.desktop_mode_handle_menu_windowing_action_ripple_radius)
        private val windowingButtonDrawableInsets = DrawableInsets(
            vertical = context.resources
                .getDimensionPixelSize(
                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base),
            horizontal = context.resources
                .getDimensionPixelSize(
                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base)
        )
        private val windowingButtonDrawableInsetsLeft = DrawableInsets(
            vertical = context.resources
                .getDimensionPixelSize(
                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base),
            horizontalLeft = context.resources
                .getDimensionPixelSize(
                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_shift),
        )
        private val windowingButtonDrawableInsetsRight = DrawableInsets(
            vertical = context.resources
                .getDimensionPixelSize(
                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base),
            horizontalRight = context.resources
                .getDimensionPixelSize(
                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_shift)
        )

        // App Info Pill.
        private val appInfoPill = rootView.requireViewById<View>(R.id.app_info_pill)
        private val collapseMenuButton = appInfoPill.requireViewById<HandleMenuImageButton>(
@@ -708,6 +739,49 @@ class HandleMenu(
            desktopBtn.isSelected = taskInfo.isFreeform
            desktopBtn.isEnabled = !taskInfo.isFreeform
            desktopBtn.imageTintList = style.windowingButtonColor

            val startInsets = if (context.isRtl) {
                windowingButtonDrawableInsetsRight
            } else {
                windowingButtonDrawableInsetsLeft
            }
            val endInsets = if (context.isRtl) {
                windowingButtonDrawableInsetsLeft
            } else {
                windowingButtonDrawableInsetsRight
            }

            fullscreenBtn.apply {
                background = createRippleDrawable(
                    color = style.textColor,
                    cornerRadius = windowingButtonRippleRadius,
                    drawableInsets = startInsets
                )
            }

            splitscreenBtn.apply {
                background = createRippleDrawable(
                    color = style.textColor,
                    cornerRadius = windowingButtonRippleRadius,
                    drawableInsets = windowingButtonDrawableInsets
                )
            }

            floatingBtn.apply {
                background = createRippleDrawable(
                    color = style.textColor,
                    cornerRadius = windowingButtonRippleRadius,
                    drawableInsets = windowingButtonDrawableInsets
                )
            }

            desktopBtn.apply {
                background = createRippleDrawable(
                    color = style.textColor,
                    cornerRadius = windowingButtonRippleRadius,
                    drawableInsets = endInsets
                )
            }
        }

        private fun bindMoreActionsPill(style: MenuStyle) {
+88 −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.wm.shell.windowdecor.common

import android.annotation.ColorInt
import android.graphics.Color
import android.graphics.drawable.LayerDrawable
import android.graphics.drawable.RippleDrawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import com.android.wm.shell.windowdecor.common.OPACITY_11
import com.android.wm.shell.windowdecor.common.OPACITY_15
import android.content.res.ColorStateList

/**
 * Represents drawable insets, specifying the number of pixels to inset a drawable from its bounds.
 */
data class DrawableInsets(val l: Int, val t: Int, val r: Int, val b: Int) {
    constructor(vertical: Int = 0, horizontal: Int = 0) :
            this(horizontal, vertical, horizontal, vertical)
    constructor(vertical: Int = 0, horizontalLeft: Int = 0, horizontalRight: Int = 0) :
            this(horizontalLeft, vertical, horizontalRight, vertical)
}

/**
 * Replaces the alpha component of a color with the given alpha value.
 */
@ColorInt
fun replaceColorAlpha(@ColorInt color: Int, alpha: Int): Int {
    return Color.argb(
        alpha,
        Color.red(color),
        Color.green(color),
        Color.blue(color)
    )
}

/**
 * Creates a RippleDrawable with specified color, corner radius, and insets.
 */
fun createRippleDrawable(
            @ColorInt color: Int,
            cornerRadius: Int,
            drawableInsets: DrawableInsets,
): RippleDrawable {
    return RippleDrawable(
        ColorStateList(
            arrayOf(
                intArrayOf(android.R.attr.state_hovered),
                intArrayOf(android.R.attr.state_pressed),
                intArrayOf(),
            ),
            intArrayOf(
                replaceColorAlpha(color, OPACITY_11),
                replaceColorAlpha(color, OPACITY_15),
                Color.TRANSPARENT,
            )
        ),
        null /* content */,
        LayerDrawable(arrayOf(
            ShapeDrawable().apply {
                shape = RoundRectShape(
                    FloatArray(8) { cornerRadius.toFloat() },
                    null /* inset */,
                    null /* innerRadii */
                )
                paint.color = Color.WHITE
            }
        )).apply {
            require(numberOfLayers == 1) { "Must only contain one layer" }
            setLayerInset(0 /* index */,
                drawableInsets.l, drawableInsets.t, drawableInsets.r, drawableInsets.b)
        }
    )
}
+2 −51
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@ import com.android.wm.shell.windowdecor.common.OPACITY_15
import com.android.wm.shell.windowdecor.common.OPACITY_55
import com.android.wm.shell.windowdecor.common.OPACITY_65
import com.android.wm.shell.windowdecor.common.Theme
import com.android.wm.shell.windowdecor.common.DrawableInsets
import com.android.wm.shell.windowdecor.common.createRippleDrawable
import com.android.wm.shell.windowdecor.extension.isLightCaptionBarAppearance
import com.android.wm.shell.windowdecor.extension.isTransparentCaptionBarAppearance

@@ -635,61 +637,10 @@ class AppHeaderViewHolder(
        )
    }

    @ColorInt
    private fun replaceColorAlpha(@ColorInt color: Int, alpha: Int): Int {
        return Color.argb(
            alpha,
            Color.red(color),
            Color.green(color),
            Color.blue(color)
        )
    }

    private fun createRippleDrawable(
        @ColorInt color: Int,
        cornerRadius: Int,
        drawableInsets: DrawableInsets,
    ): RippleDrawable {
        return RippleDrawable(
            ColorStateList(
                arrayOf(
                    intArrayOf(android.R.attr.state_hovered),
                    intArrayOf(android.R.attr.state_pressed),
                    intArrayOf(),
                ),
                intArrayOf(
                    replaceColorAlpha(color, OPACITY_11),
                    replaceColorAlpha(color, OPACITY_15),
                    Color.TRANSPARENT
                )
            ),
            null /* content */,
            LayerDrawable(arrayOf(
                ShapeDrawable().apply {
                    shape = RoundRectShape(
                        FloatArray(8) { cornerRadius.toFloat() },
                        null /* inset */,
                        null /* innerRadii */
                    )
                    paint.color = Color.WHITE
                }
            )).apply {
                require(numberOfLayers == 1) { "Must only contain one layer" }
                setLayerInset(0 /* index */,
                    drawableInsets.l, drawableInsets.t, drawableInsets.r, drawableInsets.b)
            }
        )
    }

    private enum class SizeToggleDirection {
        MAXIMIZE, RESTORE
    }

    private data class DrawableInsets(val l: Int, val t: Int, val r: Int, val b: Int) {
        constructor(vertical: Int = 0, horizontal: Int = 0) :
                this(horizontal, vertical, horizontal, vertical)
    }

    private data class Header(
        val type: Type,
        val appTheme: Theme,