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

Commit 0530e881 authored by Bartosz Chominski's avatar Bartosz Chominski
Browse files

Change ellipsis mode of handle menu labels

UI spec: https://www.figma.com/design/flC1tPqknJnIVa8m5fhUQv/App-Headers-%26-Menus-(V)?node-id=5801-145545

Fix: 355522194
Flag: com.android.window.flags.enable_desktop_windowing_mode
Test: manual — verify that labels in the handle menu are legible and marqueed (if exceed width) in handle menu for Google Play Store with different system font sizes
Change-Id: I588d31fc6be4fb7b4ebf9bb12e21927cb997e792
parent 55c5e824
Loading
Loading
Loading
Loading
+83 −35
Original line number Diff line number Diff line
@@ -46,17 +46,10 @@
            android:contentDescription="@string/app_icon_text"
            android:importantForAccessibility="no"/>

        <TextView
        <com.android.wm.shell.windowdecor.MarqueedTextView
            android:id="@+id/application_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            tools:text="Gmail"
            android:textColor="@androidprv:color/materialColorOnSurface"
            android:textSize="14sp"
            android:textFontWeight="500"
            android:lineHeight="20dp"
            android:textStyle="normal"
            android:layout_weight="1"/>
            style="@style/DesktopModeHandleMenuActionButtonTextView"/>

        <com.android.wm.shell.windowdecor.HandleMenuImageButton
            android:id="@+id/collapse_menu_button"
@@ -133,37 +126,77 @@
        android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation"
        android:background="@drawable/desktop_mode_decor_handle_menu_background">

        <Button
        <LinearLayout
            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"
            android:drawableStart="@drawable/desktop_mode_ic_handle_menu_screenshot"
            android:drawableTint="@androidprv:color/materialColorOnSurface"
            style="@style/DesktopModeHandleMenuActionButton"/>
                style="@style/DesktopModeHandleMenuActionButtonTextView"/>

        </LinearLayout>

        <Button
        <LinearLayout
            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"
            android:drawableStart="@drawable/desktop_mode_ic_handle_menu_new_window"
            android:drawableTint="@androidprv:color/materialColorOnSurface"
            style="@style/DesktopModeHandleMenuActionButton" />
                style="@style/DesktopModeHandleMenuActionButtonTextView"/>

        </LinearLayout>

        <Button
        <LinearLayout
            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"
            android:drawableStart="@drawable/desktop_mode_ic_handle_menu_manage_windows"
            android:drawableTint="@androidprv:color/materialColorOnSurface"
            style="@style/DesktopModeHandleMenuActionButton" />
                style="@style/DesktopModeHandleMenuActionButtonTextView"/>

        </LinearLayout>

        <Button
        <LinearLayout
            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"
            android:drawableStart="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio"
            android:drawableTint="@androidprv:color/materialColorOnSurface"
            style="@style/DesktopModeHandleMenuActionButton" />
                style="@style/DesktopModeHandleMenuActionButtonTextView"/>

        </LinearLayout>
    </LinearLayout>

    <LinearLayout
@@ -176,22 +209,37 @@
        android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation"
        android:background="@drawable/desktop_mode_decor_handle_menu_background">

        <Button
        <LinearLayout
            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"
            android:drawableStart="@drawable/desktop_mode_ic_handle_menu_open_in_browser"
            android:drawableTint="@androidprv:color/materialColorOnSurface"
            style="@style/DesktopModeHandleMenuActionButton"/>
                style="@style/DesktopModeHandleMenuActionButtonTextView"/>

        </LinearLayout>

        <ImageButton
            android:id="@+id/open_by_default_button"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_gravity="end|center_vertical"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="16dp"
            android:layout_marginStart="10dp"
            android:contentDescription="@string/open_by_default_settings_text"
            android:src="@drawable/desktop_mode_ic_handle_menu_open_by_default_settings"
            android:tint="@androidprv:color/materialColorOnSurface"/>
+22 −7
Original line number Diff line number Diff line
@@ -40,17 +40,32 @@
        <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
    </style>

    <style name="DesktopModeHandleMenuActionButton">
    <style name="DesktopModeHandleMenuActionButtonLayout">
        <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:paddingStart">16dp</item>
        <item name="android:paddingEnd">0dp</item>
        <item name="android:paddingHorizontal">16dp</item>
        <item name="android:background">?android:selectableItemBackground</item>
    </style>

    <style name="DesktopModeHandleMenuActionButtonImage">
       <item name="android:layout_width">20dp</item>
       <item name="android:layout_height">20dp</item>
       <item name="android:layout_marginEnd">16dp</item>
   </style>

    <style name="DesktopModeHandleMenuActionButtonTextView">
       <item name="android:layout_width">0dp</item>
       <item name="android:layout_height">wrap_content</item>
       <item name="android:layout_weight">1</item>
       <item name="android:textSize">14sp</item>
       <item name="android:lineHeight">20sp</item>
       <item name="android:textFontWeight">500</item>
       <item name="android:textColor">@androidprv:color/materialColorOnSurface</item>
        <item name="android:drawablePadding">16dp</item>
        <item name="android:background">?android:selectableItemBackground</item>
       <item name="android:ellipsize">marquee</item>
       <item name="android:scrollHorizontally">true</item>
       <item name="android:singleLine">true</item>
   </style>

    <style name="DesktopModeHandleMenuWindowingButton">
