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

Commit acbc93de authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Allow desktop windows to be resized & repositioned with a11y services" into main

parents ddf806d9 473de33c
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -46,4 +46,9 @@
    <item type="id" name="action_move_bubble_bar_right"/>

    <item type="id" name="dismiss_view"/>

    <!-- Accessibility actions for desktop windowing. -->
    <item type="id" name="action_snap_left"/>
    <item type="id" name="action_snap_right"/>
    <item type="id" name="action_maximize_restore"/>
</resources>
+22 −0
Original line number Diff line number Diff line
@@ -333,6 +333,28 @@
    <!-- Accessibility text for the Maximize Menu's snap right button [CHAR LIMIT=NONE] -->
    <string name="desktop_mode_maximize_menu_snap_right_button_text">Snap right</string>

    <!-- Accessibility text for the Maximize Menu's snap left button [CHAR LIMIT=NONE] -->
    <string name="desktop_mode_a11y_action_snap_left">Resize app window left</string>
    <!-- Accessibility text for the Maximize Menu's snap right button [CHAR LIMIT=NONE] -->
    <string name="desktop_mode_a11y_action_snap_right">Resize app window right</string>
    <!-- Accessibility text for the Maximize Menu's snap maximize/restore [CHAR LIMIT=NONE] -->
    <string name="desktop_mode_a11y_action_maximize_restore">Maximize or restore window size</string>

    <!-- Accessibility action replacement for caption handle menu split screen button [CHAR LIMIT=NONE] -->
    <string name="app_handle_menu_talkback_split_screen_mode_button_text">Enter split screen mode</string>
    <!-- Accessibility action replacement for caption handle menu enter desktop mode button [CHAR LIMIT=NONE] -->
    <string name="app_handle_menu_talkback_desktop_mode_button_text">Enter desktop windowing mode</string>
    <!-- Accessibility action replacement for maximize menu enter snap left button [CHAR LIMIT=NONE] -->
    <string name="maximize_menu_talkback_action_snap_left_text">Resize window to left</string>
    <!-- Accessibility action replacement for maximize menu enter snap right button [CHAR LIMIT=NONE] -->
    <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 minimize button [CHAR LIMIT=NONE] -->
    <string name="minimize_button_talkback_action_maximize_restore_text">Minimize 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>
    <!-- Subheader for open by default menu string. -->
+7 −5
Original line number Diff line number Diff line
@@ -27,18 +27,17 @@ import static android.view.MotionEvent.ACTION_UP;
import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;


import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode;
import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopModeOrShowAppHandle;
import static com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.windowdecor.DragPositioningCallbackUtility.DragEventListener;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.DisabledEdge;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.DisabledEdge.NONE;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeEdgeHandleSize;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeHandleEdgeInset;
import static com.android.wm.shell.windowdecor.DragPositioningCallbackUtility.DragEventListener;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -112,14 +111,14 @@ import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;

import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.MainCoroutineDispatcher;

import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;

import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.MainCoroutineDispatcher;

/**
 * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
 * {@link DesktopModeWindowDecorViewModel}.
@@ -847,6 +846,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                    mOnCaptionButtonClickListener,
                    mOnCaptionLongClickListener,
                    mOnCaptionGenericMotionListener,
                    mOnLeftSnapClickListener,
                    mOnRightSnapClickListener,
                    mOnMaximizeOrRestoreClickListener,
                    mOnMaximizeHoverListener);
        }
        throw new IllegalArgumentException("Unexpected layout resource id");
+17 −1
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ import android.window.SurfaceSyncGroup
import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import androidx.compose.ui.graphics.toArgb
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK
import androidx.core.view.isGone
import com.android.window.flags.Flags
import com.android.wm.shell.R
@@ -55,8 +57,8 @@ import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.calculateMenuPosition
import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
import com.android.wm.shell.windowdecor.common.calculateMenuPosition
import com.android.wm.shell.windowdecor.extension.isFullscreen
import com.android.wm.shell.windowdecor.extension.isMultiWindow
import com.android.wm.shell.windowdecor.extension.isPinned
@@ -536,6 +538,20 @@ class HandleMenu(
                }
                return@setOnTouchListener true
            }

            with(context.resources) {
                // Update a11y read out to say "double tap to enter desktop windowing mode"
                ViewCompat.replaceAccessibilityAction(
                    desktopBtn, ACTION_CLICK,
                    getString(R.string.app_handle_menu_talkback_desktop_mode_button_text), null
                )

                // Update a11y read out to say "double tap to enter split screen mode"
                ViewCompat.replaceAccessibilityAction(
                    splitscreenBtn, ACTION_CLICK,
                    getString(R.string.app_handle_menu_talkback_split_screen_mode_button_text), null
                )
            }
        }

        /** Binds the menu views to the new data. */
