Loading core/java/android/window/DesktopExperienceFlags.java +3 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,9 @@ public enum DesktopExperienceFlags { Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG), ENABLE_DEFAULT_DESK_WITHOUT_WARMUP_MIGRATION(Flags::defaultDeskWithoutWarmupMigration, false, Flags.FLAG_DEFAULT_DESK_WITHOUT_WARMUP_MIGRATION), ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS( Flags::enableDesktopAppHeaderStateChangeAnnouncements, false, Flags.FLAG_ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS), ENABLE_DESKTOP_APP_LAUNCH_BUGFIX(Flags::enableDesktopAppLaunchBugfix, false, Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_BUGFIX), ENABLE_DESKTOP_CLOSE_TASK_ANIMATION_IN_DTC_BUGFIX( Loading core/java/android/window/flags/lse_desktop_experience.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -562,6 +562,16 @@ flag { } } flag { name: "enable_desktop_app_header_state_change_announcements" namespace: "lse_desktop_experience" description: "Enables desktop windowing state change announcements for Talkback" bug: "398732993" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "enable_move_to_next_display_shortcut" namespace: "lse_desktop_experience" Loading libs/WindowManager/Shell/res/values/strings.xml +12 −0 Original line number Diff line number Diff line Loading @@ -330,6 +330,18 @@ <string name="desktop_mode_maximize_menu_snap_text">Resize</string> <!-- Snap resizing non-resizable string. --> <string name="desktop_mode_non_resizable_snap_text">App can\'t be moved here</string> <!-- State description for app window opening. --> <string name="desktop_mode_talkback_state_opening">Opening new app window</string> <!-- State description for app window closing. --> <string name="desktop_mode_talkback_state_closing">Closing app window window</string> <!-- State description for app window minimizing. --> <string name="desktop_mode_talkback_state_minimizing">Minimizing app window</string> <!-- State description for app window gaining focus. --> <string name="desktop_mode_talkback_state_focused"><xliff:g id="app_name" example="Chrome">%1$s</xliff:g> (Focused)</string> <!-- State description for app window losing focus. --> <string name="desktop_mode_talkback_state_not_focused"><xliff:g id="app_name" example="Chrome">%1$s</xliff:g> (Not Focused)</string> <!-- Accessibility text for the Maximize Menu's immersive button [CHAR LIMIT=NONE] --> <string name="desktop_mode_maximize_menu_immersive_button_text">Immersive</string> <!-- Accessibility text for the Maximize Menu's immersive restore button [CHAR LIMIT=NONE] --> Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt +79 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.graphics.LinearGradient import android.graphics.Rect import android.graphics.Shader import android.os.Bundle import android.util.Log import android.view.View import android.view.View.OnLongClickListener import android.view.ViewTreeObserver Loading Loading @@ -72,6 +73,12 @@ import com.android.wm.shell.windowdecor.common.Theme import com.android.wm.shell.windowdecor.common.createBackgroundDrawable import com.android.wm.shell.windowdecor.extension.isLightCaptionBarAppearance import com.android.wm.shell.windowdecor.extension.isTransparentCaptionBarAppearance import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.CLOSING import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.FOCUSED import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.MINIMIZING import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.NOT_FOCUSED import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.OPENING import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.UNKNOWN import kotlin.math.roundToInt /** Loading Loading @@ -187,12 +194,22 @@ class AppHeaderViewHolder( private val a11yAnnounceTextRestore: String = context.getString(R.string.app_header_talkback_action_restore_button_text) private val a11yAnnounceTextOpening: String = context.getString(R.string.desktop_mode_talkback_state_opening) private val a11yAnnounceTextMinimizing: String = context.getString(R.string.desktop_mode_talkback_state_minimizing) private val a11yAnnounceTextClosing: String = context.getString(R.string.desktop_mode_talkback_state_closing) private lateinit var a11yAnnounceTextFocused: String private lateinit var a11yAnnounceTextNotFocused: String private lateinit var sizeToggleDirection: SizeToggleDirection private lateinit var a11yTextMaximize: String private lateinit var a11yTextRestore: String private lateinit var currentTaskInfo: RunningTaskInfo private var a11yState = UNKNOWN init { captionView.setOnTouchListener(onCaptionTouchListener) captionHandle.setOnTouchListener(onCaptionTouchListener) Loading Loading @@ -222,6 +239,7 @@ class AppHeaderViewHolder( context.getString(R.string.desktop_mode_a11y_action_maximize_restore) ) captionHandle.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE captionHandle.accessibilityDelegate = object : View.AccessibilityDelegate() { override fun onInitializeAccessibilityNodeInfo( host: View, Loading Loading @@ -324,9 +342,10 @@ class AppHeaderViewHolder( args: Bundle? ): Boolean { when (action) { AccessibilityAction.ACTION_CLICK.id -> desktopModeUiEventLogger.log( currentTaskInfo, A11Y_APP_WINDOW_CLOSE_BUTTON ) AccessibilityAction.ACTION_CLICK.id -> { setA11yStateTo(CLOSING) desktopModeUiEventLogger.log(currentTaskInfo, A11Y_APP_WINDOW_CLOSE_BUTTON) } } return super.performAccessibilityAction(host, action, args) Loading @@ -340,10 +359,13 @@ class AppHeaderViewHolder( args: Bundle? ): Boolean { when (action) { AccessibilityAction.ACTION_CLICK.id -> desktopModeUiEventLogger.log( AccessibilityAction.ACTION_CLICK.id -> { setA11yStateTo(MINIMIZING) desktopModeUiEventLogger.log( currentTaskInfo, A11Y_APP_WINDOW_MINIMIZE_BUTTON ) } } return super.performAccessibilityAction(host, action, args) } Loading Loading @@ -388,6 +410,16 @@ class AppHeaderViewHolder( /** Sets the app's name in the header. */ fun setAppName(name: CharSequence) { appNameTextView.text = name populateA11yStrings(name) if (a11yState == OPENING) setA11yStateTo(FOCUSED) updateMaximizeButtonContentDescription() updateAppNameLayoutAndEffect() } /** Populates string variables from string templates which rely on app name */ private fun populateA11yStrings(name: CharSequence) { openMenuButton.contentDescription = context.getString(R.string.desktop_mode_app_header_chip_text, name) Loading @@ -397,9 +429,10 @@ class AppHeaderViewHolder( a11yTextMaximize = context.getString(R.string.maximize_button_text, name) a11yTextRestore = context.getString(R.string.restore_button_text, name) updateMaximizeButtonContentDescription() updateAppNameLayoutAndEffect() a11yAnnounceTextFocused = context.getString(R.string.desktop_mode_talkback_state_focused, name) a11yAnnounceTextNotFocused = context.getString(R.string.desktop_mode_talkback_state_not_focused, name) } private fun updateAppNameLayoutAndEffect() { Loading Loading @@ -492,6 +525,20 @@ class AppHeaderViewHolder( } else { bindDataLegacy(taskInfo, hasGlobalFocus, isCaptionVisible) } if (hasGlobalFocus) { // app window is gaining focus if (a11yState == UNKNOWN) { // app window is opening from close or minimize setA11yStateTo(OPENING) } else if (a11yState == NOT_FOCUSED) { // app window is being re-focused after being in background setA11yStateTo(FOCUSED) } } else if (!hasGlobalFocus && a11yState == FOCUSED) { // app window is losing focus and moving to background as another window gains focus setA11yStateTo(NOT_FOCUSED) } } private fun bindDataLegacy( Loading Loading @@ -917,6 +964,28 @@ class AppHeaderViewHolder( maximizeWindowButton.cancelLongPress() } private enum class A11yState { UNKNOWN, OPENING, MINIMIZING, CLOSING, NOT_FOCUSED, FOCUSED } private fun setA11yStateTo(newState: A11yState) { if (!DesktopExperienceFlags.ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS.isTrue) { Log.i(TAG, "no a11y state change due to missing " + "enable_desktop_windowing_app_header_state_change_announcements") return } val newStateDesc = when (newState) { OPENING -> a11yAnnounceTextOpening MINIMIZING -> a11yAnnounceTextMinimizing CLOSING -> a11yAnnounceTextClosing NOT_FOCUSED -> a11yAnnounceTextNotFocused FOCUSED -> a11yAnnounceTextFocused else -> null } captionHandle.stateDescription = newStateDesc a11yState = newState } companion object { private const val TAG = "DesktopModeAppControlsWindowDecorationViewHolder" Loading Loading
core/java/android/window/DesktopExperienceFlags.java +3 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,9 @@ public enum DesktopExperienceFlags { Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG), ENABLE_DEFAULT_DESK_WITHOUT_WARMUP_MIGRATION(Flags::defaultDeskWithoutWarmupMigration, false, Flags.FLAG_DEFAULT_DESK_WITHOUT_WARMUP_MIGRATION), ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS( Flags::enableDesktopAppHeaderStateChangeAnnouncements, false, Flags.FLAG_ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS), ENABLE_DESKTOP_APP_LAUNCH_BUGFIX(Flags::enableDesktopAppLaunchBugfix, false, Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_BUGFIX), ENABLE_DESKTOP_CLOSE_TASK_ANIMATION_IN_DTC_BUGFIX( Loading
core/java/android/window/flags/lse_desktop_experience.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -562,6 +562,16 @@ flag { } } flag { name: "enable_desktop_app_header_state_change_announcements" namespace: "lse_desktop_experience" description: "Enables desktop windowing state change announcements for Talkback" bug: "398732993" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "enable_move_to_next_display_shortcut" namespace: "lse_desktop_experience" Loading
libs/WindowManager/Shell/res/values/strings.xml +12 −0 Original line number Diff line number Diff line Loading @@ -330,6 +330,18 @@ <string name="desktop_mode_maximize_menu_snap_text">Resize</string> <!-- Snap resizing non-resizable string. --> <string name="desktop_mode_non_resizable_snap_text">App can\'t be moved here</string> <!-- State description for app window opening. --> <string name="desktop_mode_talkback_state_opening">Opening new app window</string> <!-- State description for app window closing. --> <string name="desktop_mode_talkback_state_closing">Closing app window window</string> <!-- State description for app window minimizing. --> <string name="desktop_mode_talkback_state_minimizing">Minimizing app window</string> <!-- State description for app window gaining focus. --> <string name="desktop_mode_talkback_state_focused"><xliff:g id="app_name" example="Chrome">%1$s</xliff:g> (Focused)</string> <!-- State description for app window losing focus. --> <string name="desktop_mode_talkback_state_not_focused"><xliff:g id="app_name" example="Chrome">%1$s</xliff:g> (Not Focused)</string> <!-- Accessibility text for the Maximize Menu's immersive button [CHAR LIMIT=NONE] --> <string name="desktop_mode_maximize_menu_immersive_button_text">Immersive</string> <!-- Accessibility text for the Maximize Menu's immersive restore button [CHAR LIMIT=NONE] --> Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt +79 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.graphics.LinearGradient import android.graphics.Rect import android.graphics.Shader import android.os.Bundle import android.util.Log import android.view.View import android.view.View.OnLongClickListener import android.view.ViewTreeObserver Loading Loading @@ -72,6 +73,12 @@ import com.android.wm.shell.windowdecor.common.Theme import com.android.wm.shell.windowdecor.common.createBackgroundDrawable import com.android.wm.shell.windowdecor.extension.isLightCaptionBarAppearance import com.android.wm.shell.windowdecor.extension.isTransparentCaptionBarAppearance import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.CLOSING import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.FOCUSED import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.MINIMIZING import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.NOT_FOCUSED import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.OPENING import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder.A11yState.UNKNOWN import kotlin.math.roundToInt /** Loading Loading @@ -187,12 +194,22 @@ class AppHeaderViewHolder( private val a11yAnnounceTextRestore: String = context.getString(R.string.app_header_talkback_action_restore_button_text) private val a11yAnnounceTextOpening: String = context.getString(R.string.desktop_mode_talkback_state_opening) private val a11yAnnounceTextMinimizing: String = context.getString(R.string.desktop_mode_talkback_state_minimizing) private val a11yAnnounceTextClosing: String = context.getString(R.string.desktop_mode_talkback_state_closing) private lateinit var a11yAnnounceTextFocused: String private lateinit var a11yAnnounceTextNotFocused: String private lateinit var sizeToggleDirection: SizeToggleDirection private lateinit var a11yTextMaximize: String private lateinit var a11yTextRestore: String private lateinit var currentTaskInfo: RunningTaskInfo private var a11yState = UNKNOWN init { captionView.setOnTouchListener(onCaptionTouchListener) captionHandle.setOnTouchListener(onCaptionTouchListener) Loading Loading @@ -222,6 +239,7 @@ class AppHeaderViewHolder( context.getString(R.string.desktop_mode_a11y_action_maximize_restore) ) captionHandle.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE captionHandle.accessibilityDelegate = object : View.AccessibilityDelegate() { override fun onInitializeAccessibilityNodeInfo( host: View, Loading Loading @@ -324,9 +342,10 @@ class AppHeaderViewHolder( args: Bundle? ): Boolean { when (action) { AccessibilityAction.ACTION_CLICK.id -> desktopModeUiEventLogger.log( currentTaskInfo, A11Y_APP_WINDOW_CLOSE_BUTTON ) AccessibilityAction.ACTION_CLICK.id -> { setA11yStateTo(CLOSING) desktopModeUiEventLogger.log(currentTaskInfo, A11Y_APP_WINDOW_CLOSE_BUTTON) } } return super.performAccessibilityAction(host, action, args) Loading @@ -340,10 +359,13 @@ class AppHeaderViewHolder( args: Bundle? ): Boolean { when (action) { AccessibilityAction.ACTION_CLICK.id -> desktopModeUiEventLogger.log( AccessibilityAction.ACTION_CLICK.id -> { setA11yStateTo(MINIMIZING) desktopModeUiEventLogger.log( currentTaskInfo, A11Y_APP_WINDOW_MINIMIZE_BUTTON ) } } return super.performAccessibilityAction(host, action, args) } Loading Loading @@ -388,6 +410,16 @@ class AppHeaderViewHolder( /** Sets the app's name in the header. */ fun setAppName(name: CharSequence) { appNameTextView.text = name populateA11yStrings(name) if (a11yState == OPENING) setA11yStateTo(FOCUSED) updateMaximizeButtonContentDescription() updateAppNameLayoutAndEffect() } /** Populates string variables from string templates which rely on app name */ private fun populateA11yStrings(name: CharSequence) { openMenuButton.contentDescription = context.getString(R.string.desktop_mode_app_header_chip_text, name) Loading @@ -397,9 +429,10 @@ class AppHeaderViewHolder( a11yTextMaximize = context.getString(R.string.maximize_button_text, name) a11yTextRestore = context.getString(R.string.restore_button_text, name) updateMaximizeButtonContentDescription() updateAppNameLayoutAndEffect() a11yAnnounceTextFocused = context.getString(R.string.desktop_mode_talkback_state_focused, name) a11yAnnounceTextNotFocused = context.getString(R.string.desktop_mode_talkback_state_not_focused, name) } private fun updateAppNameLayoutAndEffect() { Loading Loading @@ -492,6 +525,20 @@ class AppHeaderViewHolder( } else { bindDataLegacy(taskInfo, hasGlobalFocus, isCaptionVisible) } if (hasGlobalFocus) { // app window is gaining focus if (a11yState == UNKNOWN) { // app window is opening from close or minimize setA11yStateTo(OPENING) } else if (a11yState == NOT_FOCUSED) { // app window is being re-focused after being in background setA11yStateTo(FOCUSED) } } else if (!hasGlobalFocus && a11yState == FOCUSED) { // app window is losing focus and moving to background as another window gains focus setA11yStateTo(NOT_FOCUSED) } } private fun bindDataLegacy( Loading Loading @@ -917,6 +964,28 @@ class AppHeaderViewHolder( maximizeWindowButton.cancelLongPress() } private enum class A11yState { UNKNOWN, OPENING, MINIMIZING, CLOSING, NOT_FOCUSED, FOCUSED } private fun setA11yStateTo(newState: A11yState) { if (!DesktopExperienceFlags.ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS.isTrue) { Log.i(TAG, "no a11y state change due to missing " + "enable_desktop_windowing_app_header_state_change_announcements") return } val newStateDesc = when (newState) { OPENING -> a11yAnnounceTextOpening MINIMIZING -> a11yAnnounceTextMinimizing CLOSING -> a11yAnnounceTextClosing NOT_FOCUSED -> a11yAnnounceTextNotFocused FOCUSED -> a11yAnnounceTextFocused else -> null } captionHandle.stateDescription = newStateDesc a11yState = newState } companion object { private const val TAG = "DesktopModeAppControlsWindowDecorationViewHolder" Loading