+22 −12
Original line number Diff line number Diff line
@@ -473,7 +473,7 @@ class HandleMenu(
        @VisibleForTesting
        val appIconView = appInfoPill.requireViewById<ImageView>(R.id.application_icon)
        @VisibleForTesting
        val appNameView = appInfoPill.requireViewById<TextView>(R.id.application_name)
        val appNameView = appInfoPill.requireViewById<MarqueedTextView>(R.id.application_name)

        // Windowing Pill.
        private val windowingPill = rootView.requireViewById<View>(R.id.windowing_pill)
@@ -486,17 +486,17 @@ class HandleMenu(

        // More Actions Pill.
        private val moreActionsPill = rootView.requireViewById<View>(R.id.more_actions_pill)
        private val screenshotBtn = moreActionsPill.requireViewById<Button>(R.id.screenshot_button)
        private val newWindowBtn = moreActionsPill.requireViewById<Button>(R.id.new_window_button)
        private val screenshotBtn = moreActionsPill.requireViewById<View>(R.id.screenshot_button)
        private val newWindowBtn = moreActionsPill.requireViewById<View>(R.id.new_window_button)
        private val manageWindowBtn = moreActionsPill
            .requireViewById<Button>(R.id.manage_windows_button)
            .requireViewById<View>(R.id.manage_windows_button)
        private val changeAspectRatioBtn = moreActionsPill
            .requireViewById<Button>(R.id.change_aspect_ratio_button)
            .requireViewById<View>(R.id.change_aspect_ratio_button)

        // Open in Browser/App Pill.
        private val openInAppOrBrowserPill = rootView.requireViewById<View>(
            R.id.open_in_app_or_browser_pill)
        private val openInAppOrBrowserBtn = openInAppOrBrowserPill.requireViewById<Button>(
        private val openInAppOrBrowserBtn = openInAppOrBrowserPill.requireViewById<View>(
            R.id.open_in_app_or_browser_button)
        private val openByDefaultBtn = openInAppOrBrowserPill.requireViewById<ImageButton>(
            R.id.open_by_default_button)
@@ -658,6 +658,7 @@ class HandleMenu(
                this.taskInfo = this@HandleMenuView.taskInfo
            }
            appNameView.setTextColor(style.textColor)
            appNameView.startMarquee()
        }

        private fun bindWindowingPill(style: MenuStyle) {
@@ -693,11 +694,15 @@ class HandleMenu(
            ).forEach {
                val button = it.first
                val shouldShow = it.second
                button.apply {
                    isGone = !shouldShow
                val label = button.requireViewById<MarqueedTextView>(R.id.label)
                val image = button.requireViewById<ImageView>(R.id.image)

                button.isGone = !shouldShow
                label.apply {
                    setTextColor(style.textColor)
                    compoundDrawableTintList = ColorStateList.valueOf(style.textColor)
                    startMarquee()
                }
                image.imageTintList = ColorStateList.valueOf(style.textColor)
            }
        }

@@ -712,12 +717,17 @@ class HandleMenu(
            } else {
                getString(R.string.open_in_browser_text)
            }
            openInAppOrBrowserBtn.apply {

            val label = openInAppOrBrowserBtn.requireViewById<MarqueedTextView>(R.id.label)
            val image = openInAppOrBrowserBtn.requireViewById<ImageView>(R.id.image)
            openInAppOrBrowserBtn.contentDescription = btnText
            label.apply {
                text = btnText
                contentDescription = btnText
                setTextColor(style.textColor)
                compoundDrawableTintList = ColorStateList.valueOf(style.textColor)
                startMarquee()
            }
            image.imageTintList = ColorStateList.valueOf(style.textColor)

            openByDefaultBtn.isGone = isBrowserApp
            openByDefaultBtn.imageTintList = ColorStateList.valueOf(style.textColor)
        }
+1 −1
Original line number Diff line number Diff line
@@ -327,7 +327,7 @@ class HandleMenuAnimator(
                }

        // Open in Browser Button Opacity Animation
        val button = openInAppOrBrowserPill.requireViewById<Button>(R.id.open_in_app_or_browser_button)
        val button = openInAppOrBrowserPill.requireViewById<View>(R.id.open_in_app_or_browser_button)
        animators +=
                ObjectAnimator.ofFloat(button, ALPHA, 1f).apply {
                    startDelay = BODY_ALPHA_OPEN_DELAY
+48 −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

import android.content.Context
import android.util.AttributeSet
import android.widget.TextView

/** A custom [TextView] that allows better control over marquee animation used to ellipsize text. */
class MarqueedTextView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = android.R.attr.textViewStyle
) : TextView(context, attrs, defStyleAttr) {

    /**
     * Starts marquee animation if the layout attributes for this object include
     * `android:ellipsize=marquee`, `android:singleLine=true`, and
     * `android:scrollHorizontally=true`.
     */
    override public fun startMarquee() {
        super.startMarquee()
    }

    /**
     * Must always return [true] since [TextView.startMarquee()] requires view to be selected or
     * focused in order to start the marquee animation.
     *
     * We are not using [TextView.setSelected()] as this would dispatch undesired accessibility
     * events.
     */
    override fun isSelected() : Boolean {
        return true
    }
}