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

Commit 3a8eb242 authored by Daniel Akinola's avatar Daniel Akinola
Browse files

Update desktop app header a11y strings so buttons announce app name

Close Window, Minimize Window & Maximize/Restore Window buttons will now
announce "Close/Minimize/Maximize/Restore (App Name), double tap to
close/minimize/maximize/restore app window"  when focused by talkback
a11y focus

Fix: 397578815
Test: Enter deskop windowing with an app, turn on Talkback, select app
header buttons and listen for talkback announcement
Flag: EXEMPT bugfix

Change-Id: I00c735637777e871c366aeabfa03c5f52f10553d
parent cd319544
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -37,20 +37,17 @@
        style="@style/CaptionButtonStyle"
        android:id="@+id/minimize_window"
        android:layout_gravity="center_vertical|end"
        android:contentDescription="@string/minimize_button_text"
        android:background="@drawable/decor_minimize_button_dark"
        android:duplicateParentState="true"/>
    <Button
        style="@style/CaptionButtonStyle"
        android:id="@+id/maximize_window"
        android:layout_gravity="center_vertical|end"
        android:contentDescription="@string/maximize_button_text"
        android:background="@drawable/decor_maximize_button_dark"
        android:duplicateParentState="true"/>
    <Button
        style="@style/CaptionButtonStyle"
        android:id="@+id/close_window"
        android:contentDescription="@string/close_button_text"
        android:background="@drawable/decor_close_button_dark"
        android:duplicateParentState="true"/>
</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
 No newline at end of file
+12 −6
Original line number Diff line number Diff line
@@ -276,11 +276,13 @@

    <!-- Freeform window caption strings -->
    <!-- Accessibility text for the maximize window button [CHAR LIMIT=NONE] -->
    <string name="maximize_button_text">Maximize</string>
    <string name="maximize_button_text">Maximize <xliff:g id="app_name" example="Chrome">%1$s</xliff:g></string>
    <!-- Accessibility text for the restore window button [CHAR LIMIT=NONE] -->
    <string name="restore_button_text">Restore <xliff:g id="app_name" example="Chrome">%1$s</xliff:g></string>
     <!-- Accessibility text for the minimize window button [CHAR LIMIT=NONE] -->
     <string name="minimize_button_text">Minimize</string>
     <string name="minimize_button_text">Minimize <xliff:g id="app_name" example="Chrome">%1$s</xliff:g></string>
    <!-- Accessibility text for the close window button [CHAR LIMIT=NONE] -->
    <string name="close_button_text">Close</string>
    <string name="close_button_text">Close <xliff:g id="app_name" example="Chrome">%1$s</xliff:g></string>
    <!-- Accessibility text for the caption back button [CHAR LIMIT=NONE] -->
    <string name="back_button_text">Back</string>
    <!-- Accessibility text for the caption handle [CHAR LIMIT=NONE] -->
@@ -352,10 +354,14 @@
    <string name="maximize_menu_talkback_action_snap_right_text">Resize window to right</string>
    <!-- Accessibility action replacement for maximize menu enter maximize/restore button [CHAR LIMIT=NONE] -->
    <string name="maximize_menu_talkback_action_maximize_restore_text">Maximize or restore window size</string>
    <!-- Accessibility action replacement for app header maximize/restore button [CHAR LIMIT=NONE] -->
    <string name="maximize_button_talkback_action_maximize_restore_text">Maximize or restore window size</string>
    <!-- Accessibility action replacement for app header maximize button [CHAR LIMIT=NONE] -->
    <string name="app_header_talkback_action_maximize_button_text">Maximize app window size</string>
    <!-- Accessibility action replacement for app header restore button [CHAR LIMIT=NONE] -->
    <string name="app_header_talkback_action_restore_button_text">Restore window size</string>
    <!-- Accessibility action replacement for app header minimize button [CHAR LIMIT=NONE] -->
    <string name="minimize_button_talkback_action_maximize_restore_text">Minimize app window</string>
    <string name="app_header_talkback_action_minimize_button_text">Minimize app window</string>
    <!-- Accessibility action replacement for app header close button [CHAR LIMIT=NONE] -->
    <string name="app_header_talkback_action_close_button_text">Close app window</string>

    <!-- Accessibility text for open by default settings button [CHAR LIMIT=NONE] -->
    <string name="open_by_default_settings_text">Open by default settings</string>