+95 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.graphics.drawable.LayerDrawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.StateListDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.os.Bundle
import android.util.StateSet
import android.view.LayoutInflater
import android.view.MotionEvent.ACTION_HOVER_ENTER
@@ -51,12 +52,16 @@ import android.view.ViewGroup
import android.view.WindowManager
import android.view.WindowlessWindowManager
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
import android.widget.Button
import android.widget.TextView
import android.window.TaskConstants
import androidx.compose.material3.ColorScheme
import androidx.compose.ui.graphics.toArgb
import androidx.core.animation.addListener
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.wm.shell.R
@@ -403,6 +408,96 @@ class MaximizeMenu(
                true
            }

            sizeToggleButton.accessibilityDelegate = object : View.AccessibilityDelegate() {
                override fun onInitializeAccessibilityNodeInfo(
                    host: View,
                    info: AccessibilityNodeInfo
                ) {

                    super.onInitializeAccessibilityNodeInfo(host, info)
                    info.addAction(AccessibilityAction.ACTION_CLICK)
                    host.isClickable = true
                }

                override fun performAccessibilityAction(
                    host: View,
                    action: Int,
                    args: Bundle?
                ): Boolean {
                    if (action == AccessibilityAction.ACTION_CLICK.id) {
                        onMaximizeClickListener?.invoke()
                    }
                    return super.performAccessibilityAction(host, action, args)
                }
            }

            snapLeftButton.accessibilityDelegate = object : View.AccessibilityDelegate() {
                override fun onInitializeAccessibilityNodeInfo(
                    host: View,
                    info: AccessibilityNodeInfo
                ) {
                    super.onInitializeAccessibilityNodeInfo(host, info)
                    info.addAction(AccessibilityAction.ACTION_CLICK)
                    host.isClickable = true
                }

                override fun performAccessibilityAction(
                    host: View,
                    action: Int,
                    args: Bundle?
                ): Boolean {
                    if (action == AccessibilityAction.ACTION_CLICK.id) {
                        onLeftSnapClickListener?.invoke()
                    }
                    return super.performAccessibilityAction(host, action, args)
                }
            }

            snapRightButton.accessibilityDelegate = object : View.AccessibilityDelegate() {
                override fun onInitializeAccessibilityNodeInfo(
                    host: View,
                    info: AccessibilityNodeInfo
                ) {
                    super.onInitializeAccessibilityNodeInfo(host, info)
                    info.addAction(AccessibilityAction.ACTION_CLICK)
                    host.isClickable = true
                }

                override fun performAccessibilityAction(
                    host: View,
                    action: Int,
                    args: Bundle?
                ): Boolean {
                    if (action == AccessibilityAction.ACTION_CLICK.id) {
                        onRightSnapClickListener?.invoke()
                    }
                    return super.performAccessibilityAction(host, action, args)
                }
            }

            with(context.resources) {
                ViewCompat.replaceAccessibilityAction(
                    snapLeftButton,
                    AccessibilityActionCompat.ACTION_CLICK,
                    getString(R.string.maximize_menu_talkback_action_snap_left_text),
                    null
                )

                ViewCompat.replaceAccessibilityAction(
                    snapRightButton,
                    AccessibilityActionCompat.ACTION_CLICK,
                    getString(R.string.maximize_menu_talkback_action_snap_right_text),
                    null
                )

                ViewCompat.replaceAccessibilityAction(
                    sizeToggleButton,
                    AccessibilityActionCompat.ACTION_CLICK,
                    getString(R.string.maximize_menu_talkback_action_maximize_restore_text),
                    null
                )
            }

            // Maximize/restore button.
            val sizeToggleBtnTextId = if (sizeToggleDirection == SizeToggleDirection.RESTORE)
                R.string.desktop_mode_maximize_menu_restore_button_text
Loading