diff options
| author | 2025-02-11 00:49:38 -0800 | |
|---|---|---|
| committer | 2025-02-11 00:49:38 -0800 | |
| commit | 07d2f4be6e00a5494529152ee4a88882cfe71990 (patch) | |
| tree | 1450f971e36767652bc7b618587c35172be4245a | |
| parent | 51ff3146b7ad5b3dc22eee8cc9bed959b3a8df80 (diff) | |
Update menu details for desktop windowing:
- window info pill icon and chevron size/positioning
- "windowing action" pill icons positioning
- "more actions" pill icon size and margin to text
Add Space component in "window actions" pill and logic to account for
positioning of 3 and 4 icons.
Create custom component for "more actions" and "open in" pills options
to properly manage icon size and icon to text spacing.
Fix: 369617114
Test: manual – verify that handle menu options and spacing are properly set for YouTube in app and browser. Verify "window action" icons spacing with 3 and 4 options.
Flag: com.android.window.flags.enable_desktop_windowing_mode
Change-Id: Iac777f33fc5325082d6754ac7816784d56b3bdf9
7 files changed, 239 insertions, 109 deletions
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml index 50c08732543a..477d207a5c7e 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml @@ -41,7 +41,7 @@ android:id="@+id/application_icon" android:layout_width="@dimen/desktop_mode_caption_icon_radius" android:layout_height="@dimen/desktop_mode_caption_icon_radius" - android:layout_marginStart="12dp" + android:layout_marginStart="10dp" android:layout_marginEnd="12dp" android:contentDescription="@string/app_icon_text" android:importantForAccessibility="no"/> @@ -53,10 +53,9 @@ <com.android.wm.shell.windowdecor.HandleMenuImageButton android:id="@+id/collapse_menu_button" - android:layout_width="32dp" - android:layout_height="32dp" - android:padding="4dp" - android:layout_marginEnd="14dp" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_marginEnd="16dp" android:layout_marginStart="14dp" android:contentDescription="@string/collapse_menu_text" android:src="@drawable/ic_baseline_expand_more_24" @@ -78,40 +77,55 @@ <ImageButton android:id="@+id/fullscreen_button" - android:layout_marginEnd="4dp" + android:paddingStart="16dp" + android:paddingEnd="12dp" android:contentDescription="@string/fullscreen_text" android:src="@drawable/desktop_mode_ic_handle_menu_fullscreen" android:tint="@androidprv:color/materialColorOnSurface" - android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> + <Space + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1"/> + <ImageButton android:id="@+id/split_screen_button" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" + android:paddingStart="14dp" + android:paddingEnd="14dp" android:contentDescription="@string/split_screen_text" android:src="@drawable/desktop_mode_ic_handle_menu_splitscreen" android:tint="@androidprv:color/materialColorOnSurface" - android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> + <Space + android:id="@+id/floating_button_space" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1"/> + <ImageButton android:id="@+id/floating_button" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" + android:paddingStart="14dp" + android:paddingEnd="14dp" android:contentDescription="@string/float_button_text" android:src="@drawable/desktop_mode_ic_handle_menu_floating" android:tint="@androidprv:color/materialColorOnSurface" - android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> + <Space + android:id="@+id/desktop_button_space" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1"/> + <ImageButton android:id="@+id/desktop_button" - android:layout_marginStart="4dp" + android:paddingStart="12dp" + android:paddingEnd="16dp" android:contentDescription="@string/desktop_text" android:src="@drawable/desktop_mode_ic_handle_menu_desktop" android:tint="@androidprv:color/materialColorOnSurface" - android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> </LinearLayout> @@ -126,77 +140,33 @@ android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation" android:background="@drawable/desktop_mode_decor_handle_menu_background"> - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/screenshot_button" android:contentDescription="@string/screenshot_text" - style="@style/DesktopModeHandleMenuActionButtonLayout"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_screenshot" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/screenshot_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> + android:text="@string/screenshot_text" + android:src="@drawable/desktop_mode_ic_handle_menu_screenshot" + style="@style/DesktopModeHandleMenuActionButton"/> - </LinearLayout> - - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/new_window_button" android:contentDescription="@string/new_window_text" - style="@style/DesktopModeHandleMenuActionButtonLayout"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_new_window" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/new_window_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> + android:text="@string/new_window_text" + android:src="@drawable/desktop_mode_ic_handle_menu_new_window" + style="@style/DesktopModeHandleMenuActionButton"/> - </LinearLayout> - - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/manage_windows_button" android:contentDescription="@string/manage_windows_text" - style="@style/DesktopModeHandleMenuActionButtonLayout"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_manage_windows" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/manage_windows_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> - - </LinearLayout> + android:text="@string/manage_windows_text" + android:src="@drawable/desktop_mode_ic_handle_menu_manage_windows" + style="@style/DesktopModeHandleMenuActionButton"/> - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/change_aspect_ratio_button" android:contentDescription="@string/change_aspect_ratio_text" - style="@style/DesktopModeHandleMenuActionButtonLayout"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/change_aspect_ratio_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> - - </LinearLayout> + android:text="@string/change_aspect_ratio_text" + android:src="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio" + style="@style/DesktopModeHandleMenuActionButton"/> </LinearLayout> <LinearLayout @@ -209,29 +179,14 @@ android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation" android:background="@drawable/desktop_mode_decor_handle_menu_background"> - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/open_in_app_or_browser_button" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:layout_marginEnd="8dp" - android:gravity="start|center_vertical" - android:paddingStart="16dp" android:contentDescription="@string/open_in_browser_text" - android:background="?android:selectableItemBackground"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_open_in_browser" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/open_in_browser_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> - - </LinearLayout> + android:text="@string/open_in_browser_text" + android:src="@drawable/desktop_mode_ic_handle_menu_open_in_browser" + style="@style/DesktopModeHandleMenuActionButton" + android:layout_width="0dp" + android:layout_weight="1"/> <ImageButton android:id="@+id/open_by_default_button" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml new file mode 100644 index 000000000000..379f4e984b73 --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/action_button" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="start|center_vertical" + android:paddingHorizontal="16dp" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + android:background="?android:attr/selectableItemBackground"> + + <ImageView + android:id="@+id/image" + android:contentDescription="@+id/label" + style="@style/DesktopModeHandleMenuActionButtonImage"/> + + <com.android.wm.shell.windowdecor.MarqueedTextView + android:id="@+id/label" + style="@style/DesktopModeHandleMenuActionButtonTextView"/> +</LinearLayout> diff --git a/libs/WindowManager/Shell/res/values/attrs.xml b/libs/WindowManager/Shell/res/values/attrs.xml index fbb5caa508de..4ba0468a740d 100644 --- a/libs/WindowManager/Shell/res/values/attrs.xml +++ b/libs/WindowManager/Shell/res/values/attrs.xml @@ -23,4 +23,11 @@ <declare-styleable name="MessageState"> <attr name="state_task_focused" format="boolean"/> </declare-styleable> + + <declare-styleable name="HandleMenuActionButton"> + <attr name="android:text" format="string" /> + <attr name="android:textColor" format="color" /> + <attr name="android:src" format="reference" /> + <attr name="android:drawableTint" format="color" /> + </declare-styleable> </resources> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index e23d5725e9c3..96e008e42f1c 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -570,7 +570,7 @@ <dimen name="desktop_mode_handle_menu_corner_radius">26dp</dimen> <!-- The radius of the caption menu icon. --> - <dimen name="desktop_mode_caption_icon_radius">24dp</dimen> + <dimen name="desktop_mode_caption_icon_radius">32dp</dimen> <!-- The radius of the caption menu shadow. --> <dimen name="desktop_mode_handle_menu_shadow_radius">2dp</dimen> diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml index 035004bfd322..637b47ab3ace 100644 --- a/libs/WindowManager/Shell/res/values/styles.xml +++ b/libs/WindowManager/Shell/res/values/styles.xml @@ -40,13 +40,11 @@ <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item> </style> - <style name="DesktopModeHandleMenuActionButtonLayout"> + <style name="DesktopModeHandleMenuActionButton"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">52dp</item> - <item name="android:layout_weight">1</item> - <item name="android:gravity">start|center_vertical</item> - <item name="android:paddingHorizontal">16dp</item> - <item name="android:background">?android:selectableItemBackground</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> + <item name="android:drawableTint">@androidprv:color/materialColorOnSurface</item> </style> <style name="DesktopModeHandleMenuActionButtonImage"> @@ -71,7 +69,6 @@ <style name="DesktopModeHandleMenuWindowingButton"> <item name="android:layout_width">48dp</item> <item name="android:layout_height">48dp</item> - <item name="android:padding">14dp</item> <item name="android:scaleType">fitCenter</item> <item name="android:background">?android:selectableItemBackgroundBorderless</item> </style> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt index a17bcb39f1a0..ff50672953c9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt @@ -37,6 +37,9 @@ import android.view.WindowInsets.Type.systemBars import android.view.WindowManager import android.widget.ImageButton import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.Space +import android.widget.TextView import android.window.DesktopModeFlags import android.window.SurfaceSyncGroup import androidx.annotation.StringRes @@ -480,16 +483,23 @@ class HandleMenu( private val splitscreenBtn = windowingPill.requireViewById<ImageButton>( R.id.split_screen_button) private val floatingBtn = windowingPill.requireViewById<ImageButton>(R.id.floating_button) + private val floatingBtnSpace = windowingPill.requireViewById<Space>( + R.id.floating_button_space) + private val desktopBtn = windowingPill.requireViewById<ImageButton>(R.id.desktop_button) + private val desktopBtnSpace = windowingPill.requireViewById<Space>( + R.id.desktop_button_space) // More Actions Pill. private val moreActionsPill = rootView.requireViewById<View>(R.id.more_actions_pill) - private val screenshotBtn = moreActionsPill.requireViewById<View>(R.id.screenshot_button) - private val newWindowBtn = moreActionsPill.requireViewById<View>(R.id.new_window_button) + private val screenshotBtn = moreActionsPill.requireViewById<HandleMenuActionButton>( + R.id.screenshot_button) + private val newWindowBtn = moreActionsPill.requireViewById<HandleMenuActionButton>( + R.id.new_window_button) private val manageWindowBtn = moreActionsPill - .requireViewById<View>(R.id.manage_windows_button) + .requireViewById<HandleMenuActionButton>(R.id.manage_windows_button) private val changeAspectRatioBtn = moreActionsPill - .requireViewById<View>(R.id.change_aspect_ratio_button) + .requireViewById<HandleMenuActionButton>(R.id.change_aspect_ratio_button) // Open in Browser/App Pill. private val openInAppOrBrowserPill = rootView.requireViewById<View>( @@ -682,6 +692,7 @@ class HandleMenu( if (!BubbleAnythingFlagHelper.enableBubbleToFullscreen()) { floatingBtn.visibility = View.GONE + floatingBtnSpace.visibility = View.GONE } fullscreenBtn.isSelected = taskInfo.isFullscreen @@ -710,8 +721,10 @@ class HandleMenu( ).forEach { val button = it.first val shouldShow = it.second - val label = button.requireViewById<MarqueedTextView>(R.id.label) - val image = button.requireViewById<ImageView>(R.id.image) + + val buttonRoot = button.requireViewById<LinearLayout>(R.id.action_button) + val label = buttonRoot.requireViewById<MarqueedTextView>(R.id.label) + val image = buttonRoot.requireViewById<ImageView>(R.id.image) button.isGone = !shouldShow label.apply { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuActionButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuActionButton.kt new file mode 100644 index 000000000000..4b2e473d6ec2 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuActionButton.kt @@ -0,0 +1,120 @@ +/* + * 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 + +import android.annotation.ColorInt +import android.annotation.IdRes +import android.content.Context +import android.content.res.ColorStateList +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.content.withStyledAttributes +import androidx.core.view.isGone +import com.android.wm.shell.R + +/** + * Button-like component used to display the "Additional options" elements of the Handle menu window + * decoration. + * + * The possible options for which this button is used for are "Screenshot", "New Window", "Manage + * Windows" and "Change Aspect Ratio". + */ +class HandleMenuActionButton @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + private val rootElement: LinearLayout + private val iconView: ImageView + private val textView: MarqueedTextView + + init { + val view = LayoutInflater.from(context).inflate( + R.layout.desktop_mode_window_decor_handle_menu_action_button, this, true) + rootElement = findViewById(R.id.action_button) + iconView = findViewById(R.id.image) + textView = findViewById(R.id.label) + + context.withStyledAttributes(attrs, R.styleable.HandleMenuActionButton) { + textView.text = getString(R.styleable.HandleMenuActionButton_android_text) + textView.setTextColor(getColor(R.styleable.HandleMenuActionButton_android_textColor, 0)) + iconView.setImageResource(getResourceId( + R.styleable.HandleMenuActionButton_android_src, 0)) + iconView.imageTintList = getColorStateList( + R.styleable.HandleMenuActionButton_android_drawableTint) + } + } + + /** + * Sets a listener to be invoked when this view is clicked. + * + * @param l the [OnClickListener] that receives click events. + */ + override fun setOnClickListener(l: OnClickListener?) { + rootElement.setOnClickListener(l) + } + + /** + * Sets the text color for the text inside the button. + * + * @param color the color to set for the text, as a color integer. + */ + fun setTextColor(@ColorInt color: Int) { + textView.setTextColor(color) + } + + /** + * Sets the icon for the button using a resource ID. + * + * @param resourceId the resource ID of the drawable to set as the icon. + */ + fun setIconResource(@IdRes resourceId: Int) { + iconView.setImageResource(resourceId) + } + + /** + * Sets the text to display inside the button. + * + * @param text the text to display. + */ + fun setText(text: CharSequence?) { + textView.text = text + } + + /** + * Sets the tint color for the icon. + * + * @param color the color to use for the tint, as a color integer. + */ + fun setDrawableTint(@ColorInt color: Int) { + iconView.imageTintList = ColorStateList.valueOf(color) + } + + /** + * Gets or sets the tint applied to the icon. + * + * @return The [ColorStateList] representing the tint, or null if no tint is applied. + */ + var compoundDrawableTintList: ColorStateList? + get() = iconView.imageTintList + set(value) { + iconView.imageTintList = value + } +} |