+1 −14
Original line number Diff line number Diff line
@@ -39,10 +39,7 @@ import android.window.DesktopModeFlags
private const val OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS = 350
private const val MAX_DRAWABLE_ALPHA = 255

class MaximizeButtonView(
        context: Context,
        attrs: AttributeSet
) : FrameLayout(context, attrs) {
class MaximizeButtonView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) {
    lateinit var onHoverAnimationFinishedListener: () -> Unit
    private val hoverProgressAnimatorSet = AnimatorSet()
    var hoverDisabled = false
@@ -53,10 +50,6 @@ class MaximizeButtonView(
        (stubProgressBarContainer.inflate() as FrameLayout)
            .requireViewById(R.id.progress_bar)
    }
    private val maximizeButtonText =
        context.resources.getString(R.string.desktop_mode_maximize_menu_maximize_button_text)
    private val restoreButtonText =
        context.resources.getString(R.string.desktop_mode_maximize_menu_restore_button_text)

    init {
        LayoutInflater.from(context).inflate(R.layout.maximize_menu_button, this, true)
@@ -158,12 +151,6 @@ class MaximizeButtonView(
    /** Set the drawable resource to use for the maximize button. */
    fun setIcon(@DrawableRes icon: Int) {
        maximizeWindow.setImageResource(icon)
        when (icon) {
            R.drawable.decor_desktop_mode_immersive_or_maximize_exit_button_dark ->
                maximizeWindow.contentDescription = restoreButtonText
            R.drawable.decor_desktop_mode_maximize_button_dark ->
                maximizeWindow.contentDescription = maximizeButtonText
        }
    }

    companion object {
+73 −13
Original line number Diff line number Diff line
@@ -37,10 +37,13 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import android.window.DesktopModeFlags
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.ui.graphics.toArgb
import androidx.core.content.withStyledAttributes
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.android.internal.R.color.materialColorOnSecondaryContainer
@@ -50,9 +53,6 @@ import com.android.internal.R.color.materialColorSurfaceContainerHigh
import com.android.internal.R.color.materialColorSurfaceContainerLow
import com.android.internal.R.color.materialColorSurfaceDim
import com.android.wm.shell.R
import android.window.DesktopModeFlags
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
import com.android.wm.shell.windowdecor.MaximizeButtonView
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.OPACITY_100
@@ -145,6 +145,15 @@ class AppHeaderViewHolder(
    val appNameTextWidth: Int
        get() = appNameTextView.width

    private val a11yAnnounceTextMaximize: String =
        context.getString(R.string.app_header_talkback_action_maximize_button_text)
    private val a11yAnnounceTextRestore: String =
        context.getString(R.string.app_header_talkback_action_restore_button_text)

    private lateinit var sizeToggleDirection: SizeToggleDirection
    private lateinit var a11yTextMaximize: String
    private lateinit var a11yTextRestore: String

    init {
        captionView.setOnTouchListener(onCaptionTouchListener)
        captionHandle.setOnTouchListener(onCaptionTouchListener)
@@ -163,15 +172,15 @@ class AppHeaderViewHolder(

        val a11yActionSnapLeft = AccessibilityAction(
            R.id.action_snap_left,
            context.resources.getString(R.string.desktop_mode_a11y_action_snap_left)
            context.getString(R.string.desktop_mode_a11y_action_snap_left)
        )
        val a11yActionSnapRight = AccessibilityAction(
            R.id.action_snap_right,
            context.resources.getString(R.string.desktop_mode_a11y_action_snap_right)
            context.getString(R.string.desktop_mode_a11y_action_snap_right)
        )
        val a11yActionMaximizeRestore = AccessibilityAction(
            R.id.action_maximize_restore,
            context.resources.getString(R.string.desktop_mode_a11y_action_maximize_restore)
            context.getString(R.string.desktop_mode_a11y_action_maximize_restore)
        )

        captionHandle.accessibilityDelegate = object : View.AccessibilityDelegate() {
@@ -236,19 +245,19 @@ class AppHeaderViewHolder(
            null
        )

        // Update a11y announcement to say "double tap to maximize or restore window size"
        // Update a11y announcement to say "double tap to minimize app window"
        ViewCompat.replaceAccessibilityAction(
            maximizeWindowButton,
            minimizeWindowButton,
            AccessibilityActionCompat.ACTION_CLICK,
            context.getString(R.string.maximize_button_talkback_action_maximize_restore_text),
            context.getString(R.string.app_header_talkback_action_minimize_button_text),
            null
        )

        // Update a11y announcement out to say "double tap to minimize app window"
        // Update a11y announcement to say "double tap to close app window"
        ViewCompat.replaceAccessibilityAction(
            minimizeWindowButton,
            closeWindowButton,
            AccessibilityActionCompat.ACTION_CLICK,
            context.getString(R.string.minimize_button_talkback_action_maximize_restore_text),
            context.getString(R.string.app_header_talkback_action_close_button_text),
            null
        )
    }
@@ -268,6 +277,26 @@ class AppHeaderViewHolder(
        appNameTextView.text = name
        openMenuButton.contentDescription =
            context.getString(R.string.desktop_mode_app_header_chip_text, name)

        closeWindowButton.contentDescription = context.getString(R.string.close_button_text, name)
        minimizeWindowButton.contentDescription =
            context.getString(R.string.minimize_button_text, name)

        a11yTextMaximize = context.getString(R.string.maximize_button_text, name)
        a11yTextRestore = context.getString(R.string.restore_button_text, name)

        updateMaximizeButtonContentDescription()
    }

    private fun updateMaximizeButtonContentDescription() {
        if (this::a11yTextRestore.isInitialized &&
            this::a11yTextMaximize.isInitialized &&
            this::sizeToggleDirection.isInitialized) {
            maximizeWindowButton.contentDescription = when (sizeToggleDirection) {
                SizeToggleDirection.MAXIMIZE -> a11yTextMaximize
                SizeToggleDirection.RESTORE -> a11yTextRestore
            }
        }
    }

    /** Sets the app's icon in the header. */
@@ -388,7 +417,34 @@ class AppHeaderViewHolder(
                    drawableInsets = maximizeDrawableInsets
                )
            )
            setIcon(getMaximizeButtonIcon(isTaskMaximized, inFullImmersiveState))
            val icon = getMaximizeButtonIcon(isTaskMaximized, inFullImmersiveState)
            setIcon(icon)

            when (icon) {
                R.drawable.decor_desktop_mode_immersive_or_maximize_exit_button_dark -> {
                    sizeToggleDirection = SizeToggleDirection.RESTORE

                    // Update a11y announcement to say "double tap to maximize app window size"
                    ViewCompat.replaceAccessibilityAction(
                        maximizeWindowButton,
                        AccessibilityActionCompat.ACTION_CLICK,
                        a11yAnnounceTextRestore,
                        null
                    )
                }
                R.drawable.decor_desktop_mode_maximize_button_dark -> {
                    sizeToggleDirection = SizeToggleDirection.MAXIMIZE

                    // Update a11y announcement to say "double tap to restore app window size"
                    ViewCompat.replaceAccessibilityAction(
                        maximizeWindowButton,
                        AccessibilityActionCompat.ACTION_CLICK,
                        a11yAnnounceTextMaximize,
                        null
                    )
                }
            }
            updateMaximizeButtonContentDescription()
        }
        // Close button.
        closeWindowButton.apply {
@@ -625,6 +681,10 @@ class AppHeaderViewHolder(
        )
    }

    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)