summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java2
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java16
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java47
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java142
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPinContainer.java47
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java12
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java152
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java63
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java36
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java118
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java45
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java26
-rw-r--r--libs/WindowManager/Shell/Android.bp20
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_manage_menu_section.xml24
-rw-r--r--libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml26
-rw-r--r--libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml21
-rw-r--r--libs/WindowManager/Shell/res/drawable/ic_expand_less.xml25
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml41
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml77
-rw-r--r--libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml13
-rw-r--r--libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings.xml41
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings_tv.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-as/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-be/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-bg/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-da/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-de/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings.xml17
-rw-r--r--libs/WindowManager/Shell/res/values-en-rCA/strings.xml17
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings.xml17
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings.xml17
-rw-r--r--libs/WindowManager/Shell/res/values-en-rXC/strings.xml17
-rw-r--r--libs/WindowManager/Shell/res/values-es-rUS/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-es/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-et/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-eu/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-fi/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-gl/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-gu/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings_tv.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-hu/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-is/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-it/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-ja/strings.xml37
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-kk/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-km/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-kn/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-ko/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-lo/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-lt/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-lv/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-mk/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-ml/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-mn/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings_tv.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-ms/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-my/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-nl/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-or/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-pa/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rBR/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-pt/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-ru/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-si/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-sk/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-sl/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-sq/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-sv/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-sw/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-th/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-tl/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-tr/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-uk/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings_tv.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-uz/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-watch/colors.xml22
-rw-r--r--libs/WindowManager/Shell/res/values-watch/dimen.xml22
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings.xml35
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-zu/strings.xml29
-rw-r--r--libs/WindowManager/Shell/res/values/colors.xml5
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java207
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt73
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java79
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java177
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java42
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java189
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java131
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java54
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuItemView.java77
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java145
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java242
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/HandleView.java42
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt)25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt)17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/FloatingContentCoordinator.kt1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/LaunchAdjacentController.kt90
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/OWNERS1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissCircleView.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/common/DismissCircleView.java)40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissView.kt (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt)113
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java54
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java53
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java304
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java269
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java66
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java)10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt61
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt468
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java335
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt)21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt154
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java36
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java69
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java89
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java60
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java165
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java104
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipTransition.java43
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/README.md3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java61
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java171
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java108
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java107
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java57
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java248
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java43
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java32
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java184
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt72
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java58
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/Android.bp183
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidTest.xml53
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml101
-rw-r--r--libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml (renamed from libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml)12
-rw-r--r--libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestBubbles.xml24
-rw-r--r--libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestOther.xml24
-rw-r--r--libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml24
-rw-r--r--libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestService.xml24
-rw-r--r--libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestSplitScreen.xml24
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt105
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt106
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt29
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt117
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt274
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt99
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt60
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt88
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt20
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt47
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt48
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt26
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt49
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt21
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt47
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt13
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt48
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt47
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt48
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt47
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt11
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt44
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt17
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt16
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt17
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt14
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt26
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt44
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt53
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt)21
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt32
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt32
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt32
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt32
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt67
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt80
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt66
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt65
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt73
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt75
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt83
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt73
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt73
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt151
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt70
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt69
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt70
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt72
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt69
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt42
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt20
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt22
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt54
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt29
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt26
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OWNERS2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt42
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt23
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt23
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt23
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt49
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt145
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt89
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt32
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt39
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt36
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt42
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt40
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt)19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt33
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt)79
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt)2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt)6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MultiWindowUtils.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/MultiWindowUtils.kt)2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/NotificationListener.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt)2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt)27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/WaitUtils.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt)2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/trace_config/trace_config.textproto75
-rw-r--r--libs/WindowManager/Shell/tests/unittest/Android.bp2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java15
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockToken.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/MockToken.java)8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataRepositoryTest.kt204
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java281
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java67
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/LaunchAdjacentControllerTest.kt172
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java123
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt91
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt165
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java26
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java23
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java249
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java24
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java9
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java69
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java99
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java41
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java48
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt38
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt61
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt63
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java17
-rw-r--r--libs/androidfw/Android.bp1
-rw-r--r--libs/androidfw/ApkAssets.cpp58
-rw-r--r--libs/androidfw/ApkParsing.cpp5
-rw-r--r--libs/androidfw/AssetManager2.cpp602
-rw-r--r--libs/androidfw/Idmap.cpp10
-rw-r--r--libs/androidfw/LoadedArsc.cpp23
-rw-r--r--libs/androidfw/ResourceTypes.cpp108
-rw-r--r--libs/androidfw/ZipFileRO.cpp68
-rw-r--r--libs/androidfw/include/androidfw/ApkAssets.h69
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h82
-rw-r--r--libs/androidfw/include/androidfw/Errors.h2
-rw-r--r--libs/androidfw/include/androidfw/IDiagnostics.h19
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h3
-rw-r--r--libs/androidfw/include/androidfw/MutexGuard.h21
-rw-r--r--libs/androidfw/include/androidfw/ObbFile.h6
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h3
-rw-r--r--libs/androidfw/include/androidfw/ZipFileRO.h13
-rw-r--r--libs/androidfw/tests/ApkAssets_test.cpp14
-rw-r--r--libs/androidfw/tests/ApkParsing_test.cpp6
-rw-r--r--libs/androidfw/tests/AssetManager2_bench.cpp26
-rw-r--r--libs/androidfw/tests/AssetManager2_test.cpp186
-rw-r--r--libs/androidfw/tests/AttributeResolution_bench.cpp12
-rw-r--r--libs/androidfw/tests/AttributeResolution_test.cpp6
-rw-r--r--libs/androidfw/tests/BenchmarkHelpers.cpp10
-rw-r--r--libs/androidfw/tests/Generic_bench.cpp146
-rw-r--r--libs/androidfw/tests/Idmap_test.cpp38
-rw-r--r--libs/androidfw/tests/Theme_bench.cpp8
-rw-r--r--libs/androidfw/tests/Theme_test.cpp44
-rw-r--r--libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt6
-rw-r--r--libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt10
-rw-r--r--libs/dream/lowlight/src/com/android/dream/lowlight/util/TruncatedInterpolator.kt54
-rw-r--r--libs/dream/lowlight/tests/Android.bp1
-rw-r--r--libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt15
-rw-r--r--libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt20
-rw-r--r--libs/dream/lowlight/tests/src/com/android/dream/lowlight/util/TruncatedInterpolatorTest.kt53
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/AutoBackendTextureRelease.cpp13
-rw-r--r--libs/hwui/ColorFilter.h94
-rw-r--r--libs/hwui/DisplayListOps.in1
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp4
-rw-r--r--libs/hwui/MemoryPolicy.cpp3
-rw-r--r--libs/hwui/MemoryPolicy.h2
-rw-r--r--libs/hwui/Mesh.h25
-rw-r--r--libs/hwui/OWNERS2
-rw-r--r--libs/hwui/Properties.cpp2
-rw-r--r--libs/hwui/Readback.cpp31
-rw-r--r--libs/hwui/RecordingCanvas.cpp30
-rw-r--r--libs/hwui/RecordingCanvas.h4
-rw-r--r--libs/hwui/RenderNode.cpp6
-rw-r--r--libs/hwui/RenderProperties.cpp7
-rw-r--r--libs/hwui/RenderProperties.h5
-rw-r--r--libs/hwui/SkiaCanvas.h2
-rw-r--r--libs/hwui/SkiaInterpolator.cpp71
-rw-r--r--libs/hwui/SkiaInterpolator.h10
-rw-r--r--libs/hwui/SkiaWrapper.h56
-rw-r--r--libs/hwui/apex/android_canvas.cpp4
-rw-r--r--libs/hwui/hwui/AnimatedImageDrawable.cpp4
-rw-r--r--libs/hwui/hwui/Bitmap.cpp41
-rw-r--r--libs/hwui/hwui/Canvas.cpp2
-rw-r--r--libs/hwui/hwui/MinikinUtils.h2
-rw-r--r--libs/hwui/hwui/Typeface.cpp5
-rw-r--r--libs/hwui/jni/AnimatedImageDrawable.cpp16
-rw-r--r--libs/hwui/jni/ColorFilter.cpp75
-rw-r--r--libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp28
-rw-r--r--libs/hwui/jni/FontFamily.cpp5
-rw-r--r--libs/hwui/jni/GraphicsJNI.h8
-rw-r--r--libs/hwui/jni/MaskFilter.cpp12
-rw-r--r--libs/hwui/jni/Paint.cpp51
-rw-r--r--libs/hwui/jni/RenderEffect.cpp12
-rw-r--r--libs/hwui/jni/android_graphics_DisplayListCanvas.cpp8
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp19
-rw-r--r--libs/hwui/jni/android_graphics_RenderNode.cpp9
-rw-r--r--libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp11
-rw-r--r--libs/hwui/jni/fonts/Font.cpp20
-rw-r--r--libs/hwui/jni/fonts/FontFamily.cpp9
-rw-r--r--libs/hwui/jni/text/TextShaper.cpp48
-rw-r--r--libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp85
-rw-r--r--libs/hwui/pipeline/skia/BackdropFilterDrawable.h67
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp18
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.cpp9
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.h7
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.cpp52
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.h55
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp19
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp21
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp20
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h2
-rw-r--r--libs/hwui/pipeline/skia/StretchMask.cpp23
-rw-r--r--libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp8
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp5
-rw-r--r--libs/hwui/renderthread/CacheManager.h3
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp33
-rw-r--r--libs/hwui/renderthread/CanvasContext.h10
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp15
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp10
-rw-r--r--libs/hwui/renderthread/VulkanSurface.cpp5
-rw-r--r--libs/hwui/tests/common/TestUtils.h61
-rw-r--r--libs/hwui/tests/macrobench/main.cpp86
-rw-r--r--libs/hwui/tests/unit/AutoBackendTextureReleaseTests.cpp2
-rw-r--r--libs/hwui/tests/unit/CacheManagerTests.cpp16
-rw-r--r--libs/hwui/tests/unit/CanvasContextTests.cpp36
-rw-r--r--libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp2
-rw-r--r--libs/hwui/tests/unit/RenderNodeDrawableTests.cpp101
-rw-r--r--libs/hwui/tests/unit/RenderNodeTests.cpp3
-rw-r--r--libs/hwui/tests/unit/ShaderCacheTests.cpp15
-rw-r--r--libs/hwui/tests/unit/SkiaCanvasTests.cpp2
-rw-r--r--libs/hwui/tests/unit/SkiaDisplayListTests.cpp37
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp36
-rw-r--r--libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp22
-rw-r--r--libs/hwui/tests/unit/main.cpp64
-rw-r--r--libs/incident/src/IncidentReportArgs.cpp7
-rw-r--r--libs/input/OWNERS2
-rw-r--r--libs/services/Android.bp7
539 files changed, 15215 insertions, 6051 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 76e0e1eb7a95..55eabb039c01 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -48,7 +48,7 @@ public class WindowExtensionsImpl implements WindowExtensions {
// TODO(b/241126279) Introduce constants to better version functionality
@Override
public int getVendorApiLevel() {
- return 3;
+ return 4;
}
@NonNull
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index d94e8e426c4b..4d73c20fe39f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -17,7 +17,9 @@
package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
+import static android.window.TaskFragmentOperation.OP_TYPE_SET_ISOLATED_NAVIGATION;
import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior;
import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior;
@@ -340,6 +342,20 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
wct.deleteTaskFragment(fragmentToken);
}
+ void reorderTaskFragmentToFront(@NonNull WindowContainerTransaction wct,
+ @NonNull IBinder fragmentToken) {
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_REORDER_TO_FRONT).build();
+ wct.addTaskFragmentOperation(fragmentToken, operation);
+ }
+
+ void setTaskFragmentIsolatedNavigation(@NonNull WindowContainerTransaction wct,
+ @NonNull IBinder fragmentToken, boolean isolatedNav) {
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_SET_ISOLATED_NAVIGATION).setIsolatedNav(isolatedNav).build();
+ wct.addTaskFragmentOperation(fragmentToken, operation);
+ }
+
void updateTaskFragmentInfo(@NonNull TaskFragmentInfo taskFragmentInfo) {
mFragmentInfos.put(taskFragmentInfo.getFragmentToken(), taskFragmentInfo);
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index 18497ad249ee..08b7bb89d10c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -25,6 +25,7 @@ import android.window.TaskFragmentParentInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.window.extensions.core.util.function.Function;
/**
@@ -32,7 +33,7 @@ import androidx.window.extensions.core.util.function.Function;
*/
class SplitContainer {
@NonNull
- private final TaskFragmentContainer mPrimaryContainer;
+ private TaskFragmentContainer mPrimaryContainer;
@NonNull
private final TaskFragmentContainer mSecondaryContainer;
@NonNull
@@ -46,17 +47,35 @@ class SplitContainer {
@NonNull
private final IBinder mToken;
+ /**
+ * Whether the selection of which container is primary can be changed at runtime. Runtime
+ * updates is currently possible only for {@link SplitPinContainer}
+ *
+ * @see SplitPinContainer
+ */
+ private final boolean mIsPrimaryContainerMutable;
+
SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
@NonNull Activity primaryActivity,
@NonNull TaskFragmentContainer secondaryContainer,
@NonNull SplitRule splitRule,
@NonNull SplitAttributes splitAttributes) {
+ this(primaryContainer, primaryActivity, secondaryContainer, splitRule, splitAttributes,
+ false /* isPrimaryContainerMutable */);
+ }
+
+ SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull Activity primaryActivity,
+ @NonNull TaskFragmentContainer secondaryContainer,
+ @NonNull SplitRule splitRule,
+ @NonNull SplitAttributes splitAttributes, boolean isPrimaryContainerMutable) {
mPrimaryContainer = primaryContainer;
mSecondaryContainer = secondaryContainer;
mSplitRule = splitRule;
mDefaultSplitAttributes = splitRule.getDefaultSplitAttributes();
mCurrentSplitAttributes = splitAttributes;
mToken = new Binder("SplitContainer");
+ mIsPrimaryContainerMutable = isPrimaryContainerMutable;
if (shouldFinishPrimaryWithSecondary(splitRule)) {
if (mPrimaryContainer.getRunningActivityCount() == 1
@@ -74,6 +93,13 @@ class SplitContainer {
}
}
+ void setPrimaryContainer(@NonNull TaskFragmentContainer primaryContainer) {
+ if (!mIsPrimaryContainerMutable) {
+ throw new IllegalStateException("Cannot update primary TaskFragmentContainer");
+ }
+ mPrimaryContainer = primaryContainer;
+ }
+
@NonNull
TaskFragmentContainer getPrimaryContainer() {
return mPrimaryContainer;
@@ -161,10 +187,21 @@ class SplitContainer {
return (mSplitRule instanceof SplitPlaceholderRule);
}
- @NonNull
- SplitInfo toSplitInfo() {
- return new SplitInfo(mPrimaryContainer.toActivityStack(),
- mSecondaryContainer.toActivityStack(), mCurrentSplitAttributes, mToken);
+ /**
+ * Returns the SplitInfo representing this container.
+ *
+ * @return the SplitInfo representing this container if the underlying TaskFragmentContainers
+ * are stable, or {@code null} if any TaskFragmentContainer is in an intermediate state.
+ */
+ @Nullable
+ SplitInfo toSplitInfoIfStable() {
+ final ActivityStack primaryActivityStack = mPrimaryContainer.toActivityStackIfStable();
+ final ActivityStack secondaryActivityStack = mSecondaryContainer.toActivityStackIfStable();
+ if (primaryActivityStack == null || secondaryActivityStack == null) {
+ return null;
+ }
+ return new SplitInfo(primaryActivityStack, secondaryActivityStack,
+ mCurrentSplitAttributes, mToken);
}
static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 89f4890c254e..3d72963944c2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -213,6 +213,60 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
@Override
+ public boolean pinTopActivityStack(int taskId, @NonNull SplitPinRule splitPinRule) {
+ synchronized (mLock) {
+ final TaskContainer task = getTaskContainer(taskId);
+ if (task == null) {
+ Log.e(TAG, "Cannot find the task for id: " + taskId);
+ return false;
+ }
+
+ final TaskFragmentContainer topContainer =
+ task.getTopNonFinishingTaskFragmentContainer();
+ // Cannot pin the TaskFragment if no other TaskFragment behind it.
+ if (topContainer == null || task.indexOf(topContainer) <= 0) {
+ Log.w(TAG, "Cannot find an ActivityStack to pin or split");
+ return false;
+ }
+ // Abort if the top container is already pinned.
+ if (task.getSplitPinContainer() != null) {
+ Log.w(TAG, "There is already a pinned ActivityStack.");
+ return false;
+ }
+
+ // Find a valid adjacent TaskFragmentContainer
+ final TaskFragmentContainer primaryContainer =
+ task.getNonFinishingTaskFragmentContainerBelow(topContainer);
+ if (primaryContainer == null) {
+ Log.w(TAG, "Cannot find another ActivityStack to split");
+ return false;
+ }
+
+ // Registers a Split
+ final SplitPinContainer splitPinContainer = new SplitPinContainer(primaryContainer,
+ topContainer, splitPinRule, splitPinRule.getDefaultSplitAttributes());
+ task.addSplitContainer(splitPinContainer);
+
+ // Updates the Split
+ final TransactionRecord transactionRecord = mTransactionManager.startNewTransaction();
+ final WindowContainerTransaction wct = transactionRecord.getTransaction();
+
+ mPresenter.setTaskFragmentIsolatedNavigation(wct,
+ splitPinContainer.getSecondaryContainer().getTaskFragmentToken(),
+ true /* isolatedNav */);
+ mPresenter.updateSplitContainer(splitPinContainer, wct);
+ transactionRecord.apply(false /* shouldApplyIndependently */);
+ updateCallbackIfNecessary();
+ return true;
+ }
+ }
+
+ @Override
+ public void unpinTopActivityStack(int taskId){
+ // TODO
+ }
+
+ @Override
public void setSplitAttributesCalculator(
@NonNull Function<SplitAttributesCalculatorParams, SplitAttributes> calculator) {
synchronized (mLock) {
@@ -308,7 +362,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
forAllTaskContainers(taskContainer -> {
synchronized (mLock) {
- final List<TaskFragmentContainer> containers = taskContainer.mContainers;
+ final List<TaskFragmentContainer> containers =
+ taskContainer.getTaskFragmentContainers();
// Clean up the TaskFragmentContainers by the z-order from the lowest.
for (int i = 0; i < containers.size(); i++) {
final TaskFragmentContainer container = containers.get(i);
@@ -611,8 +666,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@NonNull TaskContainer taskContainer) {
// Update all TaskFragments in the Task. Make a copy of the list since some may be
// removed on updating.
- final List<TaskFragmentContainer> containers =
- new ArrayList<>(taskContainer.mContainers);
+ final List<TaskFragmentContainer> containers = taskContainer.getTaskFragmentContainers();
for (int i = containers.size() - 1; i >= 0; i--) {
final TaskFragmentContainer container = containers.get(i);
// Wait until onTaskFragmentAppeared to update new container.
@@ -672,7 +726,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (targetContainer == null) {
// When there is no embedding rule matched, try to place it in the top container
// like a normal launch.
- targetContainer = taskContainer.getTopTaskFragmentContainer();
+ targetContainer = taskContainer.getTopNonFinishingTaskFragmentContainer();
}
if (targetContainer == null) {
return;
@@ -791,7 +845,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
final TaskFragmentContainer container = getContainerWithActivity(activity);
if (!isOnReparent && container != null
- && container.getTaskContainer().getTopTaskFragmentContainer() != container) {
+ && container.getTaskContainer().getTopNonFinishingTaskFragmentContainer()
+ != container) {
// Do not resolve if the launched activity is not the top-most container in the Task.
return true;
}
@@ -888,7 +943,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (taskContainer == null) {
return;
}
- final TaskFragmentContainer targetContainer = taskContainer.getTopTaskFragmentContainer();
+ final TaskFragmentContainer targetContainer =
+ taskContainer.getTopNonFinishingTaskFragmentContainer();
if (targetContainer == null) {
return;
}
@@ -1213,11 +1269,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// 3. Whether the top activity (if any) should be split with the new activity intent.
final TaskContainer taskContainer = getTaskContainer(taskId);
- if (taskContainer == null || taskContainer.getTopTaskFragmentContainer() == null) {
+ if (taskContainer == null
+ || taskContainer.getTopNonFinishingTaskFragmentContainer() == null) {
// There is no other activity in the Task to check split with.
return null;
}
- final TaskFragmentContainer topContainer = taskContainer.getTopTaskFragmentContainer();
+ final TaskFragmentContainer topContainer =
+ taskContainer.getTopNonFinishingTaskFragmentContainer();
final Activity topActivity = topContainer.getTopNonFinishingActivity();
if (topActivity != null && topActivity != launchingActivity) {
final TaskFragmentContainer container = getSecondaryContainerForSplitIfAny(wct,
@@ -1331,7 +1389,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// Check pending appeared activity first because there can be a delay for the server
// update.
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+ final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
+ .getTaskFragmentContainers();
for (int j = containers.size() - 1; j >= 0; j--) {
final TaskFragmentContainer container = containers.get(j);
if (container.hasPendingAppearedActivity(activityToken)) {
@@ -1342,7 +1401,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// Check appeared activity if there is no such pending appeared activity.
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+ final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
+ .getTaskFragmentContainers();
for (int j = containers.size() - 1; j >= 0; j--) {
final TaskFragmentContainer container = containers.get(j);
if (container.hasAppearedActivity(activityToken)) {
@@ -1418,7 +1478,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) {
removeExistingSecondaryContainers(wct, primaryContainer);
}
- primaryContainer.getTaskContainer().mSplitContainers.add(splitContainer);
+ primaryContainer.getTaskContainer().addSplitContainer(splitContainer);
}
/** Cleanups all the dependencies when the TaskFragment is entering PIP. */
@@ -1430,8 +1490,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return;
}
final List<SplitContainer> splitsToRemove = new ArrayList<>();
+ final List<SplitContainer> splitContainers = taskContainer.getSplitContainers();
final Set<TaskFragmentContainer> containersToUpdate = new ArraySet<>();
- for (SplitContainer splitContainer : taskContainer.mSplitContainers) {
+ for (SplitContainer splitContainer : splitContainers) {
if (splitContainer.getPrimaryContainer() != container
&& splitContainer.getSecondaryContainer() != container) {
continue;
@@ -1449,7 +1510,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
}
container.resetDependencies();
- taskContainer.mSplitContainers.removeAll(splitsToRemove);
+ taskContainer.removeSplitContainers(splitsToRemove);
// If there is any TaskFragment split with the PIP TaskFragment, update their presentations
// since the split is dismissed.
// We don't want to close any of them even if they are dependencies of the PIP TaskFragment.
@@ -1471,7 +1532,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
void removeContainers(@NonNull TaskContainer taskContainer,
@NonNull List<TaskFragmentContainer> containers) {
// Remove all split containers that included this one
- taskContainer.mContainers.removeAll(containers);
+ taskContainer.removeTaskFragmentContainers(containers);
// Marked as a pending removal which will be removed after it is actually removed on the
// server side (#onTaskFragmentVanished).
// In this way, we can keep track of the Task bounds until we no longer have any
@@ -1481,7 +1542,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// Cleanup any split references.
final List<SplitContainer> containersToRemove = new ArrayList<>();
- for (SplitContainer splitContainer : taskContainer.mSplitContainers) {
+ final List<SplitContainer> splitContainers = taskContainer.getSplitContainers();
+ for (SplitContainer splitContainer : splitContainers) {
if (containersToRemove.contains(splitContainer)) {
// Don't need to check because it has been in the remove list.
continue;
@@ -1492,10 +1554,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
containersToRemove.add(splitContainer);
}
}
- taskContainer.mSplitContainers.removeAll(containersToRemove);
+ taskContainer.removeSplitContainers(containersToRemove);
// Cleanup any dependent references.
- for (TaskFragmentContainer containerToUpdate : taskContainer.mContainers) {
+ final List<TaskFragmentContainer> taskFragmentContainers =
+ taskContainer.getTaskFragmentContainers();
+ for (TaskFragmentContainer containerToUpdate : taskFragmentContainers) {
containerToUpdate.removeContainersToFinishOnExit(containers);
}
}
@@ -1534,8 +1598,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (taskContainer == null) {
return null;
}
- for (int i = taskContainer.mContainers.size() - 1; i >= 0; i--) {
- final TaskFragmentContainer container = taskContainer.mContainers.get(i);
+ final List<TaskFragmentContainer> containers = taskContainer.getTaskFragmentContainers();
+ for (int i = containers.size() - 1; i >= 0; i--) {
+ final TaskFragmentContainer container = containers.get(i);
if (!container.isFinished() && (container.getRunningActivityCount() > 0
// We may be waiting for the top TaskFragment to become non-empty after
// creation. In that case, we don't want to treat the TaskFragment below it as
@@ -1560,6 +1625,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// background.
return;
}
+ final SplitContainer splitContainer = getActiveSplitForContainer(container);
+ if (splitContainer instanceof SplitPinContainer
+ && updateSplitContainerIfNeeded(splitContainer, wct, null /* splitAttributes */)) {
+ // A SplitPinContainer exists and is updated.
+ return;
+ }
if (launchPlaceholderIfNecessary(wct, container)) {
// Placeholder was launched, the positions will be updated when the activity is added
// to the secondary container.
@@ -1572,7 +1643,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// If the info is not available yet the task fragment will be expanded when it's ready
return;
}
- SplitContainer splitContainer = getActiveSplitForContainer(container);
if (splitContainer == null) {
return;
}
@@ -1629,7 +1699,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
/** Whether the given split is the topmost split in the Task. */
private boolean isTopMostSplit(@NonNull SplitContainer splitContainer) {
final List<SplitContainer> splitContainers = splitContainer.getPrimaryContainer()
- .getTaskContainer().mSplitContainers;
+ .getTaskContainer().getSplitContainers();
return splitContainer == splitContainers.get(splitContainers.size() - 1);
}
@@ -1641,7 +1711,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (container == null) {
return null;
}
- final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers;
+ final List<SplitContainer> splitContainers =
+ container.getTaskContainer().getSplitContainers();
if (splitContainers.isEmpty()) {
return null;
}
@@ -1665,7 +1736,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@NonNull TaskFragmentContainer firstContainer,
@NonNull TaskFragmentContainer secondContainer) {
final List<SplitContainer> splitContainers = firstContainer.getTaskContainer()
- .mSplitContainers;
+ .getSplitContainers();
for (int i = splitContainers.size() - 1; i >= 0; i--) {
final SplitContainer splitContainer = splitContainers.get(i);
final TaskFragmentContainer primary = splitContainer.getPrimaryContainer();
@@ -1837,8 +1908,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (mEmbeddingCallback == null || !readyToReportToClient()) {
return;
}
- final List<SplitInfo> currentSplitStates = getActiveSplitStates();
- if (mLastReportedSplitStates.equals(currentSplitStates)) {
+ final List<SplitInfo> currentSplitStates = getActiveSplitStatesIfStable();
+ if (currentSplitStates == null || mLastReportedSplitStates.equals(currentSplitStates)) {
return;
}
mLastReportedSplitStates.clear();
@@ -1848,13 +1919,21 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
/**
* Returns a list of descriptors for currently active split states.
+ *
+ * @return a list of descriptors for currently active split states if all the containers are in
+ * a stable state, or {@code null} otherwise.
*/
@GuardedBy("mLock")
- @NonNull
- private List<SplitInfo> getActiveSplitStates() {
+ @Nullable
+ private List<SplitInfo> getActiveSplitStatesIfStable() {
final List<SplitInfo> splitStates = new ArrayList<>();
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- mTaskContainers.valueAt(i).getSplitStates(splitStates);
+ final List<SplitInfo> taskSplitStates =
+ mTaskContainers.valueAt(i).getSplitStatesIfStable();
+ if (taskSplitStates == null) {
+ return null;
+ }
+ splitStates.addAll(taskSplitStates);
}
return splitStates;
}
@@ -1930,7 +2009,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@GuardedBy("mLock")
TaskFragmentContainer getContainer(@NonNull IBinder fragmentToken) {
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+ final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
+ .getTaskFragmentContainers();
for (TaskFragmentContainer container : containers) {
if (container.getTaskFragmentToken().equals(fragmentToken)) {
return container;
@@ -1945,7 +2025,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@GuardedBy("mLock")
SplitContainer getSplitContainer(@NonNull IBinder token) {
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<SplitContainer> containers = mTaskContainers.valueAt(i).mSplitContainers;
+ final List<SplitContainer> containers = mTaskContainers.valueAt(i).getSplitContainers();
for (SplitContainer container : containers) {
if (container.getToken().equals(token)) {
return container;
@@ -2091,7 +2171,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
- .mContainers;
+ .getTaskFragmentContainers();
for (int j = containers.size() - 1; j >= 0; j--) {
final TaskFragmentContainer container = containers.get(j);
if (!container.hasActivity(activityToken)
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPinContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPinContainer.java
new file mode 100644
index 000000000000..03c77a089012
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPinContainer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 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 androidx.window.extensions.embedding;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Client-side descriptor of a split that holds two containers while the secondary
+ * container is pinned on top of the Task and the primary container is the container that is
+ * currently below the secondary container. The primary container could be updated to
+ * another container whenever the existing primary container is removed or no longer
+ * be the container that's right behind the secondary container.
+ */
+class SplitPinContainer extends SplitContainer {
+
+ SplitPinContainer(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull TaskFragmentContainer secondaryContainer,
+ @NonNull SplitPinRule splitPinRule,
+ @NonNull SplitAttributes splitAttributes) {
+ super(primaryContainer, primaryContainer.getTopNonFinishingActivity(), secondaryContainer,
+ splitPinRule, splitAttributes, true /* isPrimaryContainerMutable */);
+ }
+
+ @Override
+ public String toString() {
+ return "SplitPinContainer{"
+ + " primaryContainer=" + getPrimaryContainer()
+ + " secondaryContainer=" + getSecondaryContainer()
+ + " splitPinRule=" + getSplitRule()
+ + " splitAttributes" + getCurrentSplitAttributes()
+ + "}";
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 53d39d9fa28e..5de6acfcc9db 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -336,10 +336,6 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
// value.
final SplitRule rule = splitContainer.getSplitRule();
final TaskFragmentContainer primaryContainer = splitContainer.getPrimaryContainer();
- final Activity activity = primaryContainer.getTopNonFinishingActivity();
- if (activity == null) {
- return;
- }
final TaskContainer taskContainer = splitContainer.getTaskContainer();
final TaskProperties taskProperties = taskContainer.getTaskProperties();
final SplitAttributes splitAttributes = splitContainer.getCurrentSplitAttributes();
@@ -424,6 +420,14 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
container.setLastRequestedBounds(fragmentOptions.getInitialRelativeBounds());
container.setLastRequestedWindowingMode(fragmentOptions.getWindowingMode());
super.createTaskFragment(wct, fragmentOptions);
+
+ // Reorders the pinned TaskFragment to front to ensure it is the front-most TaskFragment.
+ final SplitPinContainer pinnedContainer =
+ container.getTaskContainer().getSplitPinContainer();
+ if (pinnedContainer != null) {
+ reorderTaskFragmentToFront(wct,
+ pinnedContainer.getSecondaryContainer().getTaskFragmentToken());
+ }
}
@Override
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 4b15bb187035..fa1eb9e1d167 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -51,11 +51,15 @@ class TaskContainer {
/** Active TaskFragments in this Task. */
@NonNull
- final List<TaskFragmentContainer> mContainers = new ArrayList<>();
+ private final List<TaskFragmentContainer> mContainers = new ArrayList<>();
/** Active split pairs in this Task. */
@NonNull
- final List<SplitContainer> mSplitContainers = new ArrayList<>();
+ private final List<SplitContainer> mSplitContainers = new ArrayList<>();
+
+ /** Active pin split pair in this Task. */
+ @Nullable
+ private SplitPinContainer mSplitPinContainer;
@NonNull
private final Configuration mConfiguration;
@@ -174,11 +178,28 @@ class TaskContainer {
}
@Nullable
- TaskFragmentContainer getTopTaskFragmentContainer() {
- if (mContainers.isEmpty()) {
- return null;
+ TaskFragmentContainer getTopNonFinishingTaskFragmentContainer() {
+ for (int i = mContainers.size() - 1; i >= 0; i--) {
+ final TaskFragmentContainer container = mContainers.get(i);
+ if (!container.isFinished()) {
+ return container;
+ }
}
- return mContainers.get(mContainers.size() - 1);
+ return null;
+ }
+
+ /** Gets a non-finishing container below the given one. */
+ @Nullable
+ TaskFragmentContainer getNonFinishingTaskFragmentContainerBelow(
+ @NonNull TaskFragmentContainer current) {
+ final int index = mContainers.indexOf(current);
+ for (int i = index - 1; i >= 0; i--) {
+ final TaskFragmentContainer container = mContainers.get(i);
+ if (!container.isFinished()) {
+ return container;
+ }
+ }
+ return null;
}
@Nullable
@@ -207,11 +228,124 @@ class TaskContainer {
return false;
}
- /** Adds the descriptors of split states in this Task to {@code outSplitStates}. */
- void getSplitStates(@NonNull List<SplitInfo> outSplitStates) {
+ /**
+ * Returns a list of {@link SplitContainer}. Do not modify the containers directly on the
+ * returned list. Use {@link #addSplitContainer} or {@link #removeSplitContainers} instead.
+ */
+ @NonNull
+ List<SplitContainer> getSplitContainers() {
+ return mSplitContainers;
+ }
+
+ void addSplitContainer(@NonNull SplitContainer splitContainer) {
+ if (splitContainer instanceof SplitPinContainer) {
+ mSplitPinContainer = (SplitPinContainer) splitContainer;
+ mSplitContainers.add(splitContainer);
+ return;
+ }
+
+ // Keeps the SplitPinContainer on the top of the list.
+ mSplitContainers.remove(mSplitPinContainer);
+ mSplitContainers.add(splitContainer);
+ if (mSplitPinContainer != null) {
+ mSplitContainers.add(mSplitPinContainer);
+ }
+ }
+
+ void removeSplitContainers(@NonNull List<SplitContainer> containers) {
+ mSplitContainers.removeAll(containers);
+ }
+
+ void removeSplitPinContainer() {
+ mSplitContainers.remove(mSplitPinContainer);
+ mSplitPinContainer = null;
+ }
+
+ @Nullable
+ SplitPinContainer getSplitPinContainer() {
+ return mSplitPinContainer;
+ }
+
+ void addTaskFragmentContainer(@NonNull TaskFragmentContainer taskFragmentContainer) {
+ mContainers.add(taskFragmentContainer);
+ onTaskFragmentContainerUpdated();
+ }
+
+ void addTaskFragmentContainer(int index, @NonNull TaskFragmentContainer taskFragmentContainer) {
+ mContainers.add(index, taskFragmentContainer);
+ onTaskFragmentContainerUpdated();
+ }
+
+ void removeTaskFragmentContainer(@NonNull TaskFragmentContainer taskFragmentContainer) {
+ mContainers.remove(taskFragmentContainer);
+ onTaskFragmentContainerUpdated();
+ }
+
+ void removeTaskFragmentContainers(@NonNull List<TaskFragmentContainer> taskFragmentContainer) {
+ mContainers.removeAll(taskFragmentContainer);
+ onTaskFragmentContainerUpdated();
+ }
+
+ void clearTaskFragmentContainer() {
+ mContainers.clear();
+ onTaskFragmentContainerUpdated();
+ }
+
+ /**
+ * Returns a list of {@link TaskFragmentContainer}. Do not modify the containers directly on
+ * the returned list. Use {@link #addTaskFragmentContainer},
+ * {@link #removeTaskFragmentContainer} or other related methods instead.
+ */
+ @NonNull
+ List<TaskFragmentContainer> getTaskFragmentContainers() {
+ return mContainers;
+ }
+
+ private void onTaskFragmentContainerUpdated() {
+ if (mSplitPinContainer == null) {
+ return;
+ }
+
+ final TaskFragmentContainer pinnedContainer = mSplitPinContainer.getSecondaryContainer();
+ final int pinnedContainerIndex = mContainers.indexOf(pinnedContainer);
+ if (pinnedContainerIndex <= 0) {
+ removeSplitPinContainer();
+ return;
+ }
+
+ // Ensure the pinned container is top-most.
+ if (pinnedContainerIndex != mContainers.size() - 1) {
+ mContainers.remove(pinnedContainer);
+ mContainers.add(pinnedContainer);
+ }
+
+ // Update the primary container adjacent to the pinned container if needed.
+ final TaskFragmentContainer adjacentContainer =
+ getNonFinishingTaskFragmentContainerBelow(pinnedContainer);
+ if (adjacentContainer == null) {
+ removeSplitPinContainer();
+ } else if (mSplitPinContainer.getPrimaryContainer() != adjacentContainer) {
+ mSplitPinContainer.setPrimaryContainer(adjacentContainer);
+ }
+ }
+
+ /**
+ * Gets the descriptors of split states in this Task.
+ *
+ * @return a list of {@code SplitInfo} if all the SplitContainers are stable, or {@code null} if
+ * any SplitContainer is in an intermediate state.
+ */
+ @Nullable
+ List<SplitInfo> getSplitStatesIfStable() {
+ final List<SplitInfo> splitStates = new ArrayList<>();
for (SplitContainer container : mSplitContainers) {
- outSplitStates.add(container.toSplitInfo());
+ final SplitInfo splitInfo = container.toSplitInfoIfStable();
+ if (splitInfo == null) {
+ return null;
+ }
+ splitStates.add(splitInfo);
}
+ return splitStates;
}
/** A wrapper class which contains the information of {@link TaskContainer} */
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 60be9d16d749..0a694b5c3b64 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -180,23 +180,25 @@ class TaskFragmentContainer {
throw new IllegalArgumentException(
"pairedPrimaryContainer must be in the same Task");
}
- final int primaryIndex = taskContainer.mContainers.indexOf(pairedPrimaryContainer);
- taskContainer.mContainers.add(primaryIndex + 1, this);
+ final int primaryIndex = taskContainer.indexOf(pairedPrimaryContainer);
+ taskContainer.addTaskFragmentContainer(primaryIndex + 1, this);
} else if (pendingAppearedActivity != null) {
// The TaskFragment will be positioned right above the pending appeared Activity. If any
// existing TaskFragment is empty with pending Intent, it is likely that the Activity of
// the pending Intent hasn't been created yet, so the new Activity should be below the
// empty TaskFragment.
- int i = taskContainer.mContainers.size() - 1;
+ final List<TaskFragmentContainer> containers =
+ taskContainer.getTaskFragmentContainers();
+ int i = containers.size() - 1;
for (; i >= 0; i--) {
- final TaskFragmentContainer container = taskContainer.mContainers.get(i);
+ final TaskFragmentContainer container = containers.get(i);
if (!container.isEmpty() || container.getPendingAppearedIntent() == null) {
break;
}
}
- taskContainer.mContainers.add(i + 1, this);
+ taskContainer.addTaskFragmentContainer(i + 1, this);
} else {
- taskContainer.mContainers.add(this);
+ taskContainer.addTaskFragmentContainer(this);
}
if (pendingAppearedActivity != null) {
addPendingAppearedActivity(pendingAppearedActivity);
@@ -215,6 +217,30 @@ class TaskFragmentContainer {
/** List of non-finishing activities that belong to this container and live in this process. */
@NonNull
List<Activity> collectNonFinishingActivities() {
+ final List<Activity> activities = collectNonFinishingActivities(false /* checkIfStable */);
+ if (activities == null) {
+ throw new IllegalStateException(
+ "Result activities should never be null when checkIfstable is false.");
+ }
+ return activities;
+ }
+
+ /**
+ * Collects non-finishing activities that belong to this container and live in this process.
+ *
+ * @param checkIfStable if {@code true}, returns {@code null} when the container is in an
+ * intermediate state.
+ * @return List of non-finishing activities that belong to this container and live in this
+ * process, {@code null} if checkIfStable is {@code true} and the container is in an
+ * intermediate state.
+ */
+ @Nullable
+ List<Activity> collectNonFinishingActivities(boolean checkIfStable) {
+ if (checkIfStable
+ && (mInfo == null || mInfo.isEmpty() || !mPendingAppearedActivities.isEmpty())) {
+ return null;
+ }
+
final List<Activity> allActivities = new ArrayList<>();
if (mInfo != null) {
// Add activities reported from the server.
@@ -222,6 +248,15 @@ class TaskFragmentContainer {
final Activity activity = mController.getActivity(token);
if (activity != null && !activity.isFinishing()) {
allActivities.add(activity);
+ } else {
+ if (checkIfStable) {
+ // Return null except for a special case when the activity is started in
+ // background.
+ if (activity == null && !mTaskContainer.isVisible()) {
+ continue;
+ }
+ return null;
+ }
}
}
}
@@ -275,9 +310,19 @@ class TaskFragmentContainer {
return false;
}
- @NonNull
- ActivityStack toActivityStack() {
- return new ActivityStack(collectNonFinishingActivities(), isEmpty(), mToken);
+ /**
+ * Returns the ActivityStack representing this container.
+ *
+ * @return ActivityStack representing this container if it is in a stable state. {@code null} if
+ * in an intermediate state.
+ */
+ @Nullable
+ ActivityStack toActivityStackIfStable() {
+ final List<Activity> activities = collectNonFinishingActivities(true /* checkIfStable */);
+ if (activities == null) {
+ return null;
+ }
+ return new ActivityStack(activities, isEmpty(), mToken);
}
/** Adds the activity that will be reparented to this container. */
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index a45a8a183ac8..ccf95527efea 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -98,14 +98,6 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
mTaskFragmentOrganizer = taskFragmentOrganizer;
}
- /** Registers to listen to {@link CommonFoldingFeature} changes */
- public void addFoldingStateChangedCallback(
- java.util.function.Consumer<List<CommonFoldingFeature>> consumer) {
- synchronized (mLock) {
- mFoldingFeatureProducer.addDataChangedCallback(consumer);
- }
- }
-
/**
* Adds a listener interested in receiving updates to {@link WindowLayoutInfo}
*
@@ -304,7 +296,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
* {@link IllegalArgumentException} since this can cause negative UI effects down stream.
*
* @param context a proxy for the {@link android.view.Window} that contains the
- * {@link DisplayFeature}.
+ * {@link DisplayFeature}.
* @return a {@link List} of {@link DisplayFeature}s that are within the
* {@link android.view.Window} of the {@link Activity}
*/
@@ -336,10 +328,32 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
rotateRectToDisplayRotation(displayId, featureRect);
transformToWindowSpaceRect(windowConfiguration, featureRect);
- if (!isZero(featureRect)) {
+ if (isZero(featureRect)) {
// TODO(b/228641877): Remove guarding when fixed.
- features.add(new FoldingFeature(featureRect, baseFeature.getType(), state));
+ continue;
+ }
+ if (featureRect.left != 0 && featureRect.top != 0) {
+ throw new IllegalArgumentException("Bounding rectangle must start at the top or "
+ + "left of the window. BaseFeatureRect: " + baseFeature.getRect()
+ + ", FeatureRect: " + featureRect
+ + ", WindowConfiguration: " + windowConfiguration);
+
+ }
+ if (featureRect.left == 0
+ && featureRect.width() != windowConfiguration.getBounds().width()) {
+ throw new IllegalArgumentException("Horizontal FoldingFeature must have full width."
+ + " BaseFeatureRect: " + baseFeature.getRect()
+ + ", FeatureRect: " + featureRect
+ + ", WindowConfiguration: " + windowConfiguration);
+ }
+ if (featureRect.top == 0
+ && featureRect.height() != windowConfiguration.getBounds().height()) {
+ throw new IllegalArgumentException("Vertical FoldingFeature must have full height."
+ + " BaseFeatureRect: " + baseFeature.getRect()
+ + ", FeatureRect: " + featureRect
+ + ", WindowConfiguration: " + windowConfiguration);
}
+ features.add(new FoldingFeature(featureRect, baseFeature.getType(), state));
}
return features;
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index ff08782e8cd8..b504b0c0d138 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -183,23 +183,23 @@ public class SplitControllerTest {
// tf2 has running activity so is active.
final TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class);
doReturn(1).when(tf2).getRunningActivityCount();
- taskContainer.mContainers.add(tf2);
+ taskContainer.addTaskFragmentContainer(tf2);
// tf3 is finished so is not active.
final TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class);
doReturn(true).when(tf3).isFinished();
doReturn(false).when(tf3).isWaitingActivityAppear();
- taskContainer.mContainers.add(tf3);
+ taskContainer.addTaskFragmentContainer(tf3);
mSplitController.mTaskContainers.put(TASK_ID, taskContainer);
assertWithMessage("Must return tf2 because tf3 is not active.")
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
- taskContainer.mContainers.remove(tf3);
+ taskContainer.removeTaskFragmentContainer(tf3);
assertWithMessage("Must return tf2 because tf2 has running activity.")
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
- taskContainer.mContainers.remove(tf2);
+ taskContainer.removeTaskFragmentContainer(tf2);
assertWithMessage("Must return tf because we are waiting for tf1 to appear.")
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1);
@@ -320,11 +320,11 @@ public class SplitControllerTest {
doReturn(tf).when(splitContainer).getSecondaryContainer();
doReturn(createTestTaskContainer()).when(splitContainer).getTaskContainer();
doReturn(createSplitRule(mActivity, mActivity)).when(splitContainer).getSplitRule();
- final List<SplitContainer> splitContainers =
- mSplitController.getTaskContainer(TASK_ID).mSplitContainers;
- splitContainers.add(splitContainer);
+ final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+ taskContainer.addSplitContainer(splitContainer);
// Add a mock SplitContainer on top of splitContainer
- splitContainers.add(1, mock(SplitContainer.class));
+ final SplitContainer splitContainer2 = mock(SplitContainer.class);
+ taskContainer.addSplitContainer(splitContainer2);
mSplitController.updateContainer(mTransaction, tf);
@@ -332,7 +332,9 @@ public class SplitControllerTest {
// Verify if one or both containers in the top SplitContainer are finished,
// dismissPlaceholder() won't be called.
- splitContainers.remove(1);
+ final ArrayList<SplitContainer> splitContainersToRemove = new ArrayList<>();
+ splitContainersToRemove.add(splitContainer2);
+ taskContainer.removeSplitContainers(splitContainersToRemove);
doReturn(true).when(tf).isFinished();
mSplitController.updateContainer(mTransaction, tf);
@@ -363,7 +365,8 @@ public class SplitControllerTest {
final Activity r1 = createMockActivity();
addSplitTaskFragments(r0, r1);
final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
- final TaskFragmentContainer taskFragmentContainer = taskContainer.mContainers.get(0);
+ final TaskFragmentContainer taskFragmentContainer =
+ taskContainer.getTaskFragmentContainers().get(0);
spyOn(taskContainer);
// No update when the Task is invisible.
@@ -377,7 +380,7 @@ public class SplitControllerTest {
doReturn(true).when(taskContainer).isVisible();
mSplitController.updateContainer(mTransaction, taskFragmentContainer);
- verify(mSplitPresenter).updateSplitContainer(taskContainer.mSplitContainers.get(0),
+ verify(mSplitPresenter).updateSplitContainer(taskContainer.getSplitContainers().get(0),
mTransaction);
}
@@ -1090,8 +1093,8 @@ public class SplitControllerTest {
verify(mTransaction).finishActivity(mActivity.getActivityToken());
verify(mTransaction).finishActivity(secondaryActivity0.getActivityToken());
verify(mTransaction).finishActivity(secondaryActivity1.getActivityToken());
- assertTrue(taskContainer.mContainers.isEmpty());
- assertTrue(taskContainer.mSplitContainers.isEmpty());
+ assertTrue(taskContainer.getTaskFragmentContainers().isEmpty());
+ assertTrue(taskContainer.getSplitContainers().isEmpty());
}
@Test
@@ -1248,6 +1251,34 @@ public class SplitControllerTest {
}
@Test
+ public void testSplitInfoCallback_NotReportSplitIfUnstable() {
+ final Activity r0 = createMockActivity();
+ final Activity r1 = createMockActivity();
+ addSplitTaskFragments(r0, r1);
+
+ // Should report new SplitInfo list if stable.
+ mSplitController.updateCallbackIfNecessary();
+ assertEquals(1, mSplitInfos.size());
+
+ // Should not report new SplitInfo list if unstable, e.g. any Activity is finishing.
+ mSplitInfos.clear();
+ final Activity r2 = createMockActivity();
+ final Activity r3 = createMockActivity();
+ doReturn(true).when(r2).isFinishing();
+ addSplitTaskFragments(r2, r3);
+
+ mSplitController.updateCallbackIfNecessary();
+ assertTrue(mSplitInfos.isEmpty());
+
+ // Should report SplitInfo list if it becomes stable again.
+ mSplitInfos.clear();
+ doReturn(false).when(r2).isFinishing();
+
+ mSplitController.updateCallbackIfNecessary();
+ assertEquals(2, mSplitInfos.size());
+ }
+
+ @Test
public void testSplitInfoCallback_reportSplitInMultipleTasks() {
final int taskId0 = 1;
final int taskId1 = 2;
@@ -1363,15 +1394,13 @@ public class SplitControllerTest {
TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID);
tf.setInfo(mTransaction, createMockTaskFragmentInfo(tf, mActivity));
- List<TaskFragmentContainer> containers = mSplitController.mTaskContainers.get(TASK_ID)
- .mContainers;
-
- assertEquals(containers.get(0), tf);
+ final TaskContainer taskContainer = mSplitController.mTaskContainers.get(TASK_ID);
+ assertEquals(taskContainer.getTaskFragmentContainers().get(0), tf);
mSplitController.finishActivityStacks(Collections.singleton(tf.getTaskFragmentToken()));
verify(mSplitPresenter).deleteTaskFragment(any(), eq(tf.getTaskFragmentToken()));
- assertTrue(containers.isEmpty());
+ assertTrue(taskContainer.getTaskFragmentContainers().isEmpty());
}
@Test
@@ -1381,10 +1410,8 @@ public class SplitControllerTest {
bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity));
topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity()));
- List<TaskFragmentContainer> containers = mSplitController.mTaskContainers.get(TASK_ID)
- .mContainers;
-
- assertEquals(containers.size(), 2);
+ final TaskContainer taskContainer = mSplitController.mTaskContainers.get(TASK_ID);
+ assertEquals(taskContainer.getTaskFragmentContainers().size(), 2);
Set<IBinder> activityStackTokens = new ArraySet<>(new IBinder[]{
topTf.getTaskFragmentToken(), bottomTf.getTaskFragmentToken()});
@@ -1403,7 +1430,7 @@ public class SplitControllerTest {
+ "regardless of the order in ActivityStack set",
topTf.getTaskFragmentToken(), fragmentTokens.get(1));
- assertTrue(containers.isEmpty());
+ assertTrue(taskContainer.getTaskFragmentContainers().isEmpty());
}
@Test
@@ -1463,6 +1490,51 @@ public class SplitControllerTest {
verify(testRecord).apply(eq(false));
}
+ @Test
+ public void testPinTopActivityStack() {
+ // Create two activities.
+ final Activity primaryActivity = createMockActivity();
+ final Activity secondaryActivity = createMockActivity();
+
+ // Unable to pin if not being embedded.
+ SplitPinRule splitPinRule = new SplitPinRule.Builder(new SplitAttributes.Builder().build(),
+ parentWindowMetrics -> true /* parentWindowMetricsPredicate */).build();
+ assertFalse(mSplitController.pinTopActivityStack(TASK_ID, splitPinRule));
+
+ // Split the two activities.
+ addSplitTaskFragments(primaryActivity, secondaryActivity);
+ final TaskFragmentContainer primaryContainer =
+ mSplitController.getContainerWithActivity(primaryActivity);
+ spyOn(primaryContainer);
+
+ // Unable to pin if no valid TaskFragment.
+ doReturn(true).when(primaryContainer).isFinished();
+ assertFalse(mSplitController.pinTopActivityStack(TASK_ID, splitPinRule));
+
+ // Otherwise, should pin successfully.
+ doReturn(false).when(primaryContainer).isFinished();
+ assertTrue(mSplitController.pinTopActivityStack(TASK_ID, splitPinRule));
+
+ // Unable to pin if there is already a pinned TaskFragment
+ assertFalse(mSplitController.pinTopActivityStack(TASK_ID, splitPinRule));
+
+ // Unable to pin on an unknown Task.
+ assertFalse(mSplitController.pinTopActivityStack(TASK_ID + 1, splitPinRule));
+
+ // Gets the current size of all the SplitContainers.
+ final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+ final int splitContainerCount = taskContainer.getSplitContainers().size();
+
+ // Create another activity and split with primary activity.
+ final Activity thirdActivity = createMockActivity();
+ addSplitTaskFragments(primaryActivity, thirdActivity);
+
+ // Ensure another SplitContainer is added and the pinned TaskFragment still on top
+ assertTrue(taskContainer.getSplitContainers().size() == splitContainerCount + +1);
+ assertTrue(mSplitController.getTopActiveContainer(TASK_ID).getTopNonFinishingActivity()
+ == secondaryActivity);
+ }
+
/** Creates a mock activity in the organizer process. */
private Activity createMockActivity() {
return createMockActivity(TASK_ID);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index 13e709271221..21889960a8b2 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -48,6 +48,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
/**
* Test class for {@link TaskContainer}.
*
@@ -127,7 +129,7 @@ public class TaskContainerTest {
assertFalse(taskContainer.isEmpty());
taskContainer.mFinishedContainer.add(tf.getTaskFragmentToken());
- taskContainer.mContainers.clear();
+ taskContainer.clearTaskFragmentContainer();
assertFalse(taskContainer.isEmpty());
}
@@ -135,15 +137,15 @@ public class TaskContainerTest {
@Test
public void testGetTopTaskFragmentContainer() {
final TaskContainer taskContainer = createTestTaskContainer();
- assertNull(taskContainer.getTopTaskFragmentContainer());
+ assertNull(taskContainer.getTopNonFinishingTaskFragmentContainer());
final TaskFragmentContainer tf0 = new TaskFragmentContainer(null /* activity */,
new Intent(), taskContainer, mController, null /* pairedPrimaryContainer */);
- assertEquals(tf0, taskContainer.getTopTaskFragmentContainer());
+ assertEquals(tf0, taskContainer.getTopNonFinishingTaskFragmentContainer());
final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */,
new Intent(), taskContainer, mController, null /* pairedPrimaryContainer */);
- assertEquals(tf1, taskContainer.getTopTaskFragmentContainer());
+ assertEquals(tf1, taskContainer.getTopNonFinishingTaskFragmentContainer());
}
@Test
@@ -152,17 +154,48 @@ public class TaskContainerTest {
assertNull(taskContainer.getTopNonFinishingActivity());
final TaskFragmentContainer tf0 = mock(TaskFragmentContainer.class);
- taskContainer.mContainers.add(tf0);
+ taskContainer.addTaskFragmentContainer(tf0);
final Activity activity0 = mock(Activity.class);
doReturn(activity0).when(tf0).getTopNonFinishingActivity();
assertEquals(activity0, taskContainer.getTopNonFinishingActivity());
final TaskFragmentContainer tf1 = mock(TaskFragmentContainer.class);
- taskContainer.mContainers.add(tf1);
+ taskContainer.addTaskFragmentContainer(tf1);
assertEquals(activity0, taskContainer.getTopNonFinishingActivity());
final Activity activity1 = mock(Activity.class);
doReturn(activity1).when(tf1).getTopNonFinishingActivity();
assertEquals(activity1, taskContainer.getTopNonFinishingActivity());
}
+
+ @Test
+ public void testGetSplitStatesIfStable() {
+ final TaskContainer taskContainer = createTestTaskContainer();
+
+ final SplitContainer splitContainer0 = mock(SplitContainer.class);
+ final SplitContainer splitContainer1 = mock(SplitContainer.class);
+ final SplitInfo splitInfo0 = mock(SplitInfo.class);
+ final SplitInfo splitInfo1 = mock(SplitInfo.class);
+ taskContainer.addSplitContainer(splitContainer0);
+ taskContainer.addSplitContainer(splitContainer1);
+
+ // When all the SplitContainers are stable, getSplitStatesIfStable() returns the list of
+ // SplitInfo representing the SplitContainers.
+ doReturn(splitInfo0).when(splitContainer0).toSplitInfoIfStable();
+ doReturn(splitInfo1).when(splitContainer1).toSplitInfoIfStable();
+
+ List<SplitInfo> splitInfoList = taskContainer.getSplitStatesIfStable();
+
+ assertEquals(2, splitInfoList.size());
+ assertEquals(splitInfo0, splitInfoList.get(0));
+ assertEquals(splitInfo1, splitInfoList.get(1));
+
+ // When any SplitContainer is in an intermediate state, getSplitStatesIfStable() returns
+ // null.
+ doReturn(null).when(splitContainer0).toSplitInfoIfStable();
+
+ splitInfoList = taskContainer.getSplitStatesIfStable();
+
+ assertNull(splitInfoList);
+ }
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 78b85e642c13..cc00a49604ee 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -321,6 +321,32 @@ public class TaskFragmentContainerTest {
}
@Test
+ public void testCollectNonFinishingActivities_checkIfStable() {
+ final TaskContainer taskContainer = createTestTaskContainer();
+ final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+ mIntent, taskContainer, mController, null /* pairedPrimaryContainer */);
+
+ // In case mInfo is null, collectNonFinishingActivities(true) should return null.
+ List<Activity> activities =
+ container.collectNonFinishingActivities(true /* checkIfStable */);
+ assertNull(activities);
+
+ // collectNonFinishingActivities(true) should return proper value when the container is in a
+ // stable state.
+ final List<IBinder> runningActivities = Lists.newArrayList(mActivity.getActivityToken());
+ doReturn(runningActivities).when(mInfo).getActivities();
+ container.setInfo(mTransaction, mInfo);
+ activities = container.collectNonFinishingActivities(true /* checkIfStable */);
+ assertEquals(1, activities.size());
+
+ // In case any activity is finishing, collectNonFinishingActivities(true) should return
+ // null.
+ doReturn(true).when(mActivity).isFinishing();
+ activities = container.collectNonFinishingActivities(true /* checkIfStable */);
+ assertNull(activities);
+ }
+
+ @Test
public void testAddPendingActivity() {
final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 54978bd4496d..e9abc7e522d5 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -42,16 +42,19 @@ filegroup {
filegroup {
name: "wm_shell_util-sources",
srcs: [
- "src/com/android/wm/shell/util/**/*.java",
+ "src/com/android/wm/shell/animation/Interpolators.java",
+ "src/com/android/wm/shell/animation/PhysicsAnimator.kt",
+ "src/com/android/wm/shell/common/bubbles/*.kt",
+ "src/com/android/wm/shell/common/bubbles/*.java",
+ "src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt",
"src/com/android/wm/shell/common/split/SplitScreenConstants.java",
- "src/com/android/wm/shell/sysui/ShellSharedConstants.java",
"src/com/android/wm/shell/common/TransactionPool.java",
- "src/com/android/wm/shell/common/bubbles/*.java",
"src/com/android/wm/shell/common/TriangleShape.java",
- "src/com/android/wm/shell/animation/Interpolators.java",
+ "src/com/android/wm/shell/draganddrop/DragAndDropConstants.java",
"src/com/android/wm/shell/pip/PipContentOverlay.java",
"src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java",
- "src/com/android/wm/shell/draganddrop/DragAndDropConstants.java",
+ "src/com/android/wm/shell/sysui/ShellSharedConstants.java",
+ "src/com/android/wm/shell/util/**/*.java",
],
path: "src",
}
@@ -112,8 +115,7 @@ genrule {
name: "protolog.json.gz",
srcs: [":generate-wm_shell_protolog.json"],
out: ["wmshell.protolog.json.gz"],
- cmd: "$(location minigzip) -c < $(in) > $(out)",
- tools: ["minigzip"],
+ cmd: "gzip -c < $(in) > $(out)",
}
prebuilt_etc {
@@ -148,6 +150,7 @@ android_library {
],
static_libs: [
"androidx.appcompat_appcompat",
+ "androidx.core_core-animation",
"androidx.arch.core_core-runtime",
"androidx-constraintlayout_constraintlayout",
"androidx.dynamicanimation_dynamicanimation",
@@ -155,7 +158,6 @@ android_library {
"kotlinx-coroutines-android",
"kotlinx-coroutines-core",
"iconloader_base",
- "protolog-lib",
"WindowManager-Shell-proto",
"dagger2",
"jsr330",
@@ -165,7 +167,7 @@ android_library {
// *.kt sources are inside a filegroup.
"kotlin-annotations",
],
- kotlincflags: ["-Xjvm-default=enable"],
+ kotlincflags: ["-Xjvm-default=all"],
manifest: "AndroidManifest.xml",
plugins: ["dagger2-compiler"],
}
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_section.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_section.xml
new file mode 100644
index 000000000000..d99d64d8da20
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_section.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <ripple android:color="#99999999">
+ <item android:drawable="@drawable/bubble_manage_menu_bg" />
+ </ripple>
+ </item>
+ <item android:drawable="@drawable/bubble_manage_menu_bg" />
+</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml
new file mode 100644
index 000000000000..02b707568cd0
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:tint="?attr/colorControlNormal"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M180,840Q156,840 138,822Q120,804 120,780L120,180Q120,156 138,138Q156,120 180,120L780,120Q804,120 822,138Q840,156 840,180L840,780Q840,804 822,822Q804,840 780,840L180,840ZM180,780L780,780Q780,780 780,780Q780,780 780,780L780,277L180,277L180,780Q180,780 180,780Q180,780 180,780Z" />
+</vector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
index 5d7771366bec..ce242751c172 100644
--- a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
+++ b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
@@ -13,13 +13,20 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <group android:translateY="8.0">
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="128dp"
+ android:height="4dp"
+ android:viewportWidth="128"
+ android:viewportHeight="4"
+ >
+ <group>
+ <clip-path
+ android:pathData="M2 0H126C127.105 0 128 0.895431 128 2C128 3.10457 127.105 4 126 4H2C0.895431 4 0 3.10457 0 2C0 0.895431 0.895431 0 2 0Z"
+ />
<path
- android:fillColor="@android:color/black" android:pathData="M3,5V3H21V5Z"/>
+ android:pathData="M0 0V4H128V0"
+ android:fillColor="@android:color/black"
+ />
</group>
</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/ic_expand_less.xml b/libs/WindowManager/Shell/res/drawable/ic_expand_less.xml
new file mode 100644
index 000000000000..f4508464883d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/ic_expand_less.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M18.59,16.41L20,15L12,7L4,15L5.41,16.41L12,9.83"
+ android:fillColor="#5F6368"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml
new file mode 100644
index 000000000000..ddcd5c60d9c8
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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
+ -->
+<com.android.wm.shell.bubbles.bar.BubbleBarMenuItemView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/bubble_bar_manage_menu_item_height"
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/bubble_menu_padding"
+ android:paddingEnd="@dimen/bubble_menu_padding"
+ android:background="@drawable/bubble_manage_menu_row">
+
+ <ImageView
+ android:id="@+id/bubble_bar_menu_item_icon"
+ android:layout_width="@dimen/bubble_bar_manage_menu_item_icon_size"
+ android:layout_height="@dimen/bubble_bar_manage_menu_item_icon_size"
+ android:contentDescription="@null"/>
+
+ <TextView
+ android:id="@+id/bubble_bar_menu_item_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault" />
+
+</com.android.wm.shell.bubbles.bar.BubbleBarMenuItemView> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml
new file mode 100644
index 000000000000..82e5aee41ff2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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
+ -->
+<com.android.wm.shell.bubbles.bar.BubbleBarMenuView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:minWidth="@dimen/bubble_bar_manage_menu_min_width"
+ android:orientation="vertical"
+ android:elevation="@dimen/bubble_manage_menu_elevation"
+ android:paddingTop="@dimen/bubble_bar_manage_menu_padding_top"
+ android:paddingHorizontal="@dimen/bubble_bar_manage_menu_padding"
+ android:paddingBottom="@dimen/bubble_bar_manage_menu_padding"
+ android:clipToPadding="false">
+
+ <LinearLayout
+ android:id="@+id/bubble_bar_manage_menu_bubble_section"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/bubble_bar_manage_menu_item_height"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:paddingStart="14dp"
+ android:paddingEnd="12dp"
+ android:background="@drawable/bubble_manage_menu_section"
+ android:elevation="@dimen/bubble_manage_menu_elevation">
+
+ <ImageView
+ android:id="@+id/bubble_bar_manage_menu_bubble_icon"
+ android:layout_width="@dimen/bubble_menu_icon_size"
+ android:layout_height="@dimen/bubble_menu_icon_size"
+ android:contentDescription="@null" />
+
+ <TextView
+ android:id="@+id/bubble_bar_manage_menu_bubble_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:layout_weight="1"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault" />
+
+ <ImageView
+ android:id="@+id/bubble_bar_manage_menu_dismiss_icon"
+ android:layout_width="@dimen/bubble_bar_manage_menu_dismiss_icon_size"
+ android:layout_height="@dimen/bubble_bar_manage_menu_dismiss_icon_size"
+ android:layout_marginStart="8dp"
+ android:contentDescription="@null"
+ android:src="@drawable/ic_expand_less"
+ app:tint="?android:attr/textColorPrimary" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/bubble_bar_manage_menu_actions_section"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginTop="@dimen/bubble_bar_manage_menu_section_spacing"
+ android:background="@drawable/bubble_manage_menu_bg"
+ android:elevation="@dimen/bubble_manage_menu_elevation" />
+
+</com.android.wm.shell.bubbles.bar.BubbleBarMenuView> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
index fb1980a52601..7e0c2071dc86 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
@@ -78,6 +78,19 @@
android:layout_weight="1"/>
<ImageButton
+ android:id="@+id/maximize_window"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:padding="9dp"
+ android:layout_marginEnd="8dp"
+ android:contentDescription="@string/maximize_button_text"
+ android:src="@drawable/decor_desktop_mode_maximize_button_dark"
+ android:scaleType="fitCenter"
+ android:gravity="end"
+ android:background="@null"
+ android:tint="@color/desktop_mode_caption_maximize_button_dark"/>
+
+ <ImageButton
android:id="@+id/close_window"
android:layout_width="40dp"
android:layout_height="40dp"
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml
index 1d6864c152c2..d93e9ba32105 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml
@@ -25,9 +25,9 @@
<ImageButton
android:id="@+id/caption_handle"
- android:layout_width="176dp"
+ android:layout_width="128dp"
android:layout_height="42dp"
- android:paddingHorizontal="24dp"
+ android:paddingVertical="19dp"
android:contentDescription="@string/handle_text"
android:src="@drawable/decor_handle_dark"
tools:tint="@color/desktop_mode_caption_handle_bar_dark"
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index ee00e2651f62..de4a225e41a7 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Verander grootte"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Hou vas"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Laat los"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Program sal dalk nie met verdeelde skerm werk nie."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Program steun nie verdeelde skerm nie."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"App sal dalk nie met verdeelde skerm werk nie"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"App steun nie verdeelde skerm nie"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Hierdie app kan net in 1 venster oopgemaak word."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Program sal dalk nie op \'n sekondêre skerm werk nie."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Program steun nie begin op sekondêre skerms nie."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Skermverdeler"</string>
- <string name="divider_title" msgid="5482989479865361192">"Skermverdeler"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Skermverdeler"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Skermverdeler"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Volskerm links"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Links 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Links 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bo 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Bo 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Volskerm onder"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Verdeel links"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Verdeel regs"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Verdeel bo"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Verdeel onder"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Gebruik eenhandmodus"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Swiep van die onderkant van die skerm af op of tik enige plek bo die program om uit te gaan"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Begin eenhandmodus"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nie opgelos nie?\nTik om terug te stel"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen kamerakwessies nie? Tik om toe te maak."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sien en doen meer"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Sleep ’n ander program in vir verdeelde skerm"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Sleep ’n ander app in vir verdeelde skerm"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik buite ’n program om dit te herposisioneer"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Het dit"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vou uit vir meer inligting."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Kanselleer"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Herbegin"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Moenie weer wys nie"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dubbeltik om\nhierdie app te skuif"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimeer"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Maak klein"</string>
<string name="close_button_text" msgid="2913281996024033299">"Maak toe"</string>
<string name="back_button_text" msgid="1469718707134137085">"Terug"</string>
<string name="handle_text" msgid="1766582106752184456">"Handvatsel"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Appikoon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Volskerm"</string>
<string name="desktop_text" msgid="1077633567027630454">"Rekenaarmodus"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Verdeelde skerm"</string>
<string name="more_button_text" msgid="3655388105592893530">"Meer"</string>
<string name="float_button_text" msgid="9221657008391364581">"Sweef"</string>
+ <string name="select_text" msgid="5139083974039906583">"Kies"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Skermskoot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Maak toe"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Maak kieslys oop"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 781038f1e61e..ca08d56d1697 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -32,31 +32,27 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"መጠን ይቀይሩ"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"መተግበሪያ ከተከፈለ ማያ ገጽ ጋር ላይሠራ ይችላል"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"መተግበሪያ ከተከፈለ ማያ ገፅ ጋር ላይሠራ ይችላል"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ይህ መተግበሪያ መከፈት የሚችለው በ1 መስኮት ብቻ ነው።"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"መተግበሪያ በሁለተኛ ማሳያ ላይ ላይሠራ ይችላል።"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"መተግበሪያ በሁለተኛ ማሳያዎች ላይ ማስጀመርን አይደግፍም።"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"የተከፈለ የማያ ገጽ ከፋይ"</string>
- <string name="divider_title" msgid="5482989479865361192">"የተከፈለ የማያ ገጽ ከፋይ"</string>
- <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"የግራ ሙሉ ማያ ገጽ"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"የተከፈለ የማያ ገፅ ከፋይ"</string>
+ <string name="divider_title" msgid="1963391955593749442">"የተከፈለ የማያ ገፅ ከፋይ"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"የግራ ሙሉ ማያ ገፅ"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ግራ 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ግራ 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ግራ 30%"</string>
- <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"የቀኝ ሙሉ ማያ ገጽ"</string>
- <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"የላይ ሙሉ ማያ ገጽ"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"የቀኝ ሙሉ ማያ ገፅ"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"የላይ ሙሉ ማያ ገፅ"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ከላይ 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ከላይ 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ከላይ 30%"</string>
- <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"የታች ሙሉ ማያ ገጽ"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"የታች ሙሉ ማያ ገፅ"</string>
+ <string name="accessibility_split_left" msgid="1713683765575562458">"ወደ ግራ ከፋፍል"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"ወደ ቀኝ ከፋፍል"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"ወደ ላይ ከፋፍል"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"ወደ ታች ከፋፍል"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"ባለአንድ እጅ ሁነታን በመጠቀም ላይ"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"ለመውጣት ከማያው ግርጌ ወደ ላይ ይጥረጉ ወይም ከመተግበሪያው በላይ ማንኛውም ቦታ ላይ መታ ያድርጉ"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ባለአንድ እጅ ሁነታ ጀምር"</string>
@@ -88,8 +84,8 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"አልተስተካከለም?\nለማህደር መታ ያድርጉ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ምንም የካሜራ ችግሮች የሉም? ለማሰናበት መታ ያድርጉ።"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ተጨማሪ ይመልከቱ እና ያድርጉ"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ለተከፈለ ማያ ገጽ ሌላ መተግበሪያ ይጎትቱ"</string>
- <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ቦታውን ለመቀየር ከመተግበሪያው ውጪ ሁለቴ መታ ያድርጉ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ለተከፈለ ማያ ገፅ ሌላ መተግበሪያ ይጎትቱ"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ቦታውን ለመቀየር ከመተግበሪያው ውጭ ሁለቴ መታ ያድርጉ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ገባኝ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ለተጨማሪ መረጃ ይዘርጉ።"</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"ለተሻለ ዕይታ እንደገና ይጀመር?"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"ይቅር"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"እንደገና ያስጀምሩ"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ዳግም አታሳይ"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ይህን መተግበሪያ\nለማንቀሳቀስ ሁለቴ መታ ያድርጉ"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"አስፋ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"አሳንስ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ዝጋ"</string>
<string name="back_button_text" msgid="1469718707134137085">"ተመለስ"</string>
<string name="handle_text" msgid="1766582106752184456">"መያዣ"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"የመተግበሪያ አዶ"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ሙሉ ማያ"</string>
<string name="desktop_text" msgid="1077633567027630454">"የዴስክቶፕ ሁነታ"</string>
- <string name="split_screen_text" msgid="1396336058129570886">"የተከፈለ ማያ ገጽ"</string>
+ <string name="split_screen_text" msgid="1396336058129570886">"የተከፈለ ማያ ገፅ"</string>
<string name="more_button_text" msgid="3655388105592893530">"ተጨማሪ"</string>
<string name="float_button_text" msgid="9221657008391364581">"ተንሳፋፊ"</string>
+ <string name="select_text" msgid="5139083974039906583">"ምረጥ"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"ቅጽበታዊ ገፅ እይታ"</string>
+ <string name="close_text" msgid="4986518933445178928">"ዝጋ"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"ምናሌን ክፈት"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings_tv.xml b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
index a6be57889a4e..84c1c6763d43 100644
--- a/libs/WindowManager/Shell/res/values-am/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
@@ -20,7 +20,7 @@
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ሥዕል-ላይ-ሥዕል"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ርዕስ የሌለው ፕሮግራም)"</string>
<string name="pip_close" msgid="2955969519031223530">"ዝጋ"</string>
- <string name="pip_fullscreen" msgid="7278047353591302554">"ሙሉ ማያ ገጽ"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"ሙሉ ማያ ገፅ"</string>
<string name="pip_move" msgid="158770205886688553">"ውሰድ"</string>
<string name="pip_expand" msgid="1051966011679297308">"ዘርጋ"</string>
<string name="pip_collapse" msgid="3903295106641385962">"ሰብስብ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 7325da135d94..a714b49d1305 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغيير الحجم"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"إخفاء"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"إظهار"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"قد لا يعمل التطبيق بشكل سليم في وضع \"تقسيم الشاشة\"."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"التطبيق لا يتيح تقسيم الشاشة."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"قد لا يعمل التطبيق بشكل سليم في وضع تقسيم الشاشة."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"لا يعمل التطبيق في وضع تقسيم الشاشة."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"لا يمكن فتح هذا التطبيق إلا في نافذة واحدة."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"قد لا يعمل التطبيق على شاشة عرض ثانوية."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"لا يمكن تشغيل التطبيق على شاشات عرض ثانوية."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"أداة تقسيم الشاشة"</string>
- <string name="divider_title" msgid="5482989479865361192">"أداة تقسيم الشاشة"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"أداة تقسيم الشاشة"</string>
+ <string name="divider_title" msgid="1963391955593749442">"أداة تقسيم الشاشة"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"عرض النافذة اليسرى بملء الشاشة"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ضبط حجم النافذة اليسرى ليكون ٧٠%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ضبط حجم النافذة اليسرى ليكون ٥٠%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ضبط حجم النافذة العلوية ليكون ٥٠%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ضبط حجم النافذة العلوية ليكون ٣٠%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"عرض النافذة السفلية بملء الشاشة"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"تقسيم لليسار"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"تقسيم لليمين"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"تقسيم للأعلى"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"تقسيم للأسفل"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"استخدام وضع \"التصفح بيد واحدة\""</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"للخروج، مرِّر سريعًا من أسفل الشاشة إلى أعلاها أو انقر في أي مكان فوق التطبيق."</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"بدء وضع \"التصفح بيد واحدة\""</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ألم يتم حل المشكلة؟\nانقر للعودة"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"أليس هناك مشاكل في الكاميرا؟ انقر للإغلاق."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"استخدام تطبيقات متعدّدة في وقت واحد"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"اسحب تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"اسحب تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"انقر مرّتين خارج تطبيق لتغيير موضعه."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"حسنًا"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"التوسيع للحصول على مزيد من المعلومات"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"إلغاء"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"إعادة التشغيل"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"عدم عرض مربّع حوار التأكيد مجددًا"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"انقر مرّتَين لنقل\nهذا التطبيق."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"تكبير"</string>
<string name="minimize_button_text" msgid="271592547935841753">"تصغير"</string>
<string name="close_button_text" msgid="2913281996024033299">"إغلاق"</string>
<string name="back_button_text" msgid="1469718707134137085">"رجوع"</string>
<string name="handle_text" msgid="1766582106752184456">"مقبض"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"رمز التطبيق"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ملء الشاشة"</string>
<string name="desktop_text" msgid="1077633567027630454">"وضع سطح المكتب"</string>
<string name="split_screen_text" msgid="1396336058129570886">"تقسيم الشاشة"</string>
<string name="more_button_text" msgid="3655388105592893530">"المزيد"</string>
<string name="float_button_text" msgid="9221657008391364581">"نافذة عائمة"</string>
+ <string name="select_text" msgid="5139083974039906583">"اختيار"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"لقطة شاشة"</string>
+ <string name="close_text" msgid="4986518933445178928">"إغلاق"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"فتح القائمة"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 3fd705e8a07b..6d86747ef336 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"আকাৰ সলনি কৰক"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"লুকুৱাওক"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"দেখুৱাওক"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"এপ্‌টোৱে বিভাজিত স্ক্ৰীনৰ সৈতে কাম নকৰিব পাৰে।"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"এপ্‌টোৱে বিভাজিত স্ক্ৰীন সমৰ্থন নকৰে।"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"এপ্‌টোৱে বিভাজিত স্ক্ৰীনৰ সৈতে কাম নকৰিব পাৰে"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"এপ্‌টোৱে বিভাজিত স্ক্ৰীন সমৰ্থন নকৰে"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"এই এপ্‌টো কেৱল ১ খন ৱিণ্ড’ত খুলিব পাৰি।"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"গৌণ ডিছপ্লেত এপে সঠিকভাৱে কাম নকৰিব পাৰে।"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"গৌণ ডিছপ্লেত এপ্ লঞ্চ কৰিব নোৱাৰি।"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"স্প্লিট স্ক্ৰীনৰ বিভাজক"</string>
- <string name="divider_title" msgid="5482989479865361192">"বিভাজিত স্ক্ৰীনৰ বিভাজক"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"স্প্লিট স্ক্ৰীনৰ বিভাজক"</string>
+ <string name="divider_title" msgid="1963391955593749442">"স্প্লিট স্ক্ৰীনৰ বিভাজক"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাওঁফালৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"বাওঁফালৰ স্ক্ৰীনখন ৭০% কৰক"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"বাওঁফালৰ স্ক্ৰীনখন ৫০% কৰক"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ স্ক্ৰীনখন ৫০% কৰক"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"শীর্ষ স্ক্ৰীনখন ৩০% কৰক"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"তলৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"বাওঁফালে বিভাজন কৰক"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"সোঁফালে বিভাজন কৰক"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"একেবাৰে ওপৰৰফালে বিভাজন কৰক"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"একেবাৰে তলৰফালে বিভাজন কৰক"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড ব্যৱহাৰ কৰা"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"বাহিৰ হ’বলৈ স্ক্ৰীনখনৰ একেবাৰে তলৰ পৰা ওপৰলৈ ছোৱাইপ কৰক অথবা এপ্‌টোৰ ওপৰত যিকোনো ঠাইত টিপক"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"এখন হাতেৰে ব্যৱহাৰ কৰা ম\'ডটো আৰম্ভ কৰক"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এইটো সমাধান কৰা নাই নেকি?\nপূৰ্বাৱস্থালৈ নিবলৈ টিপক"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"কেমেৰাৰ কোনো সমস্যা নাই নেকি? অগ্ৰাহ্য কৰিবলৈ টিপক।"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"চাওক আৰু অধিক কৰক"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"বিভাজিত স্ক্ৰীনৰ বাবে অন্য এটা এপ্‌ টানি আনি এৰক"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"বিভাজিত স্ক্ৰীনৰ বাবে অন্য এটা এপ্‌ টানি আনি এৰক"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"এপ্‌টোৰ স্থান সলনি কৰিবলৈ ইয়াৰ বাহিৰত দুবাৰ টিপক"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুজি পালোঁ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"অধিক তথ্যৰ বাবে বিস্তাৰ কৰক।"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"বাতিল কৰক"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"ৰিষ্টাৰ্ট কৰক"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"পুনৰাই নেদেখুৱাব"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"এই এপ্‌টো\nস্থানান্তৰ কৰিবলৈ দুবাৰ টিপক"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"সৰ্বাধিক মাত্ৰালৈ বঢ়াওক"</string>
<string name="minimize_button_text" msgid="271592547935841753">"মিনিমাইজ কৰক"</string>
<string name="close_button_text" msgid="2913281996024033299">"বন্ধ কৰক"</string>
<string name="back_button_text" msgid="1469718707134137085">"উভতি যাওক"</string>
<string name="handle_text" msgid="1766582106752184456">"হেণ্ডেল"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"এপৰ চিহ্ন"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"সম্পূৰ্ণ স্ক্ৰীন"</string>
<string name="desktop_text" msgid="1077633567027630454">"ডেস্কটপ ম’ড"</string>
<string name="split_screen_text" msgid="1396336058129570886">"বিভাজিত স্ক্ৰীন"</string>
<string name="more_button_text" msgid="3655388105592893530">"অধিক"</string>
<string name="float_button_text" msgid="9221657008391364581">"ওপঙা"</string>
+ <string name="select_text" msgid="5139083974039906583">"বাছনি কৰক"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"স্ক্ৰীনশ্বট"</string>
+ <string name="close_text" msgid="4986518933445178928">"বন্ধ কৰক"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"মেনু খোলক"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index a31b1e7eb9cd..7c662827cca7 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ölçüsünü dəyişin"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Güvənli məkanda saxlayın"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Güvənli məkandan çıxarın"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Tətbiq bölünmüş ekran ilə işləməyə bilər."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Tətbiq ekran bölünməsini dəstəkləmir."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Tətbiq bölünmüş ekranda işləməyə bilər"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Tətbiq bölünmüş ekranı dəstəkləmir"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Bu tətbiq yalnız 1 pəncərədə açıla bilər."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Tətbiq ikinci ekranda işləməyə bilər."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Tətbiq ikinci ekranda başlamağı dəstəkləmir."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Bölünmüş ekran ayırıcısı"</string>
- <string name="divider_title" msgid="5482989479865361192">"Bölünmüş ekran ayırıcısı"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Bölünmüş ekran ayırıcısı"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Bölünmüş ekran ayırıcısı"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Sol tam ekran"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Sol 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sol 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yuxarı 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Yuxarı 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Aşağı tam ekran"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Sola ayırın"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Sağa ayırın"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Yuxarı ayırın"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Aşağı ayırın"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Birəlli rejim istifadəsi"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Çıxmaq üçün ekranın aşağısından yuxarıya doğru sürüşdürün və ya tətbiqin yuxarısında istənilən yerə toxunun"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Birəlli rejim başlasın"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Düzəltməmisiniz?\nGeri qaytarmaq üçün toxunun"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera problemi yoxdur? Qapatmaq üçün toxunun."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ardını görün və edin"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Bölünmüş ekrandan istifadə etmək üçün başqa tətbiqi sürüşdürüb gətirin"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Bölünmüş ekran üçün başqa tətbiq sürüşdürün"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tətbiqin yerini dəyişmək üçün kənarına iki dəfə toxunun"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ətraflı məlumat üçün genişləndirin."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Ləğv edin"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Yenidən başladın"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Yenidən göstərməyin"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tətbiqi köçürmək üçün\niki dəfə toxunun"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Böyüdün"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Kiçildin"</string>
<string name="close_button_text" msgid="2913281996024033299">"Bağlayın"</string>
<string name="back_button_text" msgid="1469718707134137085">"Geriyə"</string>
<string name="handle_text" msgid="1766582106752184456">"Hər kəsə açıq istifadəçi adı"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Tətbiq ikonası"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Tam Ekran"</string>
<string name="desktop_text" msgid="1077633567027630454">"Masaüstü Rejimi"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Bölünmüş Ekran"</string>
<string name="more_button_text" msgid="3655388105592893530">"Ardı"</string>
<string name="float_button_text" msgid="9221657008391364581">"Üzən pəncərə"</string>
+ <string name="select_text" msgid="5139083974039906583">"Seçin"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Skrinşot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Bağlayın"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Menyunu bağlayın"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Menyunu açın"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index c0e4789d3d97..c415c868ac04 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promenite veličinu"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stavite u tajnu memoriju"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Uklonite iz tajne memorije"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi sa podeljenim ekranom."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podeljeni ekran."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Aplikacija možda neće raditi sa podeljenim ekranom."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikacija ne podržava podeljeni ekran."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ova aplikacija može da se otvori samo u jednom prozoru."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionisati na sekundarnom ekranu."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Razdelnik podeljenog ekrana"</string>
- <string name="divider_title" msgid="5482989479865361192">"Razdelnik podeljenog ekrana"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Razdelnik podeljenog ekrana"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Razdelnik podeljenog ekrana"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Režim celog ekrana za levi ekran"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Levi ekran 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Levi ekran 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gornji ekran 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gornji ekran 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Režim celog ekrana za donji ekran"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Podelite levo"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Podelite desno"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Podelite u vrhu"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Podelite u dnu"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Korišćenje režima jednom rukom"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Da biste izašli, prevucite nagore od dna ekrana ili dodirnite bilo gde iznad aplikacije"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Pokrenite režim jednom rukom"</string>
@@ -88,23 +84,30 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije rešen?\nDodirnite da biste vratili"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema sa kamerom? Dodirnite da biste odbacili."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vidite i uradite više"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Prevucite drugu aplikaciju da biste koristili podeljeni ekran"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Prevucite drugu aplikaciju da biste koristili podeljeni ekran"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste promenili njenu poziciju"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Važi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za još informacija."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Želite li da restartujete radi boljeg prikaza?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Možete da restartujete aplikaciju da bi izgledala bolje na ekranu, s tim što možete da izgubite ono što ste uradili ili nesačuvane promene, ako ih ima"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Možete da restartujete aplikaciju da bi izgledala bolje na ekranu, ali možete da izgubite napredak ili nesačuvane promene"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Otkaži"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartuj"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovo"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvaput dodirnite da biste\npremestili ovu aplikaciju"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Uvećajte"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Umanjite"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zatvorite"</string>
<string name="back_button_text" msgid="1469718707134137085">"Nazad"</string>
<string name="handle_text" msgid="1766582106752184456">"Identifikator"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Preko celog ekrana"</string>
<string name="desktop_text" msgid="1077633567027630454">"Režim za računare"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Podeljeni ekran"</string>
<string name="more_button_text" msgid="3655388105592893530">"Još"</string>
<string name="float_button_text" msgid="9221657008391364581">"Plutajuće"</string>
+ <string name="select_text" msgid="5139083974039906583">"Izaberite"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string>
+ <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Otvorite meni"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index b67e2cdca49e..3d99514e2172 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змяніць памер"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Схаваць"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Паказаць"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Праграма можа не працаваць у рэжыме падзеленага экрана."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Праграма не падтрымлівае функцыю дзялення экрана."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Праграма можа не працаваць у рэжыме падзеленага экрана"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Праграма не падтрымлівае рэжым падзеленага экрана"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Гэту праграму можна адкрыць толькі ў адным акне."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Праграма можа не працаваць на дадатковых экранах."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Праграма не падтрымлівае запуск на дадатковых экранах."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Раздзяляльнік падзеленага экрана"</string>
- <string name="divider_title" msgid="5482989479865361192">"Раздзяляльнік падзеленага экрана"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Раздзяляльнік падзеленага экрана"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Раздзяляльнік падзеленага экрана"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левы экран – поўнаэкранны рэжым"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Левы экран – 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левы экран – 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхні экран – 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Верхні экран – 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ніжні экран – поўнаэкранны рэжым"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Падзяліць злева"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Падзяліць справа"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Падзяліць уверсе"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Падзяліць унізе"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Выкарыстоўваецца рэжым кіравання адной рукой"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Каб выйсці, правядзіце па экране пальцам знізу ўверх або націсніце ў любым месцы над праграмай"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Запусціць рэжым кіравання адной рукой"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не ўдалося выправіць?\nНацісніце, каб аднавіць"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ніякіх праблем з камерай? Націсніце, каб адхіліць."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Адначасова выконвайце розныя задачы"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Перацягніце іншую праграму, каб выкарыстоўваць падзелены экран"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Перацягніце іншую праграму, каб выкарыстоўваць падзелены экран"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двойчы націсніце экран па-за праграмай, каб перамясціць яе"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Зразумела"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгарнуць для дадатковай інфармацыі"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Скасаваць"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Перазапусціць"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Больш не паказваць"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Каб перамясціць праграму,\nнацісніце двойчы"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Разгарнуць"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Згарнуць"</string>
<string name="close_button_text" msgid="2913281996024033299">"Закрыць"</string>
<string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
<string name="handle_text" msgid="1766582106752184456">"Маркер"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Значок праграмы"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"На ўвесь экран"</string>
<string name="desktop_text" msgid="1077633567027630454">"Рэжым працоўнага стала"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Падзяліць экран"</string>
<string name="more_button_text" msgid="3655388105592893530">"Яшчэ"</string>
<string name="float_button_text" msgid="9221657008391364581">"Зрабіць рухомым акном"</string>
+ <string name="select_text" msgid="5139083974039906583">"Выбраць"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Здымак экрана"</string>
+ <string name="close_text" msgid="4986518933445178928">"Закрыць"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Адкрыць меню"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 9bf396dc04c9..0473f270239a 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Преоразмеряване"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Съхраняване"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Отмяна на съхраняването"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Приложението може да не работи в режим на разделен екран."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложението не поддържа разделен екран."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Приложението може да не работи в режим на разделен екран"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Приложението не поддържа разделен екран"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Това приложение може да се отвори само в 1 прозорец."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Възможно е приложението да не работи на алтернативни дисплеи."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Приложението не поддържа използването на алтернативни дисплеи."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Разделител в режима за разделен екран"</string>
- <string name="divider_title" msgid="5482989479865361192">"Разделител в режима за разделен екран"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Разделител в режима за разделен екран"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Разделител в режима за разделен екран"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ляв екран: Показване на цял екран"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ляв екран: 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ляв екран: 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горен екран: 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Горен екран: 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Долен екран: Показване на цял екран"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Разделяне в лявата част"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Разделяне в дясната част"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Разделяне в горната част"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Разделяне в долната част"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Използване на режима за работа с една ръка"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"За изход прекарайте пръст нагоре от долната част на екрана или докоснете произволно място над приложението"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Стартиране на режима за работа с една ръка"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблемът не се отстрани?\nДокоснете за връщане в предишното състояние"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нямате проблеми с камерата? Докоснете, за да отхвърлите."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Преглеждайте и правете повече неща"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Преместете друго приложение с плъзгане, за да преминете в режим за разделен екран"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Преместете друго приложение с плъзгане, за да преминете в режим за разделен екран"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Докоснете два пъти извън дадено приложение, за да промените позицията му"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Разбрах"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгъване за още информация."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Отказ"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартиране"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Да не се показва отново"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Докоснете двукратно, за да\nпреместите това приложение"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Увеличаване"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Намаляване"</string>
<string name="close_button_text" msgid="2913281996024033299">"Затваряне"</string>
<string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
<string name="handle_text" msgid="1766582106752184456">"Манипулатор"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Икона на приложението"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Цял екран"</string>
<string name="desktop_text" msgid="1077633567027630454">"Режим за настолни компютри"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Разделяне на екрана"</string>
<string name="more_button_text" msgid="3655388105592893530">"Още"</string>
<string name="float_button_text" msgid="9221657008391364581">"Плаващо"</string>
+ <string name="select_text" msgid="5139083974039906583">"Избиране"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Екранна снимка"</string>
+ <string name="close_text" msgid="4986518933445178928">"Затваряне"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Отваряне на менюто"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index affb62e74591..4fe1be0c455e 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"রিসাইজ করুন"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"স্ট্যাস করুন"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"আনস্ট্যাস করুন"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"অ্যাপটি স্প্লিট স্ক্রিনে কাজ নাও করতে পারে।"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"অ্যাপ্লিকেশান বিভক্ত-স্ক্রিন সমর্থন করে না৷"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"স্প্লিট স্ক্রিনে এই অ্যাপ নাও কাজ করতে পারে"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"স্প্লিট স্ক্রিনে এই অ্যাপ কাজ করে না"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"এই অ্যাপটি শুধু ১টি উইন্ডোয় খোলা যেতে পারে।"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"সেকেন্ডারি ডিসপ্লেতে অ্যাপটি কাজ নাও করতে পারে।"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"সেকেন্ডারি ডিসপ্লেতে অ্যাপ লঞ্চ করা যাবে না।"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"বিভক্ত-স্ক্রিন বিভাজক"</string>
- <string name="divider_title" msgid="5482989479865361192">"স্প্লিট স্ক্রিন বিভাজক"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"স্প্লিট স্ক্রিন বিভাজক"</string>
+ <string name="divider_title" msgid="1963391955593749442">"স্প্লিট স্ক্রিন বিভাজক"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাঁ দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"৭০% বাকি আছে"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"৫০% বাকি আছে"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ ৫০%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"শীর্ষ ৩০%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"নীচের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"স্ক্রিনের বাঁদিকে স্প্লিট করুন"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"স্ক্রিনের ডানদিকে স্প্লিট করুন"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"স্ক্রিনের উপরের দিকে স্প্লিট করুন"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"স্প্লিট করার বোতাম"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"\'এক হাতে ব্যবহার করার মোড\'-এর ব্যবহার"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"বেরিয়ে আসার জন্য, স্ক্রিনের নিচ থেকে উপরের দিকে সোয়াইপ করুন অথবা অ্যাপ আইকনের উপরে যেকোনও জায়গায় ট্যাপ করুন"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"\'এক হাতে ব্যবহার করার মোড\' শুরু করুন"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এখনও সমাধান হয়নি?\nরিভার্ট করার জন্য ট্যাপ করুন"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ক্যামেরা সংক্রান্ত সমস্যা নেই? বাতিল করতে ট্যাপ করুন।"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"দেখুন ও আরও অনেক কিছু করুন"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"স্প্লিট স্ক্রিনের জন্য অন্য অ্যাপে টেনে আনুন"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"স্প্লিট স্ক্রিনের ক্ষেত্রে অন্য কোনও অ্যাপ টেনে আনুন"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"কোনও অ্যাপের স্থান পরিবর্তন করতে তার বাইরে ডবল ট্যাপ করুন"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুঝেছি"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"আরও তথ্যের জন্য বড় করুন।"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"বাতিল করুন"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"রিস্টার্ট করুন"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"আর দেখতে চাই না"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"এই অ্যাপ সরাতে\nডবল ট্যাপ করুন"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"বড় করুন"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ছোট করুন"</string>
<string name="close_button_text" msgid="2913281996024033299">"বন্ধ করুন"</string>
<string name="back_button_text" msgid="1469718707134137085">"ফিরে যান"</string>
<string name="handle_text" msgid="1766582106752184456">"হাতল"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"অ্যাপ আইকন"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ফুলস্ক্রিন"</string>
<string name="desktop_text" msgid="1077633567027630454">"ডেস্কটপ মোড"</string>
<string name="split_screen_text" msgid="1396336058129570886">"স্প্লিট স্ক্রিন"</string>
<string name="more_button_text" msgid="3655388105592893530">"আরও"</string>
<string name="float_button_text" msgid="9221657008391364581">"ফ্লোট"</string>
+ <string name="select_text" msgid="5139083974039906583">"বেছে নিন"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"স্ক্রিনশট"</string>
+ <string name="close_text" msgid="4986518933445178928">"বন্ধ করুন"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"\'মেনু\' বন্ধ করুন"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"মেনু খুলুন"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index dd2f871c5ebb..b39b497f5c66 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stavljanje u stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vađenje iz stasha"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi na podijeljenom ekranu."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava dijeljenje ekrana."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Aplikacija možda neće funkcionirati na podijeljenom ekranu"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikacija ne podržava podijeljeni ekran"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ova aplikacija se može otvoriti samo u 1 prozoru."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće raditi na sekundarnom ekranu."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Razdjelnik podijeljenog ekrana"</string>
- <string name="divider_title" msgid="5482989479865361192">"Razdjelnik podijeljenog ekrana"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Razdjelnik podijeljenog ekrana"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Razdjelnik podijeljenog ekrana"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lijevo cijeli ekran"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Lijevo 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevo 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gore 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gore 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Donji ekran kao cijeli ekran"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Podjela ulijevo"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Podjela udesno"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Podjela nagore"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Podjela nadolje"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Korištenje načina rada jednom rukom"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Da izađete, prevucite s dna ekrana prema gore ili dodirnite bilo gdje iznad aplikacije"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Započinjanje načina rada jednom rukom"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nije popravljeno?\nDodirnite da vratite"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nema problema s kamerom? Dodirnite da odbacite."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Pogledajte i učinite više"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Prevucite još jednu aplikaciju za podijeljeni ekran"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Prevucite još jednu aplikaciju za podijeljeni ekran"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da promijenite njen položaj"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Razumijem"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za više informacija."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Otkaži"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Ponovo pokreni"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovo"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dodirnite dvaput da\npomjerite aplikaciju"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziranje"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimiziranje"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zatvaranje"</string>
<string name="back_button_text" msgid="1469718707134137085">"Nazad"</string>
<string name="handle_text" msgid="1766582106752184456">"Identifikator"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Cijeli ekran"</string>
<string name="desktop_text" msgid="1077633567027630454">"Način rada radne površine"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Podijeljeni ekran"</string>
<string name="more_button_text" msgid="3655388105592893530">"Više"</string>
<string name="float_button_text" msgid="9221657008391364581">"Lebdeći"</string>
+ <string name="select_text" msgid="5139083974039906583">"Odabir"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string>
+ <string name="close_text" msgid="4986518933445178928">"Zatvaranje"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Otvaranje menija"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 937e0d9d4b3f..fe76e73135c9 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Canvia la mida"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Amaga"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Deixa d\'amagar"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"És possible que l\'aplicació no funcioni amb la pantalla dividida."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'aplicació no admet la pantalla dividida."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"És possible que l\'aplicació no funcioni amb la pantalla dividida"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"L\'aplicació no admet la pantalla dividida"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aquesta aplicació només pot obrir-se en 1 finestra."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"És possible que l\'aplicació no funcioni en una pantalla secundària."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'aplicació no es pot obrir en pantalles secundàries."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalles"</string>
- <string name="divider_title" msgid="5482989479865361192">"Separador de pantalla dividida"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Separador de pantalla dividida"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Separador de pantalla dividida"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla esquerra completa"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Pantalla esquerra al 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pantalla esquerra al 50%"</string>
@@ -49,20 +49,16 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Pantalla superior al 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Pantalla superior al 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Divideix a l\'esquerra"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Divideix a la dreta"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Divideix a la part superior"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Divideix a la part inferior"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"S\'està utilitzant el mode d\'una mà"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Per sortir, llisca cap amunt des de la part inferior de la pantalla o toca qualsevol lloc a sobre de l\'aplicació"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Inicia el mode d\'una mà"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Surt del mode d\'una mà"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"Configuració de les bombolles: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú addicional"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú de desbordament"</string>
<string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Torna a afegir a la pila"</string>
<string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>) i <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> més"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"El problema no s\'ha resolt?\nToca per desfer els canvis"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No tens cap problema amb la càmera? Toca per ignorar."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta i fes més coses"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrossega una altra aplicació per utilitzar la pantalla dividida"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrossega una altra aplicació per utilitzar la pantalla dividida"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Fes doble toc fora d\'una aplicació per canviar-ne la posició"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entesos"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Desplega per obtenir més informació."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel·la"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Reinicia"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No ho tornis a mostrar"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Fes doble toc per\nmoure aquesta aplicació"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximitza"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimitza"</string>
<string name="close_button_text" msgid="2913281996024033299">"Tanca"</string>
<string name="back_button_text" msgid="1469718707134137085">"Enrere"</string>
<string name="handle_text" msgid="1766582106752184456">"Ansa"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Icona de l\'aplicació"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string>
<string name="desktop_text" msgid="1077633567027630454">"Mode d\'escriptori"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Més"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flotant"</string>
+ <string name="select_text" msgid="5139083974039906583">"Selecciona"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
+ <string name="close_text" msgid="4986518933445178928">"Tanca"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Obre el menú"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index a35889546ec9..ac22b8569e16 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Změnit velikost"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Uložit"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušit uložení"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikace v režimu rozdělené obrazovky nemusí fungovat."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikace nepodporuje režim rozdělené obrazovky."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Aplikace v režimu rozdělené obrazovky nemusí fungovat"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikace nepodporuje režim rozdělené obrazovky"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Tuto aplikaci lze otevřít jen na jednom okně."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikace na sekundárním displeji nemusí fungovat."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikace nepodporuje spuštění na sekundárních displejích."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Čára rozdělující obrazovku"</string>
- <string name="divider_title" msgid="5482989479865361192">"Čára rozdělující obrazovku"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Čára rozdělující obrazovku"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Čára rozdělující obrazovku"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Levá část na celou obrazovku"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % vlevo"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % vlevo"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % nahoře"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % nahoře"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Dolní část na celou obrazovku"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Rozdělit vlevo"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Rozdělit vpravo"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Rozdělit nahoře"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Rozdělit dole"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Používání režimu jedné ruky"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Režim ukončíte, když přejedete prstem z dolní části obrazovky nahoru nebo klepnete kamkoli nad aplikaci"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Spustit režim jedné ruky"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovat"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina byla zavřena."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Klepnutím tuto aplikaci kvůli lepšímu zobrazení restartujete."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Pokud je problém se zobrazením aplikace, klepněte na ni a restartujte ji."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s fotoaparátem?\nKlepnutím vyřešíte"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepomohlo to?\nKlepnutím se vrátíte"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Žádné problémy s fotoaparátem? Klepnutím zavřete."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lepší zobrazení a více možností"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Přetáhnutím druhé aplikace použijete rozdělenou obrazovku"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Přetáhnutím druhé aplikace použijete rozdělenou obrazovku"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikaci změníte její umístění"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozbalením zobrazíte další informace."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Zrušit"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartovat"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Tuto zprávu příště nezobrazovat"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvojitým klepnutím\npřesunete aplikaci"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovat"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimalizovat"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zavřít"</string>
<string name="back_button_text" msgid="1469718707134137085">"Zpět"</string>
<string name="handle_text" msgid="1766582106752184456">"Úchyt"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikace"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Celá obrazovka"</string>
<string name="desktop_text" msgid="1077633567027630454">"Režim počítače"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Rozdělená obrazovka"</string>
<string name="more_button_text" msgid="3655388105592893530">"Více"</string>
<string name="float_button_text" msgid="9221657008391364581">"Plovoucí"</string>
+ <string name="select_text" msgid="5139083974039906583">"Vybrat"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Snímek obrazovky"</string>
+ <string name="close_text" msgid="4986518933445178928">"Zavřít"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Otevřít nabídku"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 7a40efd0382c..c91cd7a956aa 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Rediger størrelse"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Skjul"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vis"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Appen fungerer muligvis ikke i opdelt skærm."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen understøtter ikke opdelt skærm."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Appen fungerer muligvis ikke i opdelt skærm"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Appen understøtter ikke opdelt skærm"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Denne app kan kun åbnes i 1 vindue."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer muligvis ikke på sekundære skærme."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke åbnes på sekundære skærme."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Adskiller til opdelt skærm"</string>
- <string name="divider_title" msgid="5482989479865361192">"Adskiller til opdelt skærm"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Adskiller til opdelt skærm"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Adskiller til opdelt skærm"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vis venstre del i fuld skærm"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Venstre 70 %"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Venstre 50 %"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Øverste 50 %"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Øverste 30 %"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Vis nederste del i fuld skærm"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Vis i venstre side"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Vis i højre side"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Vis øverst"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Vis nederst"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Brug af enhåndstilstand"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Du kan afslutte ved at stryge opad fra bunden af skærmen eller trykke et vilkårligt sted over appen"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Start enhåndstilstand"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Løste det ikke problemet?\nTryk for at fortryde"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen problemer med dit kamera? Tryk for at afvise."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gør mere"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Træk en anden app hertil for at bruge opdelt skærm"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Træk en anden app hertil for at bruge opdelt skærm"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryk to gange uden for en app for at justere dens placering"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Udvid for at få flere oplysninger."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuller"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Genstart"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Vis ikke igen"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tryk to gange\nfor at flytte appen"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimér"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string>
<string name="close_button_text" msgid="2913281996024033299">"Luk"</string>
<string name="back_button_text" msgid="1469718707134137085">"Tilbage"</string>
<string name="handle_text" msgid="1766582106752184456">"Håndtag"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Fuld skærm"</string>
<string name="desktop_text" msgid="1077633567027630454">"Computertilstand"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Opdelt skærm"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mere"</string>
<string name="float_button_text" msgid="9221657008391364581">"Svævende"</string>
+ <string name="select_text" msgid="5139083974039906583">"Vælg"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Luk"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Åbn menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 8f6275209280..c17f97fbad0f 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -20,7 +20,7 @@
<string name="pip_phone_close" msgid="5783752637260411309">"Schließen"</string>
<string name="pip_phone_expand" msgid="2579292903468287504">"Maximieren"</string>
<string name="pip_phone_settings" msgid="5468987116750491918">"Einstellungen"</string>
- <string name="pip_phone_enter_split" msgid="7042877263880641911">"„Geteilter Bildschirm“ aktivieren"</string>
+ <string name="pip_phone_enter_split" msgid="7042877263880641911">"Splitscreen aktivieren"</string>
<string name="pip_menu_title" msgid="5393619322111827096">"Menü"</string>
<string name="pip_menu_accessibility_title" msgid="8129016817688656249">"Menü „Bild im Bild“"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ist in Bild im Bild"</string>
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Größe anpassen"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"In Stash legen"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Aus Stash entfernen"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Die App funktioniert unter Umständen im Modus für geteilten Bildschirm nicht."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Die App funktioniert im Splitscreen-Modus unter Umständen nicht"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Splitscreen wird in dieser App nicht unterstützt"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Diese App kann nur in einem einzigen Fenster geöffnet werden."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Die App funktioniert auf einem sekundären Display möglicherweise nicht."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Die App unterstützt den Start auf sekundären Displays nicht."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Bildschirmteiler"</string>
- <string name="divider_title" msgid="5482989479865361192">"Bildschirmteiler"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Bildschirmteiler"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Bildschirmteiler"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vollbild links"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % links"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % links"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % oben"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % oben"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Vollbild unten"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Links teilen"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Rechts teilen"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Oben teilen"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Unten teilen"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Einhandmodus wird verwendet"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Wenn du die App schließen möchtest, wische vom unteren Rand des Displays nach oben oder tippe auf eine beliebige Stelle oberhalb der App"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Einhandmodus starten"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Das Problem ist nicht behoben?\nZum Rückgängigmachen tippen."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Keine Probleme mit der Kamera? Zum Schließen tippen."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Mehr sehen und erledigen"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Weitere App hineinziehen, um den Bildschirm zu teilen"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Für Splitscreen-Modus weitere App hineinziehen"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Außerhalb einer App doppeltippen, um die Position zu ändern"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ok"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Für weitere Informationen maximieren."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Abbrechen"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Neu starten"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nicht mehr anzeigen"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Zum Verschieben\ndoppeltippen"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximieren"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimieren"</string>
<string name="close_button_text" msgid="2913281996024033299">"Schließen"</string>
<string name="back_button_text" msgid="1469718707134137085">"Zurück"</string>
<string name="handle_text" msgid="1766582106752184456">"Ziehpunkt"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"App-Symbol"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Vollbild"</string>
<string name="desktop_text" msgid="1077633567027630454">"Desktopmodus"</string>
- <string name="split_screen_text" msgid="1396336058129570886">"Geteilter Bildschirm"</string>
+ <string name="split_screen_text" msgid="1396336058129570886">"Splitscreen"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mehr"</string>
<string name="float_button_text" msgid="9221657008391364581">"Frei schwebend"</string>
+ <string name="select_text" msgid="5139083974039906583">"Auswählen"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Schließen"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Menü schließen"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Menü öffnen"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 8d0faebf269d..ab5c44e9e07f 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Αλλαγή μεγέθους"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Απόκρυψη"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Κατάργηση απόκρυψης"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Η εφαρμογή ενδέχεται να μην λειτουργεί με διαχωρισμό οθόνης."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Η εφαρμογή ενδέχεται να μην λειτουργεί με διαχωρισμό οθόνης."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Αυτή η εφαρμογή μπορεί να ανοιχθεί μόνο σε 1 παράθυρο."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Η εφαρμογή ίσως να μην λειτουργήσει σε δευτερεύουσα οθόνη."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Η εφαρμογή δεν υποστηρίζει την εκκίνηση σε δευτερεύουσες οθόνες."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Διαχωριστικό οθόνης"</string>
- <string name="divider_title" msgid="5482989479865361192">"Διαχωριστικό οθόνης"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Διαχωριστικό οθόνης"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Διαχωριστικό οθόνης"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Αριστερή πλήρης οθόνη"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Αριστερή 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Αριστερή 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Πάνω 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Πάνω 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Κάτω πλήρης οθόνη"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Διαχωρισμός αριστερά"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Διαχωρισμός δεξιά"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Διαχωρισμός επάνω"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Διαχωρισμός κάτω"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Χρήση λειτουργίας ενός χεριού"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Για έξοδο, σύρετε προς τα πάνω από το κάτω μέρος της οθόνης ή πατήστε οπουδήποτε πάνω από την εφαρμογή."</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Έναρξη λειτουργίας ενός χεριού"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Δεν διορθώθηκε;\nΠατήστε για επαναφορά."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Δεν αντιμετωπίζετε προβλήματα με την κάμερα; Πατήστε για παράβλεψη."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Δείτε και κάντε περισσότερα"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Σύρετε σε μια άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Σύρετε σε μια άλλη εφαρμογή για διαχωρισμό οθόνης."</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Πατήστε δύο φορές έξω από μια εφαρμογή για να αλλάξετε τη θέση της"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Το κατάλαβα"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ανάπτυξη για περισσότερες πληροφορίες."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Ακύρωση"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Επανεκκίνηση"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Να μην εμφανιστεί ξανά"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Πατήστε δύο φορές για\nμετακίνηση αυτής της εφαρμογής"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Μεγιστοποίηση"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Ελαχιστοποίηση"</string>
<string name="close_button_text" msgid="2913281996024033299">"Κλείσιμο"</string>
<string name="back_button_text" msgid="1469718707134137085">"Πίσω"</string>
<string name="handle_text" msgid="1766582106752184456">"Λαβή"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Εικονίδιο εφαρμογής"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Πλήρης οθόνη"</string>
<string name="desktop_text" msgid="1077633567027630454">"Λειτουργία επιφάνειας εργασίας"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Διαχωρισμός οθόνης"</string>
<string name="more_button_text" msgid="3655388105592893530">"Περισσότερα"</string>
<string name="float_button_text" msgid="9221657008391364581">"Κινούμενο"</string>
+ <string name="select_text" msgid="5139083974039906583">"Επιλογή"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Στιγμιότυπο οθόνης"</string>
+ <string name="close_text" msgid="4986518933445178928">"Κλείσιμο"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Άνοιγμα μενού"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index a108e8930251..ea91014298df 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"App may not work with split screen"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"App does not support split screen"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in one window."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
- <string name="divider_title" msgid="5482989479865361192">"Split screen divider"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
@@ -84,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
@@ -93,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string>
<string name="close_button_text" msgid="2913281996024033299">"Close"</string>
<string name="back_button_text" msgid="1469718707134137085">"Back"</string>
<string name="handle_text" msgid="1766582106752184456">"Handle"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string>
<string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string>
<string name="more_button_text" msgid="3655388105592893530">"More"</string>
<string name="float_button_text" msgid="9221657008391364581">"Float"</string>
+ <string name="select_text" msgid="5139083974039906583">"Select"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Close"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index cfa9abc5bc13..01bdf95da918 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"App may not work with split screen"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"App does not support split screen"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in 1 window."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Split-screen divider"</string>
- <string name="divider_title" msgid="5482989479865361192">"Split-screen divider"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
@@ -84,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
@@ -93,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don’t show again"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximize"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimize"</string>
<string name="close_button_text" msgid="2913281996024033299">"Close"</string>
<string name="back_button_text" msgid="1469718707134137085">"Back"</string>
<string name="handle_text" msgid="1766582106752184456">"Handle"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"App Icon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string>
<string name="desktop_text" msgid="1077633567027630454">"Desktop Mode"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Split Screen"</string>
<string name="more_button_text" msgid="3655388105592893530">"More"</string>
<string name="float_button_text" msgid="9221657008391364581">"Float"</string>
+ <string name="select_text" msgid="5139083974039906583">"Select"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Close"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Open Menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index a108e8930251..ea91014298df 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"App may not work with split screen"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"App does not support split screen"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in one window."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
- <string name="divider_title" msgid="5482989479865361192">"Split screen divider"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
@@ -84,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
@@ -93,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string>
<string name="close_button_text" msgid="2913281996024033299">"Close"</string>
<string name="back_button_text" msgid="1469718707134137085">"Back"</string>
<string name="handle_text" msgid="1766582106752184456">"Handle"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string>
<string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string>
<string name="more_button_text" msgid="3655388105592893530">"More"</string>
<string name="float_button_text" msgid="9221657008391364581">"Float"</string>
+ <string name="select_text" msgid="5139083974039906583">"Select"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Close"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index a108e8930251..ea91014298df 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"App may not work with split screen"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"App does not support split screen"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in one window."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
- <string name="divider_title" msgid="5482989479865361192">"Split screen divider"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
@@ -84,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
@@ -93,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string>
<string name="close_button_text" msgid="2913281996024033299">"Close"</string>
<string name="back_button_text" msgid="1469718707134137085">"Back"</string>
<string name="handle_text" msgid="1766582106752184456">"Handle"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string>
<string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string>
<string name="more_button_text" msgid="3655388105592893530">"More"</string>
<string name="float_button_text" msgid="9221657008391364581">"Float"</string>
+ <string name="select_text" msgid="5139083974039906583">"Select"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Close"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 65af7781ad98..f6dac79d0379 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎Resize‎‏‎‎‏‎"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎Stash‎‏‎‎‏‎"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎Unstash‎‏‎‎‏‎"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎App may not work with split-screen.‎‏‎‎‏‎"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‏‎App does not support split-screen.‎‏‎‎‏‎"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎App may not work with split screen‎‏‎‎‏‎"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎App does not support split screen‎‏‎‎‏‎"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‎‎‏‎This app can only be opened in 1 window.‎‏‎‎‏‎"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎App may not work on a secondary display.‎‏‎‎‏‎"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎App does not support launch on secondary displays.‎‏‎‎‏‎"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎Split-screen divider‎‏‎‎‏‎"</string>
- <string name="divider_title" msgid="5482989479865361192">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‎Split-screen divider‎‏‎‎‏‎"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‎Split screen divider‎‏‎‎‏‎"</string>
+ <string name="divider_title" msgid="1963391955593749442">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎Split screen divider‎‏‎‎‏‎"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‏‏‎‎‏‏‎‎‎‎Left full screen‎‏‎‎‏‎"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎Left 70%‎‏‎‎‏‎"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎Left 50%‎‏‎‎‏‎"</string>
@@ -84,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‏‎Didn’t fix it?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap to revert‎‏‎‎‏‎"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎No camera issues? Tap to dismiss.‎‏‎‎‏‎"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎See and do more‎‏‎‎‏‎"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‎Drag in another app for split-screen‎‏‎‎‏‎"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎Drag in another app for split screen‎‏‎‎‏‎"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‏‎Double-tap outside an app to reposition it‎‏‎‎‏‎"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎Got it‎‏‎‎‏‎"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‎‏‎‏‎‎Expand for more information.‎‏‎‎‏‎"</string>
@@ -93,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎Cancel‎‏‎‎‏‎"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‏‏‏‎‏‎Restart‎‏‎‎‏‎"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‎‎‎‎‎‏‎‎Don’t show again‎‏‎‎‏‎"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‎Double-tap to‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎move this app‎‏‎‎‏‎"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‎Maximize‎‏‎‎‏‎"</string>
<string name="minimize_button_text" msgid="271592547935841753">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎Minimize‎‏‎‎‏‎"</string>
<string name="close_button_text" msgid="2913281996024033299">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎Close‎‏‎‎‏‎"</string>
<string name="back_button_text" msgid="1469718707134137085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎Back‎‏‎‎‏‎"</string>
<string name="handle_text" msgid="1766582106752184456">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‎‎‎Handle‎‏‎‎‏‎"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‏‎App Icon‎‏‎‎‏‎"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎Fullscreen‎‏‎‎‏‎"</string>
<string name="desktop_text" msgid="1077633567027630454">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎Desktop Mode‎‏‎‎‏‎"</string>
<string name="split_screen_text" msgid="1396336058129570886">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‏‎‎Split Screen‎‏‎‎‏‎"</string>
<string name="more_button_text" msgid="3655388105592893530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎More‎‏‎‎‏‎"</string>
<string name="float_button_text" msgid="9221657008391364581">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎Float‎‏‎‎‏‎"</string>
+ <string name="select_text" msgid="5139083974039906583">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎Select‎‏‎‎‏‎"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‎Screenshot‎‏‎‎‏‎"</string>
+ <string name="close_text" msgid="4986518933445178928">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‎Close‎‏‎‎‏‎"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‏‎Close Menu‎‏‎‎‏‎"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎‎Open Menu‎‏‎‎‏‎"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index c26532eb3860..0190ea85a30b 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar el tamaño"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Almacenar de manera segura"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Dejar de almacenar de manera segura"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la app no funcione en el modo de pantalla dividida."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La app no es compatible con la función de pantalla dividida."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Es posible que la app no funcione en el modo de pantalla dividida"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"La app no es compatible con la función de pantalla dividida"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta app solo puede estar abierta en 1 ventana."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la app no funcione en una pantalla secundaria."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La app no puede iniciarse en pantallas secundarias."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalla dividida"</string>
- <string name="divider_title" msgid="5482989479865361192">"Divisor de pantalla dividida"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Divisor de pantalla dividida"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Divisor de pantalla dividida"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla izquierda completa"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Izquierda: 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda: 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior: 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Superior: 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Dividir a la izquierda"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Dividir a la derecha"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Dividir en la parte superior"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Dividir en la parte inferior"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Cómo usar el modo de una mano"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para salir, desliza el dedo hacia arriba desde la parte inferior de la pantalla o presiona cualquier parte arriba de la app"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar el modo de una mano"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se resolvió?\nPresiona para revertir los cambios"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No tienes problemas con la cámara? Presionar para descartar."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Aprovecha más"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrastra otra app para el modo de pantalla dividida"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra otra app para el modo de pantalla dividida"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Presiona dos veces fuera de una app para cambiar su ubicación"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expande para obtener más información."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No volver a mostrar"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Presiona dos veces\npara mover esta app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string>
<string name="back_button_text" msgid="1469718707134137085">"Atrás"</string>
<string name="handle_text" msgid="1766582106752184456">"Controlador"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ícono de la app"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string>
<string name="desktop_text" msgid="1077633567027630454">"Modo de escritorio"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Más"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flotante"</string>
+ <string name="select_text" msgid="5139083974039906583">"Seleccionar"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
+ <string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Abrir el menú"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 58deed555fd9..9c5e0c48f6cb 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Esconder"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"No esconder"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la aplicación no funcione con la pantalla dividida."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La aplicación no admite la pantalla dividida."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Puede que la aplicación no funcione con la pantalla dividida"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"La aplicación no es compatible con la pantalla dividida"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta aplicación solo puede abrirse en una ventana."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la aplicación no funcione en una pantalla secundaria."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La aplicación no se puede abrir en pantallas secundarias."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Dividir la pantalla"</string>
- <string name="divider_title" msgid="5482989479865361192">"Divisor de pantalla dividida"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Divisor de pantalla dividida"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Divisor de pantalla dividida"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla izquierda completa"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Izquierda 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Superior 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Dividir en la parte izquierda"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Dividir en la parte derecha"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Dividir en la parte superior"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Dividir en la parte inferior"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usar modo Una mano"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para salir, desliza el dedo hacia arriba desde la parte inferior de la pantalla o toca cualquier zona que haya encima de la aplicación"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar modo Una mano"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbuja"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbuja cerrada."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Toca para reiniciar esta aplicación y obtener una mejor vista."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Toca para reiniciar esta aplicación y verlo mejor."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Problemas con la cámara?\nToca para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta más información y haz más"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrastra otra aplicación para activar la pantalla dividida"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra otra aplicación para activar la pantalla dividida"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dos veces fuera de una aplicación para cambiarla de posición"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mostrar más información"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No volver a mostrar"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toca dos veces para\nmover esta aplicación"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string>
<string name="back_button_text" msgid="1469718707134137085">"Atrás"</string>
<string name="handle_text" msgid="1766582106752184456">"Controlador"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Icono de la aplicación"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string>
<string name="desktop_text" msgid="1077633567027630454">"Modo Escritorio"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Más"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flotante"</string>
+ <string name="select_text" msgid="5139083974039906583">"Seleccionar"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
+ <string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Abrir menú"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index c0d0588900ad..fb23d11ef74a 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Suuruse muutmine"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Pane hoidlasse"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Eemalda hoidlast"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Rakendus ei pruugi poolitatud ekraaniga töötada."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Rakendus ei toeta jagatud ekraani."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Rakendus ei pruugi jagatud ekraanikuvaga töötada."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Rakendus ei toeta jagatud ekraanikuva."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Selle rakenduse saab avada ainult ühes aknas."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Rakendus ei pruugi teisesel ekraanil töötada."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Rakendus ei toeta teisestel ekraanidel käivitamist."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Ekraanijagaja"</string>
- <string name="divider_title" msgid="5482989479865361192">"Ekraanijagaja"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Jagatud ekraanikuva jaotur"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Jagatud ekraanikuva jaotur"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vasak täisekraan"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vasak: 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasak: 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ülemine: 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Ülemine: 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Alumine täisekraan"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Jaga vasakule"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Jaga paremale"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Jaga üles"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Jaga alla"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Ühekäerežiimi kasutamine"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Väljumiseks pühkige ekraani alaosast üles või puudutage rakenduse kohal olevat ala"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Ühekäerežiimi käivitamine"</string>
@@ -88,23 +84,30 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Kas probleemi ei lahendatud?\nPuudutage ennistamiseks."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kas kaameraprobleeme pole? Puudutage loobumiseks."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vaadake ja tehke rohkem"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Lohistage muusse rakendusse, et jagatud ekraanikuva kasutada"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Lohistage muusse rakendusse, et jagatud ekraanikuva kasutada"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Topeltpuudutage rakendusest väljaspool, et selle asendit muuta"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Selge"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Laiendage lisateabe saamiseks."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Kas taaskäivitada parema vaate saavutamiseks?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Saate rakenduse taaskäivitada, et see näeks ekraanikuval parem välja, kuid võite kaotada edenemise või salvestamata muudatused"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Saate rakenduse taaskäivitada, et see näeks ekraanikuval parem välja, kuid võite kaotada edenemise või salvestamata muudatused."</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Tühista"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Taaskäivita"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ära kuva uuesti"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Rakenduse teisaldamiseks\ntopeltpuudutage"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimeeri"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimeeri"</string>
<string name="close_button_text" msgid="2913281996024033299">"Sule"</string>
<string name="back_button_text" msgid="1469718707134137085">"Tagasi"</string>
<string name="handle_text" msgid="1766582106752184456">"Käepide"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Rakenduse ikoon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Täisekraan"</string>
<string name="desktop_text" msgid="1077633567027630454">"Lauaarvuti režiim"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Jagatud ekraanikuva"</string>
<string name="more_button_text" msgid="3655388105592893530">"Rohkem"</string>
<string name="float_button_text" msgid="9221657008391364581">"Hõljuv"</string>
+ <string name="select_text" msgid="5139083974039906583">"Vali"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Ekraanipilt"</string>
+ <string name="close_text" msgid="4986518933445178928">"Sule"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Ava menüü"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 6a1f45727203..de27a8045e85 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Aldatu tamaina"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Gorde"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ez gorde"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikazioak ez du onartzen pantaila zatitua"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikazioak ez du onartzen pantaila zatitua"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Leiho bakar batean ireki daiteke aplikazioa."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Baliteke aplikazioak ez funtzionatzea bigarren mailako pantailetan."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikazioa ezin da abiarazi bigarren mailako pantailatan."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Pantaila-zatitzailea"</string>
- <string name="divider_title" msgid="5482989479865361192">"Pantaila-zatitzailea"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Pantaila-zatitzailea"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Pantaila-zatitzailea"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ezarri ezkerraldea pantaila osoan"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ezarri ezkerraldea % 70en"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ezarri ezkerraldea % 50en"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ezarri goialdea % 50en"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Ezarri goialdea % 30en"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ezarri behealdea pantaila osoan"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Zatitu ezkerraldean"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Zatitu eskuinaldean"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Zatitu goialdean"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Zatitu behealdean"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Esku bakarreko modua erabiltzea"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Irteteko, pasatu hatza pantailaren behealdetik gora edo sakatu aplikazioaren gainaldea"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Abiarazi esku bakarreko modua"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ez al da konpondu?\nLeheneratzeko, sakatu hau."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ez daukazu arazorik kamerarekin? Baztertzeko, sakatu hau."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ikusi eta egin gauza gehiago"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Pantaila zatituta ikusteko, arrastatu beste aplikazio bat"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Pantaila zatitua ikusteko, arrastatu beste aplikazio bat"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Aplikazioaren posizioa aldatzeko, sakatu birritan haren kanpoaldea"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ados"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Informazio gehiago lortzeko, zabaldu hau."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Utzi"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Berrabiarazi"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ez erakutsi berriro"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Sakatu birritan\naplikazioa mugitzeko"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizatu"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizatu"</string>
<string name="close_button_text" msgid="2913281996024033299">"Itxi"</string>
<string name="back_button_text" msgid="1469718707134137085">"Atzera"</string>
<string name="handle_text" msgid="1766582106752184456">"Kontu-izena"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Aplikazioaren ikonoa"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pantaila osoa"</string>
<string name="desktop_text" msgid="1077633567027630454">"Ordenagailuetarako modua"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Pantaila zatitua"</string>
<string name="more_button_text" msgid="3655388105592893530">"Gehiago"</string>
<string name="float_button_text" msgid="9221657008391364581">"Leiho gainerakorra"</string>
+ <string name="select_text" msgid="5139083974039906583">"Hautatu"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Pantaila-argazkia"</string>
+ <string name="close_text" msgid="4986518933445178928">"Itxi"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Ireki menua"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 59c119d18c2d..edff47a0be1a 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغییر اندازه"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"مخفی‌سازی"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"لغو مخفی‌سازی"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن است برنامه با «صفحهٔ دونیمه» کار نکند."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"برنامه از تقسیم صفحه پشتیبانی نمی‌کند."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"ممکن است برنامه با صفحهٔ دونیمه کار نکند"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"برنامه از صفحهٔ دونیمه پشتیبانی نمی‌کند"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"این برنامه فقط در ۱ پنجره می‌تواند باز شود."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن است برنامه در نمایشگر ثانویه کار نکند."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"برنامه از راه‌اندازی در نمایشگرهای ثانویه پشتیبانی نمی‌کند."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"تقسیم‌کننده صفحه"</string>
- <string name="divider_title" msgid="5482989479865361192">"تقسیم‌کننده صفحهٔ دونیمه"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"تقسیم‌کننده صفحهٔ دونیمه"</string>
+ <string name="divider_title" msgid="1963391955593749442">"تقسیم‌کننده صفحهٔ دونیمه"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"تمام‌صفحه چپ"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"٪۷۰ چپ"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"٪۵۰ چپ"</string>
@@ -49,21 +49,17 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"٪۵۰ بالا"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"٪۳۰ بالا"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"تمام‌صفحه پایین"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"تقسیم از چپ"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"تقسیم از راست"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"تقسیم از بالا"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"تقسیم از پایین"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"استفاده از حالت یک‌دستی"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"برای خارج شدن، از پایین صفحه‌نمایش تند به‌طرف بالا بکشید یا در هر جایی از بالای برنامه که می‌خواهید ضربه بزنید"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"آغاز «حالت یک‌دستی»"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"خروج از «حالت یک‌دستی»"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"تنظیمات برای حبابک‌های <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"لبریزشده"</string>
- <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"افزودن برگشت به پشته"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"سرریز"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"افزودن برگشتن به پشته"</string>
<string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g> و <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> مورد بیشتر"</string>
<string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"انتقال به بالا سمت راست"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"مشکل برطرف نشد؟\nبرای برگرداندن ضربه بزنید"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"دوربین مشکلی ندارد؟ برای بستن ضربه بزنید."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"از چندین برنامه به‌طور هم‌زمان استفاده کنید"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"برای حالت صفحهٔ دونیمه، در برنامه‌ای دیگر بکشید"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"برای حالت صفحهٔ دونیمه، در برنامه‌ای دیگر بکشید"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"برای جابه‌جا کردن برنامه، بیرون از آن دوضربه بزنید"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجه‌ام"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"برای اطلاعات بیشتر، گسترده کنید."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"لغو کردن"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"بازراه‌اندازی"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"دوباره نشان داده نشود"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"برای جابه‌جا کردن این برنامه\nدوضربه بزنید"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"بزرگ کردن"</string>
<string name="minimize_button_text" msgid="271592547935841753">"کوچک کردن"</string>
<string name="close_button_text" msgid="2913281996024033299">"بستن"</string>
<string name="back_button_text" msgid="1469718707134137085">"برگشتن"</string>
<string name="handle_text" msgid="1766582106752184456">"دستگیره"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"نماد برنامه"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"تمام‌صفحه"</string>
<string name="desktop_text" msgid="1077633567027630454">"حالت رایانه"</string>
<string name="split_screen_text" msgid="1396336058129570886">"صفحهٔ دونیمه"</string>
<string name="more_button_text" msgid="3655388105592893530">"بیشتر"</string>
<string name="float_button_text" msgid="9221657008391364581">"شناور"</string>
+ <string name="select_text" msgid="5139083974039906583">"انتخاب"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"نماگرفت"</string>
+ <string name="close_text" msgid="4986518933445178928">"بستن"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"باز کردن منو"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index edb1dae1269d..92fa76013134 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Muuta kokoa"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Lisää turvasäilytykseen"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poista turvasäilytyksestä"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Sovellus ei ehkä toimi jaetulla näytöllä."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Sovellus ei tue jaetun näytön tilaa."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Sovellus ei ehkä toimi jaetulla näytöllä"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Sovellus ei tue jaetun näytön tilaa"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Tämän sovelluksen voi avata vain yhdessä ikkunassa."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Sovellus ei ehkä toimi toissijaisella näytöllä."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Sovellus ei tue käynnistämistä toissijaisilla näytöillä."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Näytön jakaja"</string>
- <string name="divider_title" msgid="5482989479865361192">"Näytönjakaja"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Näytönjakaja"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Näytönjakaja"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vasen koko näytölle"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vasen 70 %"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasen 50 %"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yläosa 50 %"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Yläosa 30 %"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Alaosa koko näytölle"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Vasemmalla"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Oikealla"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Ylhäällä"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Alhaalla"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Yhden käden moodin käyttö"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Poistu pyyhkäisemällä ylös näytön alareunasta tai napauttamalla sovelluksen yllä"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Käynnistä yhden käden moodi"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Eikö ongelma ratkennut?\nKumoa napauttamalla"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ei ongelmia kameran kanssa? Hylkää napauttamalla."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Näe ja tee enemmän"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Käytä jaettua näyttöä vetämällä tähän toinen sovellus"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Käytä jaettua näyttöä vetämällä tähän toinen sovellus"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kaksoisnapauta sovelluksen ulkopuolella, jos haluat siirtää sitä"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Katso lisätietoja laajentamalla."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Peru"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Käynnistä uudelleen"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Älä näytä uudelleen"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Kaksoisnapauta, jos\nhaluat siirtää sovellusta"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Suurenna"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Pienennä"</string>
<string name="close_button_text" msgid="2913281996024033299">"Sulje"</string>
<string name="back_button_text" msgid="1469718707134137085">"Takaisin"</string>
<string name="handle_text" msgid="1766582106752184456">"Kahva"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Sovelluskuvake"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Koko näyttö"</string>
<string name="desktop_text" msgid="1077633567027630454">"Työpöytätila"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Jaettu näyttö"</string>
<string name="more_button_text" msgid="3655388105592893530">"Lisää"</string>
<string name="float_button_text" msgid="9221657008391364581">"Kelluva ikkuna"</string>
+ <string name="select_text" msgid="5139083974039906583">"Valitse"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Kuvakaappaus"</string>
+ <string name="close_text" msgid="4986518933445178928">"Sulje"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Avaa valikko"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index ee6e7be45024..6d19e55217f6 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ajouter à la réserve"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Retirer de la réserve"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'application n\'est pas compatible avec l\'écran partagé."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"L\'application peut ne pas fonctionner avec l\'écran partagé"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"L\'application ne prend pas en charge l\'écran partagé"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Cette application ne peut être ouverte que dans une fenêtre."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Séparateur d\'écran partagé"</string>
- <string name="divider_title" msgid="5482989479865361192">"Séparateur d\'écran partagé"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Séparateur d\'écran partagé"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Séparateur d\'écran partagé"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Plein écran à la gauche"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % à la gauche"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % à la gauche"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % dans le haut"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % dans le haut"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Plein écran dans le bas"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Diviser à gauche"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Diviser à droite"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Diviser dans la partie supérieure"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Diviser dans la partie inférieure"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utiliser le mode Une main"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pour quitter, balayez l\'écran du bas vers le haut, ou touchez n\'importe où sur l\'écran en haut de l\'application"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Démarrer le mode Une main"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle ignorée."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Touchez pour redémarrer cette application afin d\'obtenir un meilleur affichage."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Pour obtenir un meilleur affichage, touchez pour redémarrer cette application."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo?\nTouchez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et en faire plus"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Faites glisser une autre application pour utiliser l\'écran partagé"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Faites glisser une autre application pour utiliser l\'écran partagé"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Touchez deux fois à côté d\'une application pour la repositionner"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développer pour en savoir plus."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuler"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toucher deux fois pour\ndéplacer cette application"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fermer"</string>
<string name="back_button_text" msgid="1469718707134137085">"Retour"</string>
<string name="handle_text" msgid="1766582106752184456">"Identifiant"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Icône de l\'application"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Plein écran"</string>
<string name="desktop_text" msgid="1077633567027630454">"Mode Bureau"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Écran partagé"</string>
<string name="more_button_text" msgid="3655388105592893530">"Plus"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flottant"</string>
+ <string name="select_text" msgid="5139083974039906583">"Sélectionner"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Capture d\'écran"</string>
+ <string name="close_text" msgid="4986518933445178928">"Fermer"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Ouvrir le menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index c9fc0613260b..5fb91f7b6948 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Application incompatible avec l\'écran partagé."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"L\'appli peut ne pas fonctionner en mode Écran partagé"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Appli incompatible avec l\'écran partagé"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Cette appli ne peut être ouverte que dans 1 fenêtre."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Séparateur d\'écran partagé"</string>
- <string name="divider_title" msgid="5482989479865361192">"Séparateur d\'écran partagé"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Séparateur d\'écran partagé"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Séparateur d\'écran partagé"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Écran de gauche en plein écran"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Écran de gauche à 70 %"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Écran de gauche à 50 %"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Écran du haut à 50 %"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Écran du haut à 30 %"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Écran du bas en plein écran"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Affichée à gauche"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Affichée à droite"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Affichée en haut"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Affichée en haut"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utiliser le mode une main"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pour quitter, balayez l\'écran de bas en haut ou appuyez n\'importe où au-dessus de l\'application"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Démarrer le mode une main"</string>
@@ -83,28 +79,35 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle fermée."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Appuyez pour redémarrer cette appli et avoir une meilleure vue."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Pour un meilleur affichage, appuyez pour redémarrer cette appli."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo ?\nAppuyez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu ?\nAppuyez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo ? Appuyez pour ignorer."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et interagir plus"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Faites glisser une autre appli pour utiliser l\'écran partagé"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Faites glisser une autre appli pour utiliser l\'écran partagé"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Appuyez deux fois en dehors d\'une appli pour la repositionner"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développez pour obtenir plus d\'informations"</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Redémarrer pour améliorer l\'affichage ?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Vous pouvez redémarrer l\'appli pour en améliorer son aspect sur votre écran, mais vous risquez de perdre votre progression ou les modifications non enregistrées"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Vous pouvez redémarrer l\'appli pour un meilleur rendu sur votre écran, mais il se peut que vous perdiez votre progression ou les modifications non enregistrées"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuler"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Appuyez deux fois\npour déplacer cette appli"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fermer"</string>
<string name="back_button_text" msgid="1469718707134137085">"Retour"</string>
<string name="handle_text" msgid="1766582106752184456">"Poignée"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Icône d\'application"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Plein écran"</string>
<string name="desktop_text" msgid="1077633567027630454">"Mode ordinateur"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Écran partagé"</string>
<string name="more_button_text" msgid="3655388105592893530">"Plus"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flottante"</string>
+ <string name="select_text" msgid="5139083974039906583">"Sélectionner"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Capture d\'écran"</string>
+ <string name="close_text" msgid="4986518933445178928">"Fermer"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Ouvrir le menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 3e1a93fe424e..c08cff86f63c 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Esconder"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Non esconder"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Pode que a aplicación non funcione coa pantalla dividida."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A aplicación non é compatible coa función de pantalla dividida."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"É posible que a aplicación non funcione coa pantalla dividida"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"A aplicación non admite a función de pantalla dividida"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta aplicación só se pode abrir en 1 ventá."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É posible que a aplicación non funcione nunha pantalla secundaria."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"A aplicación non se pode iniciar en pantallas secundarias."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalla dividida"</string>
- <string name="divider_title" msgid="5482989479865361192">"Divisor de pantalla dividida"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Divisor de pantalla dividida"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Divisor de pantalla dividida"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla completa á esquerda"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % á esquerda"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % á esquerda"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % arriba"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % arriba"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla completa abaixo"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Dividir (esquerda)"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Dividir (dereita)"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Dividir (arriba)"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Dividir (abaixo)"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Como se usa o modo dunha soa man?"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para saír, pasa o dedo cara arriba desde a parte inferior da pantalla ou toca calquera lugar da zona situada encima da aplicación"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar modo dunha soa man"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Non se solucionaron os problemas?\nToca para reverter o seu tratamento"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Non hai problemas coa cámara? Tocar para ignorar."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ver e facer máis"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrastra outra aplicación para usar a pantalla dividida"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra outra aplicación para usar a pantalla dividida"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dúas veces fóra da aplicación para cambiala de posición"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Despregar para obter máis información."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Non mostrar outra vez"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toca dúas veces para\nmover esta aplicación"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Pechar"</string>
<string name="back_button_text" msgid="1469718707134137085">"Atrás"</string>
<string name="handle_text" msgid="1766582106752184456">"Controlador"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Icona de aplicación"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string>
<string name="desktop_text" msgid="1077633567027630454">"Modo de escritorio"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Máis"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flotante"</string>
+ <string name="select_text" msgid="5139083974039906583">"Seleccionar"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
+ <string name="close_text" msgid="4986518933445178928">"Pechar"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Pechar o menú"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Abrir menú"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index 24950f760e5a..2a521991ef8d 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"કદ બદલો"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"છુપાવો"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"બતાવો"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"વિભાજિત-સ્ક્રીન સાથે ઍપ કદાચ કામ ન કરે."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ઍપ્લિકેશન સ્ક્રીન-વિભાજનનું સમર્થન કરતી નથી."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"વિભાજિત સ્ક્રીન સાથે ઍપ કદાચ કામ ન કરે"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"ઍપ વિભાજિત સ્ક્રીનને સપોર્ટ કરતી નથી"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"આ ઍપ માત્ર 1 વિન્ડોમાં ખોલી શકાય છે."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર કદાચ કામ ન કરે."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર લૉન્ચનું સમર્થન કરતી નથી."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"સ્પ્લિટ-સ્ક્રીન વિભાજક"</string>
- <string name="divider_title" msgid="5482989479865361192">"સ્ક્રીનને વિભાજિત કરતું વિભાજક"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"સ્ક્રીનને વિભાજિત કરતું વિભાજક"</string>
+ <string name="divider_title" msgid="1963391955593749442">"સ્ક્રીનને વિભાજિત કરતું વિભાજક"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ડાબી પૂર્ણ સ્ક્રીન"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ડાબે 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ડાબે 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"શીર્ષ 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"શીર્ષ 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"તળિયાની પૂર્ણ સ્ક્રીન"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"ડાબે વિભાજિત કરો"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"જમણે વિભાજિત કરો"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"ઉપર વિભાજિત કરો"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"નીચે વિભાજિત કરો"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"એક-હાથે વાપરો મોડનો ઉપયોગ કરી રહ્યાં છીએ"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"બહાર નીકળવા માટે, સ્ક્રીનની નીચેના ભાગથી ઉપરની તરફ સ્વાઇપ કરો અથવા ઍપના આઇકન પર ગમે ત્યાં ટૅપ કરો"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"એક-હાથે વાપરો મોડ શરૂ કરો"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"સુધારો નથી થયો?\nપહેલાંના પર પાછું ફેરવવા માટે ટૅપ કરો"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"કૅમેરામાં કોઈ સમસ્યા નથી? છોડી દેવા માટે ટૅપ કરો."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"જુઓ અને બીજું ઘણું કરો"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"સ્ક્રીન વિભાજન માટે કોઈ અન્ય ઍપમાં ખેંચો"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"વિભાજિત સ્ક્રીન માટે કોઈ અન્ય ઍપમાં ખેંચો"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"કોઈ ઍપની જગ્યા બદલવા માટે, તેની બહાર બે વાર ટૅપ કરો"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"સમજાઈ ગયું"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"વધુ માહિતી માટે મોટું કરો."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"રદ કરો"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"ફરી શરૂ કરો"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ફરીથી બતાવશો નહીં"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"આ ઍપને ખસેડવા માટે\nબે વાર ટૅપ કરો"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"મોટું કરો"</string>
<string name="minimize_button_text" msgid="271592547935841753">"નાનું કરો"</string>
<string name="close_button_text" msgid="2913281996024033299">"બંધ કરો"</string>
<string name="back_button_text" msgid="1469718707134137085">"પાછળ"</string>
<string name="handle_text" msgid="1766582106752184456">"હૅન્ડલ"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ઍપનું આઇકન"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"પૂર્ણસ્ક્રીન"</string>
<string name="desktop_text" msgid="1077633567027630454">"ડેસ્કટૉપ મોડ"</string>
<string name="split_screen_text" msgid="1396336058129570886">"સ્ક્રીનને વિભાજિત કરો"</string>
<string name="more_button_text" msgid="3655388105592893530">"વધુ"</string>
<string name="float_button_text" msgid="9221657008391364581">"ફ્લોટિંગ વિન્ડો"</string>
+ <string name="select_text" msgid="5139083974039906583">"પસંદ કરો"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"સ્ક્રીનશૉટ"</string>
+ <string name="close_text" msgid="4986518933445178928">"બંધ કરો"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"મેનૂ ખોલો"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 9f36799092e1..b0b0e9c6f5bc 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदलें"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"छिपाएं"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"दिखाएं"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"ऐप्लिकेशन शायद स्प्लिट स्क्रीन मोड में काम न करे."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ऐप विभाजित स्‍क्रीन का समर्थन नहीं करता है."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"मुमकिन है कि ऐप्लिकेशन, स्प्लिट स्क्रीन मोड में काम न करे"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"यह ऐप्लिकेशन, स्प्लिट स्क्रीन मोड पर काम नहीं करता"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"इस ऐप्लिकेशन को सिर्फ़ एक विंडो में खोला जा सकता है."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"हो सकता है कि ऐप प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर काम न करे."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर ऐप लॉन्च नहीं किया जा सकता."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"विभाजित स्क्रीन विभाजक"</string>
- <string name="divider_title" msgid="5482989479865361192">"स्प्लिट स्क्रीन डिवाइडर"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"स्प्लिट स्क्रीन डिवाइडर मोड"</string>
+ <string name="divider_title" msgid="1963391955593749442">"स्प्लिट स्क्रीन डिवाइडर मोड"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बाईं स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"बाईं स्क्रीन को 70% बनाएं"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बाईं स्क्रीन को 50% बनाएं"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ऊपर की स्क्रीन को 50% बनाएं"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ऊपर की स्क्रीन को 30% बनाएं"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"नीचे की स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"स्क्रीन को बाएं हिस्से में स्प्लिट करें"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"स्क्रीन को दाएं हिस्से में स्प्लिट करें"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"स्क्रीन को ऊपर के हिस्से में स्प्लिट करें"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"स्क्रीन को सबसे नीचे वाले हिस्से में स्प्लिट करें"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"वन-हैंडेड मोड का इस्तेमाल करना"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"इस मोड से बाहर निकलने के लिए, स्क्रीन के सबसे निचले हिस्से से ऊपर की ओर स्वाइप करें या ऐप्लिकेशन के बाहर कहीं भी टैप करें"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"वन-हैंडेड मोड चालू करें"</string>
@@ -88,23 +84,30 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"क्या समस्या ठीक नहीं हुई?\nपहले जैसा करने के लिए टैप करें"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्या कैमरे से जुड़ी कोई समस्या नहीं है? खारिज करने के लिए टैप करें."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पूरी जानकारी लेकर, बेहतर तरीके से काम करें"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"स्प्लिट स्क्रीन के लिए, दूसरे ऐप्लिकेशन को खींचें और छोड़ें"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"स्प्लिट स्क्रीन का इस्तेमाल करने के लिए, किसी अन्य ऐप्लिकेशन को खींचें और छोड़ें"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"किसी ऐप्लिकेशन की जगह बदलने के लिए, उसके बाहर दो बार टैप करें"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ठीक है"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ज़्यादा जानकारी के लिए बड़ा करें."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"बेहतर व्यू पाने के लिए ऐप्लिकेशन को रीस्टार्ट करना है?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"स्क्रीन पर ऐप्लिकेशन का बेहतर व्यू पाने के लिए उसे रीस्टार्ट करें. हालांकि, आपने जो बदलाव सेव नहीं किए हैं या अब तक जो काम किए हैं उनका डेटा, ऐप्लिकेशन रीस्टार्ट करने पर मिट सकता है"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"स्क्रीन पर ऐप्लिकेशन का बेहतर व्यू पाने के लिए उसे रीस्टार्ट करें. हालांकि, इससे अब तक किया गया काम और सेव न किए गए बदलाव मिट सकते हैं"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"रद्द करें"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"रीस्टार्ट करें"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"फिर से न दिखाएं"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ऐप्लिकेशन की जगह बदलने के लिए\nदो बार टैप करें"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"बड़ा करें"</string>
<string name="minimize_button_text" msgid="271592547935841753">"विंडो छोटी करें"</string>
<string name="close_button_text" msgid="2913281996024033299">"बंद करें"</string>
<string name="back_button_text" msgid="1469718707134137085">"वापस जाएं"</string>
<string name="handle_text" msgid="1766582106752184456">"हैंडल"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ऐप्लिकेशन आइकॉन"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"फ़ुलस्क्रीन"</string>
<string name="desktop_text" msgid="1077633567027630454">"डेस्कटॉप मोड"</string>
<string name="split_screen_text" msgid="1396336058129570886">"स्प्लिट स्क्रीन मोड"</string>
<string name="more_button_text" msgid="3655388105592893530">"ज़्यादा देखें"</string>
<string name="float_button_text" msgid="9221657008391364581">"फ़्लोट"</string>
+ <string name="select_text" msgid="5139083974039906583">"चुनें"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"स्क्रीनशॉट"</string>
+ <string name="close_text" msgid="4986518933445178928">"बंद करें"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"मेन्यू खोलें"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
index 595435bcf8b8..e2f272c36329 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
@@ -18,7 +18,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"पिक्चर में पिक्चर"</string>
- <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(कोई शीर्षक कार्यक्रम नहीं)"</string>
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(कोई टाइटल कार्यक्रम नहीं)"</string>
<string name="pip_close" msgid="2955969519031223530">"बंद करें"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"फ़ुल स्‍क्रीन"</string>
<string name="pip_move" msgid="158770205886688553">"ले जाएं"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 9459e4c5f2af..08721f0e6746 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Sakrijte"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poništite sakrivanje"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće funkcionirati s podijeljenim zaslonom."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podijeljeni zaslon."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Aplikacija možda neće funkcionirati s podijeljenim zaslonom"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikacija ne podržava podijeljeni zaslon"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ova se aplikacija može otvoriti samo u jednom prozoru."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionirati na sekundarnom zaslonu."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim zaslonima."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Razdjelnik podijeljenog zaslona"</string>
- <string name="divider_title" msgid="5482989479865361192">"Razdjelnik podijeljenog zaslona"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Razdjelnik podijeljenog zaslona"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Razdjelnik podijeljenog zaslona"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lijevi zaslon u cijeli zaslon"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Lijevi zaslon na 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevi zaslon na 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gornji zaslon na 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gornji zaslon na 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Donji zaslon u cijeli zaslon"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Podijeli lijevo"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Podijeli desno"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Podijeli gore"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Podijeli dolje"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Korištenje načina rada jednom rukom"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Za izlaz prijeđite prstom od dna zaslona prema gore ili dodirnite bio gdje iznad aplikacije"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Pokretanje načina rada jednom rukom"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić odbačen."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Dodirnite da biste ponovo pokrenuli tu aplikaciju kako biste bolje vidjeli."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Dodirnite za ponovno pokretanje te aplikacije i bolji prikaz."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s fotoaparatom?\nDodirnite za popravak"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije riješen?\nDodirnite za vraćanje"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema s fotoaparatom? Dodirnite za odbacivanje."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Gledajte i učinite više"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Povucite drugu aplikaciju unutra da biste podijelili zaslon"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Povucite drugu aplikaciju unutra da biste podijelili zaslon"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste je premjestili"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Shvaćam"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite da biste saznali više."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Odustani"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Pokreni ponovno"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovno"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvaput dodirnite da biste\npremjestili ovu aplikaciju"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziraj"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimiziraj"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zatvori"</string>
<string name="back_button_text" msgid="1469718707134137085">"Natrag"</string>
<string name="handle_text" msgid="1766582106752184456">"Pokazivač"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Puni zaslon"</string>
<string name="desktop_text" msgid="1077633567027630454">"Stolni način rada"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Razdvojeni zaslon"</string>
<string name="more_button_text" msgid="3655388105592893530">"Više"</string>
<string name="float_button_text" msgid="9221657008391364581">"Plutajući"</string>
+ <string name="select_text" msgid="5139083974039906583">"Odaberite"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Snimka zaslona"</string>
+ <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Otvaranje izbornika"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index fc9341b82c36..7566439ec7f8 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Átméretezés"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Félretevés"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Félretevés megszüntetése"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Lehet, hogy az alkalmazás nem működik osztott képernyős nézetben."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Az alkalmazás nem támogatja az osztott képernyős nézetet."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Lehet, hogy az alkalmazás nem működik osztott képernyős nézetben"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Az alkalmazás nem támogatja az osztott képernyőt"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ez az alkalmazás csak egy ablakban nyitható meg."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Előfordulhat, hogy az alkalmazás nem működik másodlagos kijelzőn."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Az alkalmazást nem lehet másodlagos kijelzőn elindítani."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Elválasztó az osztott nézetben"</string>
- <string name="divider_title" msgid="5482989479865361192">"Elválasztó az osztott nézetben"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Elválasztó az osztott képernyős nézetben"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Elválasztó az osztott képernyős nézetben"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Bal oldali teljes képernyőre"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Bal oldali 70%-ra"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Bal oldali 50%-ra"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Felső 50%-ra"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Felső 30%-ra"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Alsó teljes képernyőre"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Osztás a képernyő bal oldalán"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Osztás a képernyő jobb oldalán"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Osztás a képernyő tetején"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Osztás alul"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Egykezes mód használata"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"A kilépéshez csúsztasson felfelé a képernyő aljáról, vagy koppintson az alkalmazás felett a képernyő bármelyik részére"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Egykezes mód indítása"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nem sikerült a hiba kijavítása?\nKoppintson a visszaállításhoz."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nincsenek problémái kamerával? Koppintson az elvetéshez."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Több mindent láthat és tehet"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Húzzon ide egy másik alkalmazást az osztott képernyő használatához"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Húzzon ide egy másik alkalmazást az osztott képernyő használatához"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Koppintson duplán az alkalmazáson kívül az áthelyezéséhez"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Értem"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kibontással további információkhoz juthat."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Mégse"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Újraindítás"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne jelenjen meg többé"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Koppintson duplán\naz alkalmazás áthelyezéséhez"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Teljes méret"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Kis méret"</string>
<string name="close_button_text" msgid="2913281996024033299">"Bezárás"</string>
<string name="back_button_text" msgid="1469718707134137085">"Vissza"</string>
<string name="handle_text" msgid="1766582106752184456">"Fogópont"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Alkalmazásikon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Teljes képernyő"</string>
<string name="desktop_text" msgid="1077633567027630454">"Asztali üzemmód"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Osztott képernyő"</string>
<string name="more_button_text" msgid="3655388105592893530">"Továbbiak"</string>
<string name="float_button_text" msgid="9221657008391364581">"Lebegő"</string>
+ <string name="select_text" msgid="5139083974039906583">"Kiválasztás"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Képernyőkép"</string>
+ <string name="close_text" msgid="4986518933445178928">"Bezárás"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Menü bezárása"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Menü megnyitása"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 6943532c17be..2b20870b1048 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Փոխել չափը"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Թաքցնել"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ցուցադրել"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Հավելվածը չի կարող աշխատել տրոհված էկրանի ռեժիմում։"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Հավելվածը չի աջակցում էկրանի տրոհումը:"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Հավելվածը չի կարող աշխատել տրոհված էկրանի ռեժիմում"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Հավելվածը չի աջակցում էկրանի տրոհումը"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Այս հավելվածը հնարավոր է բացել միայն մեկ պատուհանում։"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Հավելվածը կարող է չաշխատել լրացուցիչ էկրանի վրա"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Հավելվածը չի աջակցում գործարկումը լրացուցիչ էկրանների վրա"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Տրոհված էկրանի բաժանիչ"</string>
- <string name="divider_title" msgid="5482989479865361192">"Տրոհված էկրանի բաժանիչ"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Տրոհված էկրանի բաժանիչ"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Տրոհված էկրանի բաժանիչ"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ձախ էկրանը՝ լիաէկրան"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ձախ էկրանը՝ 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ձախ էկրանը՝ 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Վերևի էկրանը՝ 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Վերևի էկրանը՝ 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ներքևի էկրանը՝ լիաէկրան"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Հավելվածը ձախ կողմում"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Հավելվածը աջ կողմում"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Հավելվածը վերևում"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Հավելվածը ներքևում"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Ինչպես օգտվել մեկ ձեռքի ռեժիմից"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Դուրս գալու համար մատը սահեցրեք էկրանի ներքևից վերև կամ հպեք հավելվածի վերևում որևէ տեղ։"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Գործարկել մեկ ձեռքի ռեժիմը"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Չհաջողվե՞ց շտկել։\nՀպեք՝ փոփոխությունները չեղարկելու համար։"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Տեսախցիկի հետ կապված խնդիրներ չկա՞ն։ Փակելու համար հպեք։"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Միաժամանակ կատարեք մի քանի առաջադրանք"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Քաշեք մյուս հավելվածի մեջ՝ էկրանի տրոհումն օգտագործելու համար"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Քաշեք մյուս հավելվածի մեջ՝ էկրանի տրոհումն օգտագործելու համար"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Կրկնակի հպեք հավելվածի կողքին՝ այն տեղափոխելու համար"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Եղավ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ծավալեք՝ ավելին իմանալու համար։"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Չեղարկել"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Վերագործարկել"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Այլևս ցույց չտալ"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Կրկնակի հպեք՝\nհավելվածը տեղափոխելու համար"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Ծավալել"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Ծալել"</string>
<string name="close_button_text" msgid="2913281996024033299">"Փակել"</string>
<string name="back_button_text" msgid="1469718707134137085">"Հետ"</string>
<string name="handle_text" msgid="1766582106752184456">"Նշիչ"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Հավելվածի պատկերակ"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Լիաէկրան"</string>
<string name="desktop_text" msgid="1077633567027630454">"Համակարգչի ռեժիմ"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Տրոհված էկրան"</string>
<string name="more_button_text" msgid="3655388105592893530">"Ավելին"</string>
<string name="float_button_text" msgid="9221657008391364581">"Լողացող պատուհան"</string>
+ <string name="select_text" msgid="5139083974039906583">"Ընտրել"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Սքրինշոթ"</string>
+ <string name="close_text" msgid="4986518933445178928">"Փակել"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Բացել ընտրացանկը"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 4fca32dfc812..3f6d9c551aa6 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah ukuran"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Batalkan stash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikasi mungkin tidak berfungsi dengan layar terpisah."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App tidak mendukung layar terpisah."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Aplikasi mungkin tidak berfungsi dengan layar terpisah"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikasi tidak mendukung layar terpisah"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aplikasi ini hanya dapat dibuka di 1 jendela."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikasi mungkin tidak berfungsi pada layar sekunder."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikasi tidak mendukung peluncuran pada layar sekunder."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Pembagi layar terpisah"</string>
- <string name="divider_title" msgid="5482989479865361192">"Pembagi layar terpisah"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Pembagi layar terpisah"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Pembagi layar terpisah"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Layar penuh di kiri"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kiri 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Atas 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Layar penuh di bawah"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Pisahkan ke kiri"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Pisahkan ke kanan"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Pisahkan ke atas"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Pisahkan ke bawah"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Menggunakan mode satu tangan"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Untuk keluar, geser layar dari bawah ke atas atau ketuk di mana saja di atas aplikasi"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Mulai mode satu tangan"</string>
@@ -88,23 +84,30 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tidak dapat diperbaiki?\nKetuk untuk mengembalikan"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tidak ada masalah kamera? Ketuk untuk menutup."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih banyak hal"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Tarik aplikasi lain untuk menggunakan layar terpisah"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Tarik aplikasi lain untuk menggunakan layar terpisah"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketuk dua kali di luar aplikasi untuk mengubah posisinya"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Oke"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Luaskan untuk melihat informasi selengkapnya."</string>
- <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Mulai ulang untuk tampilan yang lebih baik?"</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Mulai ulang untuk melihat tampilan yang lebih baik?"</string>
<string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Anda dapat memulai ulang aplikasi agar terlihat lebih baik di layar, tetapi Anda mungkin kehilangan progres atau perubahan yang belum disimpan"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Batal"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Mulai ulang"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Jangan tampilkan lagi"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ketuk dua kali untuk\nmemindahkan aplikasi ini"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimalkan"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimalkan"</string>
<string name="close_button_text" msgid="2913281996024033299">"Tutup"</string>
<string name="back_button_text" msgid="1469718707134137085">"Kembali"</string>
<string name="handle_text" msgid="1766582106752184456">"Tuas"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikon Aplikasi"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Layar Penuh"</string>
<string name="desktop_text" msgid="1077633567027630454">"Mode Desktop"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Layar Terpisah"</string>
<string name="more_button_text" msgid="3655388105592893530">"Lainnya"</string>
<string name="float_button_text" msgid="9221657008391364581">"Mengambang"</string>
+ <string name="select_text" msgid="5139083974039906583">"Pilih"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Tutup"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Buka Menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 1bc019e7f67e..20c16be3eaca 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Breyta stærð"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Geymsla"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Taka úr geymslu"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Hugsanlega virkar forritið ekki með skjáskiptingu."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Forritið styður ekki að skjánum sé skipt."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Forritið virkar hugsanlega ekki með skjáskiptingu"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Forritið styður ekki skjáskiptingu"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aðeins er hægt að opna þetta forrit í 1 glugga."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Hugsanlegt er að forritið virki ekki á öðrum skjá."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Forrit styður ekki opnun á öðrum skjá."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Skjáskipting"</string>
- <string name="divider_title" msgid="5482989479865361192">"Skjáskipting"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Skilrúm skjáskiptingar"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Skilrúm skjáskiptingar"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vinstri á öllum skjánum"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vinstri 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vinstri 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Efri 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Efri 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Neðri á öllum skjánum"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Skipta vinstra megin"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Skipta hægra megin"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Skipta efst"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Skipta neðst"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Notkun einhentrar stillingar"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Til að loka skaltu strjúka upp frá neðri hluta skjásins eða ýta hvar sem er fyrir ofan forritið"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Ræsa einhenta stillingu"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Blaðra"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Stjórna"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Blöðru lokað."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Ýta til að endurræsa forritið og fá betri sýn."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Ýttu til að endurræsa forritið og fá betri sýn."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Myndavélavesen?\nÝttu til að breyta stærð"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ennþá vesen?\nÝttu til að afturkalla"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ekkert myndavélavesen? Ýttu til að hunsa."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sjáðu og gerðu meira"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Dragðu annað forrit inn til að nota skjáskiptingu"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Dragðu annað forrit inn til að nota skjáskiptingu"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ýttu tvisvar utan við forrit til að færa það"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ég skil"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Stækka til að sjá frekari upplýsingar."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Hætta við"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Endurræsa"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ekki sýna þetta aftur"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ýttu tvisvar til\nað færa þetta forrit"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Stækka"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minnka"</string>
<string name="close_button_text" msgid="2913281996024033299">"Loka"</string>
<string name="back_button_text" msgid="1469718707134137085">"Til baka"</string>
<string name="handle_text" msgid="1766582106752184456">"Handfang"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Tákn forrits"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Allur skjárinn"</string>
<string name="desktop_text" msgid="1077633567027630454">"Skjáborðsstilling"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Skjáskipting"</string>
<string name="more_button_text" msgid="3655388105592893530">"Meira"</string>
<string name="float_button_text" msgid="9221657008391364581">"Reikult"</string>
+ <string name="select_text" msgid="5139083974039906583">"Velja"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Skjámynd"</string>
+ <string name="close_text" msgid="4986518933445178928">"Loka"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Opna valmynd"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 8d2715a181de..025646cbb9cd 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ridimensiona"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Accantona"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Annulla accantonamento"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"L\'app potrebbe non funzionare con lo schermo diviso."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'app non supporta la modalità Schermo diviso."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"L\'app potrebbe non funzionare con lo schermo diviso"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"L\'app non supporta la modalità schermo diviso"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Questa app può essere aperta soltanto in 1 finestra."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"L\'app potrebbe non funzionare su un display secondario."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'app non supporta l\'avvio su display secondari."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Strumento per schermo diviso"</string>
- <string name="divider_title" msgid="5482989479865361192">"Strumento per schermo diviso"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Strumento per schermo diviso"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Strumento per schermo diviso"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Schermata sinistra a schermo intero"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Schermata sinistra al 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Schermata sinistra al 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Schermata superiore al 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Schermata superiore al 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Schermata inferiore a schermo intero"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Dividi a sinistra"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Dividi a destra"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Dividi in alto"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Dividi in basso"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usare la modalità a una mano"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Per uscire, scorri verso l\'alto dalla parte inferiore dello schermo oppure tocca un punto qualsiasi sopra l\'app"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Avvia la modalità a una mano"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Il problema non si è risolto?\nTocca per ripristinare"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nessun problema con la fotocamera? Tocca per ignorare."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Visualizza più contenuti e fai di più"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Trascina in un\'altra app per usare lo schermo diviso"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Trascina in un\'altra app per usare lo schermo diviso"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tocca due volte fuori da un\'app per riposizionarla"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Espandi per avere ulteriori informazioni."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annulla"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Riavvia"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Non mostrare più"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tocca due volte per\nspostare questa app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Ingrandisci"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Riduci a icona"</string>
<string name="close_button_text" msgid="2913281996024033299">"Chiudi"</string>
<string name="back_button_text" msgid="1469718707134137085">"Indietro"</string>
<string name="handle_text" msgid="1766582106752184456">"Handle"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Icona dell\'app"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Schermo intero"</string>
<string name="desktop_text" msgid="1077633567027630454">"Modalità desktop"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Schermo diviso"</string>
<string name="more_button_text" msgid="3655388105592893530">"Altro"</string>
<string name="float_button_text" msgid="9221657008391364581">"Mobile"</string>
+ <string name="select_text" msgid="5139083974039906583">"Seleziona"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Chiudi"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Apri menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 26f3236e5947..bb3845b26a88 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"שינוי גודל"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"הסתרה זמנית"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ביטול ההסתרה הזמנית"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"ייתכן שהאפליקציה לא תפעל במסך מפוצל."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"האפליקציה אינה תומכת במסך מפוצל."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"יכול להיות שהאפליקציה לא תפעל עם מסך מפוצל"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"האפליקציה לא תומכת במסך מפוצל"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ניתן לפתוח את האפליקציה הזו רק בחלון אחד."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ייתכן שהאפליקציה לא תפעל במסך משני."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"האפליקציה אינה תומכת בהפעלה במסכים משניים."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"מחלק מסך מפוצל"</string>
- <string name="divider_title" msgid="5482989479865361192">"מחלק מסך מפוצל"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"מחלק מסך מפוצל"</string>
+ <string name="divider_title" msgid="1963391955593749442">"מחלק מסך מפוצל"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"מסך שמאלי מלא"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"שמאלה 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"שמאלה 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"עליון 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"למעלה 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"מסך תחתון מלא"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"פיצול שמאלה"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"פיצול ימינה"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"פיצול למעלה"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"פיצול למטה"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"איך להשתמש בתכונה \'מצב שימוש ביד אחת\'"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"כדי לצאת, יש להחליק למעלה מתחתית המסך או להקיש במקום כלשהו במסך מעל האפליקציה"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"הפעלה של מצב שימוש ביד אחת"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר להקיש כדי לחזור לגרסה הקודמת"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר להקיש כדי לסגור."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"רוצה לראות ולעשות יותר?"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"צריך לגרור אפליקציה אחרת כדי להשתמש במסך מפוצל"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"צריך לגרור אפליקציה אחרת כדי להשתמש במסך המפוצל"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"צריך להקיש הקשה כפולה מחוץ לאפליקציה כדי למקם אותה מחדש"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"הבנתי"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"מרחיבים כדי לקבל מידע נוסף."</string>
@@ -96,15 +92,22 @@
<string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"אפשר להפעיל מחדש את האפליקציה כדי שהיא תוצג באופן טוב יותר במסך, אבל ייתכן שההתקדמות שלך או כל שינוי שלא נשמר יאבדו"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"ביטול"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"הפעלה מחדש"</string>
- <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"אין צורך להציג את זה שוב"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"אין להציג שוב"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"אפשר להקיש הקשה כפולה כדי\nלהעביר את האפליקציה למקום אחר"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"הגדלה"</string>
<string name="minimize_button_text" msgid="271592547935841753">"מזעור"</string>
<string name="close_button_text" msgid="2913281996024033299">"סגירה"</string>
<string name="back_button_text" msgid="1469718707134137085">"חזרה"</string>
<string name="handle_text" msgid="1766582106752184456">"נקודת אחיזה"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"סמל האפליקציה"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"מסך מלא"</string>
<string name="desktop_text" msgid="1077633567027630454">"ממשק המחשב"</string>
<string name="split_screen_text" msgid="1396336058129570886">"מסך מפוצל"</string>
<string name="more_button_text" msgid="3655388105592893530">"עוד"</string>
<string name="float_button_text" msgid="9221657008391364581">"בלונים"</string>
+ <string name="select_text" msgid="5139083974039906583">"בחירה"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"צילום מסך"</string>
+ <string name="close_text" msgid="4986518933445178928">"סגירה"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"פתיחת התפריט"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 91fd724791fa..8f2f6d8e882f 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"サイズ変更"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"非表示"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"表示"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"アプリは分割画面では動作しないことがあります。"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"アプリで分割画面がサポートされていません。"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"アプリは分割画面では動作しないことがあります"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"アプリで分割画面がサポートされていません"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"このアプリはウィンドウが 1 つの場合のみ開くことができます。"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"アプリはセカンダリ ディスプレイでは動作しないことがあります。"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"アプリはセカンダリ ディスプレイでの起動に対応していません。"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"分割画面の分割線"</string>
- <string name="divider_title" msgid="5482989479865361192">"分割画面の分割線"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"分割画面の分割線"</string>
+ <string name="divider_title" msgid="1963391955593749442">"分割画面の分割線"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左全画面"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"左 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左 50%"</string>
@@ -49,16 +49,12 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"上 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"上 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"下部全画面"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"左に分割"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"右に分割"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"上に分割"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"下に分割"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"片手モードの使用"</string>
- <string name="one_handed_tutorial_description" msgid="3486582858591353067">"終了するには、画面を下から上にスワイプするか、アプリの任意の場所をタップします"</string>
+ <string name="one_handed_tutorial_description" msgid="3486582858591353067">"終了するには、画面を下から上にスワイプするか、アプリの上側の任意の場所をタップします"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"片手モードを開始します"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"片手モードを終了します"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> のバブルの設定"</string>
@@ -83,28 +79,35 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"バブル"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ふきだしが非表示になっています。"</string>
- <string name="restart_button_description" msgid="6712141648865547958">"タップしてこのアプリを再起動すると、表示が適切になります。"</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"タップしてこのアプリを再起動すると、より見やすく表示されます。"</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"カメラに関する問題の場合は、\nタップすると修正できます"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"修正されなかった場合は、\nタップすると元に戻ります"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"カメラに関する問題でない場合は、タップすると閉じます。"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"表示を拡大して機能を強化"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"分割画面にするにはもう 1 つのアプリをドラッグしてください"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"分割画面にするにはもう 1 つのアプリをドラッグしてください"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"位置を変えるにはアプリの外側をダブルタップしてください"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"開くと詳細が表示されます。"</string>
- <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"再起動して画面をすっきりさせますか?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"アプリを再起動して画面をすっきりさせることはできますが、進捗状況が失われ、保存されていない変更が消える可能性があります"</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"アプリを再起動して画面表示を最適化しますか?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"アプリを再起動することにより表示を最適化できますが、保存されていない変更は失われる可能性があります"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"キャンセル"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"再起動"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"次回から表示しない"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ダブルタップすると\nこのアプリを移動できます"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
<string name="minimize_button_text" msgid="271592547935841753">"最小化"</string>
<string name="close_button_text" msgid="2913281996024033299">"閉じる"</string>
<string name="back_button_text" msgid="1469718707134137085">"戻る"</string>
<string name="handle_text" msgid="1766582106752184456">"ハンドル"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"アプリのアイコン"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"全画面表示"</string>
<string name="desktop_text" msgid="1077633567027630454">"デスクトップ モード"</string>
<string name="split_screen_text" msgid="1396336058129570886">"分割画面"</string>
<string name="more_button_text" msgid="3655388105592893530">"その他"</string>
<string name="float_button_text" msgid="9221657008391364581">"フローティング"</string>
+ <string name="select_text" msgid="5139083974039906583">"選択"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"スクリーンショット"</string>
+ <string name="close_text" msgid="4986518933445178928">"閉じる"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"メニューを開く"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index a711afd5e39e..e58e67ab36cb 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ზომის შეცვლა"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"გადანახვა"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"გადანახვის გაუქმება"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"აპმა შეიძლება არ იმუშაოს გაყოფილი ეკრანის რეჟიმში."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"აპმა შეიძლება არ იმუშაოს გაყოფილი ეკრანის რეჟიმში"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ამ აპის გახსნა შესაძლებელია მხოლოდ 1 ფანჯარაში."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"აპმა შეიძლება არ იმუშაოს მეორეულ ეკრანზე."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"აპს არ გააჩნია მეორეული ეკრანის მხარდაჭერა."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"გაყოფილი ეკრანის რეჟიმის გამყოფი"</string>
- <string name="divider_title" msgid="5482989479865361192">"ეკრანის გაყოფის გამყოფი"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"ეკრანის გაყოფის გამყოფი"</string>
+ <string name="divider_title" msgid="1963391955593749442">"ეკრანის გაყოფის გამყოფი"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"მარცხენა ნაწილის სრულ ეკრანზე გაშლა"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"მარცხენა ეკრანი — 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"მარცხენა ეკრანი — 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ზედა ეკრანი — 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ზედა ეკრანი — 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ქვედა ნაწილის სრულ ეკრანზე გაშლა"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"გაყოფა მარცხნივ"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"გაყოფა მარჯვნივ"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"გაყოფა ზემოთ"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"გაყოფა ქვემოთ"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"ცალი ხელის რეჟიმის გამოყენება"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"გასასვლელად გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ ან შეეხეთ ნებისმიერ ადგილას აპის ზემოთ"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ცალი ხელის რეჟიმის დაწყება"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"არ გამოსწორდა?\nშეეხეთ წინა ვერსიის დასაბრუნებლად"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"კამერას პრობლემები არ აქვს? შეეხეთ უარყოფისთვის."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"მეტის ნახვა და გაკეთება"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ეკრანის გასაყოფად ჩავლებით გადაიტანეთ სხვა აპში"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ეკრანის გასაყოფად ჩავლებით გადაიტანეთ სხვა აპში"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ორმაგად შეეხეთ აპის გარშემო სივრცეს, რათა ის სხვაგან გადაიტანოთ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"გასაგებია"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"დამატებითი ინფორმაციისთვის გააფართოეთ."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"გაუქმება"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"გადატვირთვა"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"აღარ გამოჩნდეს"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ამ აპის გადასატანად\nორმაგად შეეხეთ მას"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"მაქსიმალურად გაშლა"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ჩაკეცვა"</string>
<string name="close_button_text" msgid="2913281996024033299">"დახურვა"</string>
<string name="back_button_text" msgid="1469718707134137085">"უკან"</string>
<string name="handle_text" msgid="1766582106752184456">"იდენტიფიკატორი"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"აპის ხატულა"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"სრულ ეკრანზე"</string>
<string name="desktop_text" msgid="1077633567027630454">"დესკტოპის რეჟიმი"</string>
<string name="split_screen_text" msgid="1396336058129570886">"ეკრანის გაყოფა"</string>
<string name="more_button_text" msgid="3655388105592893530">"სხვა"</string>
<string name="float_button_text" msgid="9221657008391364581">"ფარფატი"</string>
+ <string name="select_text" msgid="5139083974039906583">"არჩევა"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"ეკრანის ანაბეჭდი"</string>
+ <string name="close_text" msgid="4986518933445178928">"დახურვა"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"მენიუს დახურვა"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"მენიუს გახსნა"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index a2e868805d08..c40cd2fb24aa 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлшемін өзгерту"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Жасыру"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Көрсету"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Қолданба экранды бөлу режимінде жұмыс істемеуі мүмкін."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Қодланба бөлінген экранды қолдамайды."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Қолданба экранды бөлу режимінде жұмыс істемеуі мүмкін."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Қолданбада экранды бөлу мүмкін емес."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Бұл қолданбаны тек 1 терезеден ашуға болады."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Қолданба қосымша дисплейде жұмыс істемеуі мүмкін."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Қолданба қосымша дисплейлерде іске қосуды қолдамайды."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Бөлінген экран бөлгіші"</string>
- <string name="divider_title" msgid="5482989479865361192">"Бөлінген экран бөлгіші"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Экранды бөлу режимінің бөлгіші"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Экранды бөлу режимінің бөлгіші"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Сол жағын толық экранға шығару"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% сол жақта"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% сол жақта"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% жоғарғы жақта"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% жоғарғы жақта"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Төменгісін толық экранға шығару"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Сол жақтан шығару"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Оң жақтан шығару"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Жоғарыдан шығару"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Астынан шығару"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Бір қолмен енгізу режимін пайдалану"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Шығу үшін экранның төменгі жағынан жоғары қарай сырғытыңыз немесе қолданбаның үстінен кез келген жерден түртіңіз."</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Бір қолмен енгізу режимін іске қосу"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Көпіршік"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Басқару"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Қалқыма хабар жабылды."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Ыңғайлы көріністі реттеу үшін қолданбаны түртіп, өшіріп қосыңыз."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Түртсеңіз, қолданба жабылып, ыңғайлы көрініспен қайта ашылады."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада қателер шықты ма?\nЖөндеу үшін түртіңіз."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Жөнделмеді ме?\nҚайтару үшін түртіңіз."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада қателер шықпады ма? Жабу үшін түртіңіз."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Қосымша ақпаратты қарап, әрекеттер жасау"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Экранды бөлу үшін басқа қолданбаға сүйреңіз."</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Экранды бөлу үшін басқа қолданбаға өтіңіз."</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Қолданбаның орнын өзгерту үшін одан тыс жерді екі рет түртіңіз."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түсінікті"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толығырақ ақпарат алу үшін терезені жайыңыз."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Бас тарту"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Өшіріп қосу"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Қайта көрсетілмесін"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Бұл қолданбаны басқа орынға\nжылжыту үшін екі рет түртіңіз."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Жаю"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Кішірейту"</string>
<string name="close_button_text" msgid="2913281996024033299">"Жабу"</string>
<string name="back_button_text" msgid="1469718707134137085">"Артқа"</string>
<string name="handle_text" msgid="1766582106752184456">"Идентификатор"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Қолданба белгішесі"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Толық экран"</string>
<string name="desktop_text" msgid="1077633567027630454">"Компьютер режимі"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Экранды бөлу"</string>
<string name="more_button_text" msgid="3655388105592893530">"Қосымша"</string>
<string name="float_button_text" msgid="9221657008391364581">"Қалқыма"</string>
+ <string name="select_text" msgid="5139083974039906583">"Таңдау"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string>
+ <string name="close_text" msgid="4986518933445178928">"Жабу"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Мәзірді ашу"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 7a486b86747c..45302677a043 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ប្ដូរ​ទំហំ"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"លាក់ជាបណ្ដោះអាសន្ន"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ឈប់លាក់ជាបណ្ដោះអាសន្ន"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"កម្មវិធី​អាចនឹងមិន​ដំណើរការ​ជាមួយ​មុខងារបំបែកអេក្រង់​ទេ។"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"កម្មវិធីមិនគាំទ្រអេក្រង់បំបែកជាពីរទេ"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"កម្មវិធី​អាចមិន​ដំណើរការ​ជាមួយ​មុខងារបំបែកអេក្រង់​ទេ"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"កម្មវិធីមិនអាចប្រើមុខងារ​បំបែកអេក្រង់បានទេ"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"កម្មវិធីនេះអាចបើកនៅក្នុងវិនដូតែ 1 ប៉ុណ្ណោះ។"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"កម្មវិធីនេះ​ប្រហែល​ជាមិនដំណើរការ​នៅលើ​អេក្រង់បន្ទាប់បន្សំទេ។"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"កម្មវិធី​នេះមិន​អាច​ចាប់ផ្តើម​នៅលើ​អេក្រង់បន្ទាប់បន្សំបានទេ។"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"កម្មវិធីចែកអេក្រង់បំបែក"</string>
- <string name="divider_title" msgid="5482989479865361192">"បន្ទាត់ខណ្ឌចែកអេក្រង់បំបែក"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"បន្ទាត់ខណ្ឌចែកក្នុងមុខងារ​បំបែកអេក្រង់"</string>
+ <string name="divider_title" msgid="1963391955593749442">"បន្ទាត់ខណ្ឌចែកក្នុងមុខងារ​បំបែកអេក្រង់"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"អេក្រង់ពេញខាងឆ្វេង"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ឆ្វេង 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ឆ្វេង 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ខាងលើ 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ខាងលើ 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"អេក្រង់ពេញខាងក្រោម"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"បំបែក​ខាងឆ្វេង"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"បំបែក​ខាងស្ដាំ"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"បំបែក​ខាងលើ"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"បំបែក​ខាងក្រោម"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"កំពុងប្រើ​មុខងារប្រើដៃម្ខាង"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"ដើម្បីចាកចេញ សូមអូសឡើងលើ​ពីផ្នែកខាងក្រោមអេក្រង់ ឬចុចផ្នែកណាមួយ​នៅខាងលើកម្មវិធី"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ចាប់ផ្ដើម​មុខងារប្រើដៃម្ខាង"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"មិនបាន​ដោះស្រាយ​បញ្ហានេះទេឬ?\nចុចដើម្បី​ត្រឡប់"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"មិនមាន​បញ្ហាពាក់ព័ន្ធនឹង​កាមេរ៉ាទេឬ? ចុចដើម្បី​ច្រានចោល។"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"មើលឃើញ និងធ្វើបានកាន់តែច្រើន"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"អូស​កម្មវិធី​មួយ​ទៀត​ចូល ដើម្បី​ប្រើ​មុខងារ​បំបែកអេក្រង់"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"អូស​កម្មវិធី​មួយ​ទៀត​ចូល ដើម្បី​ប្រើ​មុខងារ​បំបែកអេក្រង់"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ចុចពីរដង​នៅ​ក្រៅ​កម្មវិធី ដើម្បី​ប្ដូរ​ទីតាំង​កម្មវិធី​នោះ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"យល់ហើយ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ពង្រីកដើម្បីទទួលបានព័ត៌មានបន្ថែម។"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"បោះបង់"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"ចាប់ផ្ដើម​ឡើង​វិញ"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"កុំ​បង្ហាញ​ម្ដង​ទៀត"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ចុចពីរដងដើម្បី\nផ្លាស់ទីកម្មវិធីនេះ"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ពង្រីក"</string>
<string name="minimize_button_text" msgid="271592547935841753">"បង្រួម"</string>
<string name="close_button_text" msgid="2913281996024033299">"បិទ"</string>
<string name="back_button_text" msgid="1469718707134137085">"ថយក្រោយ"</string>
<string name="handle_text" msgid="1766582106752184456">"ឈ្មោះអ្នកប្រើប្រាស់"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"រូប​កម្មវិធី"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"អេក្រង់​ពេញ"</string>
<string name="desktop_text" msgid="1077633567027630454">"មុខងារកុំព្យូទ័រ"</string>
<string name="split_screen_text" msgid="1396336058129570886">"មុខងារ​បំបែក​អេក្រង់"</string>
<string name="more_button_text" msgid="3655388105592893530">"ច្រើនទៀត"</string>
<string name="float_button_text" msgid="9221657008391364581">"អណ្ដែត"</string>
+ <string name="select_text" msgid="5139083974039906583">"ជ្រើសរើស"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"រូបថតអេក្រង់"</string>
+ <string name="close_text" msgid="4986518933445178928">"បិទ"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"បិទ​ម៉ឺនុយ"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"បើកម៉ឺនុយ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 5fcdcf2c8fac..2dfbad49bb06 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -24,7 +24,7 @@
<string name="pip_menu_title" msgid="5393619322111827096">"ಮೆನು"</string>
<string name="pip_menu_accessibility_title" msgid="8129016817688656249">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ ಮೆನು"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವಾಗಿದೆ"</string>
- <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ಈ ವೈಶಿಷ್ಟ್ಯ ಬಳಸುವುದನ್ನು ನೀವು ಬಯಸದಿದ್ದರೆ, ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಲು ಮತ್ತು ಅದನ್ನು ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ಈ ಫೀಚರ್ ಬಳಸುವುದನ್ನು ನೀವು ಬಯಸದಿದ್ದರೆ, ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಲು ಮತ್ತು ಅದನ್ನು ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="pip_play" msgid="3496151081459417097">"ಪ್ಲೇ"</string>
<string name="pip_pause" msgid="690688849510295232">"ವಿರಾಮಗೊಳಿಸಿ"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"ಮುಂದಕ್ಕೆ ಸ್ಕಿಪ್‌ ಮಾಡಿ"</string>
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ಸ್ಟ್ಯಾಶ್ ಮಾಡಿ"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ಅನ್‌ಸ್ಟ್ಯಾಶ್ ಮಾಡಿ"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"ವಿಭಜಿಸಿದ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ಆ್ಯಪ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"ಸ್ಪ್ಲಿಟ್‌ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ಆ್ಯಪ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"ಸ್ಪ್ಲಿಟ್‌ ಸ್ಕ್ರೀನ್‌ ಅನ್ನು ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ಈ ಆ್ಯಪ್ ಅನ್ನು 1 ವಿಂಡೋದಲ್ಲಿ ಮಾತ್ರ ತೆರೆಯಬಹುದು."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ಸೆಕೆಂಡರಿ ಡಿಸ್‌ಪ್ಲೇಗಳಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್‌ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ಸೆಕೆಂಡರಿ ಡಿಸ್‌ಪ್ಲೇಗಳಲ್ಲಿ ಪ್ರಾರಂಭಿಸುವಿಕೆಯನ್ನು ಅಪ್ಲಿಕೇಶನ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"ಸ್ಪ್ಲಿಟ್-ಪರದೆ ಡಿವೈಡರ್"</string>
- <string name="divider_title" msgid="5482989479865361192">"ಸ್ಪ್ಲಿಟ್-ಪರದೆ ಡಿವೈಡರ್"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"ಸ್ಪ್ಲಿಟ್‌ ಸ್ಕ್ರೀನ್ ಡಿವೈಡರ್"</string>
+ <string name="divider_title" msgid="1963391955593749442">"ಸ್ಪ್ಲಿಟ್‌ ಸ್ಕ್ರೀನ್ ಡಿವೈಡರ್"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ಎಡ ಪೂರ್ಣ ಪರದೆ"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% ಎಡಕ್ಕೆ"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% ಎಡಕ್ಕೆ"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% ಮೇಲಕ್ಕೆ"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% ಮೇಲಕ್ಕೆ"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ಕೆಳಗಿನ ಪೂರ್ಣ ಪರದೆ"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"ಎಡಕ್ಕೆ ವಿಭಜಿಸಿ"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"ಬಲಕ್ಕೆ ವಿಭಜಿಸಿ"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"ಮೇಲಕ್ಕೆ ವಿಭಜಿಸಿ"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"ಕೆಳಕ್ಕೆ ವಿಭಜಿಸಿ"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"ಒಂದು ಕೈ ಮೋಡ್ ಬಳಸುವುದರ ಬಗ್ಗೆ"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"ನಿರ್ಗಮಿಸಲು, ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಅಥವಾ ಆ್ಯಪ್‌ನ ಮೇಲೆ ಎಲ್ಲಿಯಾದರೂ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ಒಂದು ಕೈ ಮೋಡ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಿ"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ಅದನ್ನು ಸರಿಪಡಿಸಲಿಲ್ಲವೇ?\nಹಿಂತಿರುಗಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿಲ್ಲವೇ? ವಜಾಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ನೋಡಿ ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್‌ಗಾಗಿ ಮತ್ತೊಂದು ಆ್ಯಪ್‌ನಲ್ಲಿ ಎಳೆಯಿರಿ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ಸ್ಪ್ಲಿಟ್‌ ಸ್ಕ್ರೀನ್‌ಗಾಗಿ ಮತ್ತೊಂದು ಆ್ಯಪ್‌ನಲ್ಲಿ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ಆ್ಯಪ್ ಒಂದರ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸಲು ಅದರ ಹೊರಗೆ ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ಸರಿ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ವಿಸ್ತೃತಗೊಳಿಸಿ."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"ರದ್ದುಮಾಡಿ"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"ಮರುಪ್ರಾರಂಭಿಸಿ"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಸರಿಸಲು\nಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ಹಿಗ್ಗಿಸಿ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ಕುಗ್ಗಿಸಿ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ಮುಚ್ಚಿರಿ"</string>
<string name="back_button_text" msgid="1469718707134137085">"ಹಿಂದಕ್ಕೆ"</string>
<string name="handle_text" msgid="1766582106752184456">"ಹ್ಯಾಂಡಲ್"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ಆ್ಯಪ್ ಐಕಾನ್"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ಫುಲ್‌ಸ್ಕ್ರೀನ್"</string>
<string name="desktop_text" msgid="1077633567027630454">"ಡೆಸ್ಕ್‌ಟಾಪ್ ಮೋಡ್"</string>
<string name="split_screen_text" msgid="1396336058129570886">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string>
<string name="more_button_text" msgid="3655388105592893530">"ಇನ್ನಷ್ಟು"</string>
<string name="float_button_text" msgid="9221657008391364581">"ಫ್ಲೋಟ್"</string>
+ <string name="select_text" msgid="5139083974039906583">"ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
+ <string name="close_text" msgid="4986518933445178928">"ಮುಚ್ಚಿ"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"ಮೆನು ತೆರೆಯಿರಿ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 74cff1f5b13e..55697ca23a86 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"크기 조절"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"숨기기"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"숨기기 취소"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"앱이 분할 화면에서 작동하지 않을 수 있습니다."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"앱이 화면 분할을 지원하지 않습니다."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"앱이 화면 분할 모드로는 작동하지 않을 수 있습니다"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"앱이 화면 분할을 지원하지 않습니다"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"이 앱은 창 1개에서만 열 수 있습니다."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"앱이 보조 디스플레이에서 작동하지 않을 수도 있습니다."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"앱이 보조 디스플레이에서의 실행을 지원하지 않습니다."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"화면 분할기"</string>
- <string name="divider_title" msgid="5482989479865361192">"화면 분할기"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"화면 분할기"</string>
+ <string name="divider_title" msgid="1963391955593749442">"화면 분할기"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"왼쪽 화면 전체화면"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"왼쪽 화면 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"왼쪽 화면 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"위쪽 화면 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"위쪽 화면 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"아래쪽 화면 전체화면"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"왼쪽으로 분할"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"오른쪽으로 분할"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"위쪽으로 분할"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"아래쪽으로 분할"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"한 손 사용 모드 사용하기"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"화면 하단에서 위로 스와이프하거나 앱 상단을 탭하여 종료합니다."</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"한 손 사용 모드 시작"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"버블"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"관리"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"대화창을 닫았습니다."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"보기를 개선하려면 탭하여 앱을 다시 시작합니다."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"더 편하게 보기를 원하면 탭하여 앱을 다시 시작하세요."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"카메라 문제가 있나요?\n해결하려면 탭하세요."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"해결되지 않았나요?\n되돌리려면 탭하세요."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"카메라에 문제가 없나요? 닫으려면 탭하세요."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"더 많은 정보를 보고 더 많은 작업을 처리하세요"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"화면 분할을 사용하려면 다른 앱을 드래그해 가져옵니다."</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"화면 분할을 사용하려면 다른 앱을 드래그해 가져옵니다."</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"앱 위치를 조정하려면 앱 외부를 두 번 탭합니다."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"확인"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"추가 정보는 펼쳐서 확인하세요."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"취소"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"다시 시작"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"다시 표시 안함"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"두 번 탭하여\n이 앱 이동"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"최대화"</string>
<string name="minimize_button_text" msgid="271592547935841753">"최소화"</string>
<string name="close_button_text" msgid="2913281996024033299">"닫기"</string>
<string name="back_button_text" msgid="1469718707134137085">"뒤로"</string>
<string name="handle_text" msgid="1766582106752184456">"핸들"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"앱 아이콘"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"전체 화면"</string>
<string name="desktop_text" msgid="1077633567027630454">"데스크톱 모드"</string>
<string name="split_screen_text" msgid="1396336058129570886">"화면 분할"</string>
<string name="more_button_text" msgid="3655388105592893530">"더보기"</string>
<string name="float_button_text" msgid="9221657008391364581">"플로팅"</string>
+ <string name="select_text" msgid="5139083974039906583">"선택"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"스크린샷"</string>
+ <string name="close_text" msgid="4986518933445178928">"닫기"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"메뉴 열기"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 477c65d2e68e..19df267e1d27 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -24,7 +24,7 @@
<string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
<string name="pip_menu_accessibility_title" msgid="8129016817688656249">"Сүрөт ичиндеги сүрөт менюсу"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> – сүрөт ичиндеги сүрөт"</string>
- <string name="pip_notification_message" msgid="8854051911700302620">"Эгер <xliff:g id="NAME">%s</xliff:g> колдонмосу бул функцияны пайдаланбасын десеңиз, жөндөөлөрдү ачып туруп, аны өчүрүп коюңуз."</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Эгер <xliff:g id="NAME">%s</xliff:g> колдонмосу бул функцияны пайдаланбасын десеңиз, параметрлерди ачып туруп, аны өчүрүп коюңуз."</string>
<string name="pip_play" msgid="3496151081459417097">"Ойнотуу"</string>
<string name="pip_pause" msgid="690688849510295232">"Тындыруу"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"Кийинкисине өткөрүп жиберүү"</string>
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлчөмүн өзгөртүү"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сейфке салуу"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Сейфтен чыгаруу"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Колдонмодо экран бөлүнбөшү мүмкүн."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Колдонмодо экран бөлүнбөйт."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Колдонмодо экран бөлүнбөшү мүмкүн"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Колдонмодо экран бөлүнбөйт"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Бул колдонмону 1 терезеде гана ачууга болот."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Колдонмо кошумча экранда иштебей коюшу мүмкүн."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Колдонмону кошумча экрандарда иштетүүгө болбойт."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Экранды бөлгүч"</string>
- <string name="divider_title" msgid="5482989479865361192">"Экранды бөлгүч"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Экранды бөлгүч"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Экранды бөлгүч"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Сол жактагы экранды толук экран режимине өткөрүү"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Сол жактагы экранды 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Сол жактагы экранды 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Үстүнкү экранды 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Үстүнкү экранды 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ылдыйкы экранды толук экран режимине өткөрүү"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Солго бөлүү"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Оңго бөлүү"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Өйдө бөлүү"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Ылдый бөлүү"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Бир кол режимин колдонуу"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Чыгуу үчүн экранды ылдый жагынан өйдө сүрүңүз же колдонмонун өйдө жагын басыңыз"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Бир кол режимин баштоо"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Оңдолгон жокпу?\nАртка кайтаруу үчүн таптаңыз"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада маселе жокпу? Этибарга албоо үчүн таптаңыз."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Көрүп, көбүрөөк нерселерди жасаңыз"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Экранды бөлүү үчүн башка колдонмону сүйрөңүз"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Экранды бөлүү үчүн башка колдонмону сүйрөңүз"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Колдонмону жылдыруу үчүн сырт жагын эки жолу таптаңыз"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түшүндүм"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толук маалымат алуу үчүн жайып көрүңүз."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Токтотуу"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Өчүрүп күйгүзүү"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Экинчи көрүнбөсүн"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Бул колдонмону жылдыруу үчүн\nэки жолу таптаңыз"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Чоңойтуу"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Кичирейтүү"</string>
<string name="close_button_text" msgid="2913281996024033299">"Жабуу"</string>
<string name="back_button_text" msgid="1469718707134137085">"Артка"</string>
<string name="handle_text" msgid="1766582106752184456">"Маркер"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Колдонмонун сүрөтчөсү"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Толук экран"</string>
<string name="desktop_text" msgid="1077633567027630454">"Компьютер режими"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Экранды бөлүү"</string>
<string name="more_button_text" msgid="3655388105592893530">"Дагы"</string>
<string name="float_button_text" msgid="9221657008391364581">"Калкыма"</string>
+ <string name="select_text" msgid="5139083974039906583">"Тандоо"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string>
+ <string name="close_text" msgid="4986518933445178928">"Жабуу"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Менюну ачуу"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 81b082600f76..a25699fa4d10 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ປ່ຽນຂະໜາດ"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ເກັບໄວ້ບ່ອນເກັບສ່ວນຕົວ"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ເອົາອອກຈາກບ່ອນເກັບສ່ວນຕົວ"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"ແອັບອາດໃຊ້ບໍ່ໄດ້ກັບການແບ່ງໜ້າຈໍ."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ແອັບບໍ່ຮອງຮັບໜ້າຈໍແບບແຍກກັນ."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"ແອັບອາດໃຊ້ບໍ່ໄດ້ກັບໂໝດແບ່ງໜ້າຈໍ"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"ແອັບບໍ່ຮອງຮັບການແບ່ງໜ້າຈໍ"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ແອັບນີ້ສາມາດເປີດໄດ້ໃນ 1 ໜ້າຈໍເທົ່ານັ້ນ."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ໃນໜ້າຈໍທີສອງ."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ແອັບບໍ່ຮອງຮັບການເປີດໃນໜ້າຈໍທີສອງ."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"ຕົວຂັ້ນການແບ່ງໜ້າຈໍ"</string>
- <string name="divider_title" msgid="5482989479865361192">"ຕົວຂັ້ນການແບ່ງໜ້າຈໍ"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"ເສັ້ນແບ່ງໜ້າຈໍ"</string>
+ <string name="divider_title" msgid="1963391955593749442">"ເສັ້ນແບ່ງໜ້າຈໍ"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ເຕັມໜ້າຈໍຊ້າຍ"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ຊ້າຍ 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ຊ້າຍ 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ເທິງສຸດ 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ເທິງສຸດ 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ເຕັມໜ້າຈໍລຸ່ມສຸດ"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"ແຍກຊ້າຍ"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"ແຍກຂວາ"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"ແຍກເທິງ"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"ແຍກລຸ່ມ"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"ກຳລັງໃຊ້ໂໝດມືດຽວ"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"ເພື່ອອອກ, ໃຫ້ປັດຂຶ້ນຈາກລຸ່ມສຸດຂອງໜ້າຈໍ ຫຼື ແຕະບ່ອນໃດກໍໄດ້ຢູ່ເໜືອແອັບ"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ເລີ່ມໂໝດມືດຽວ"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ບໍ່ໄດ້ແກ້ໄຂມັນບໍ?\nແຕະເພື່ອແປງກັບຄືນ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ບໍ່ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ? ແຕະເພື່ອ​ປິດ​ໄວ້."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ເບິ່ງ ແລະ ເຮັດຫຼາຍຂຶ້ນ"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ລາກແອັບອື່ນເຂົ້າມາເພື່ອແບ່ງໜ້າຈໍ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ລາກໄປໄວ້ໃນແອັບອື່ນເພື່ອແບ່ງໜ້າຈໍ"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ແຕະສອງເທື່ອໃສ່ນອກແອັບໃດໜຶ່ງເພື່ອຈັດຕຳແໜ່ງຂອງມັນຄືນໃໝ່"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ເຂົ້າໃຈແລ້ວ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ຂະຫຍາຍເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"ຍົກເລີກ"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"ຣີສະຕາດ"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ແຕະສອງເທື່ອເພື່ອ\nຍ້າຍແອັບນີ້"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ຂະຫຍາຍໃຫຍ່ສຸດ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ຫຍໍ້ລົງ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ປິດ"</string>
<string name="back_button_text" msgid="1469718707134137085">"ກັບຄືນ"</string>
<string name="handle_text" msgid="1766582106752184456">"ມືບັງຄັບ"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ໄອຄອນແອັບ"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ເຕັມຈໍ"</string>
<string name="desktop_text" msgid="1077633567027630454">"ໂໝດເດັສທັອບ"</string>
<string name="split_screen_text" msgid="1396336058129570886">"ແບ່ງໜ້າຈໍ"</string>
<string name="more_button_text" msgid="3655388105592893530">"ເພີ່ມເຕີມ"</string>
<string name="float_button_text" msgid="9221657008391364581">"ລອຍ"</string>
+ <string name="select_text" msgid="5139083974039906583">"ເລືອກ"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"ຮູບໜ້າຈໍ"</string>
+ <string name="close_text" msgid="4986518933445178928">"ປິດ"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"ເປີດເມນູ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 0447ec7b2797..d893fcf21d46 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Pakeisti dydį"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Paslėpti"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Nebeslėpti"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Programa gali neveikti naudojant išskaidyto ekrano režimą."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programoje nepalaikomas skaidytas ekranas."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Programa gali neveikti naudojant išskaidyto ekrano režimą"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Programoje nepalaikomas išskaidyto ekrano režimas"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Šią programą galima atidaryti tik viename lange."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Programa gali neveikti antriniame ekrane."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Programa nepalaiko paleisties antriniuose ekranuose."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Skaidyto ekrano daliklis"</string>
- <string name="divider_title" msgid="5482989479865361192">"Skaidyto ekrano daliklis"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Išskaidyto ekrano režimo daliklis"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Išskaidyto ekrano režimo daliklis"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Kairysis ekranas viso ekrano režimu"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kairysis ekranas 70 %"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kairysis ekranas 50 %"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Viršutinis ekranas 50 %"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Viršutinis ekranas 30 %"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Apatinis ekranas viso ekrano režimu"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Išskaidyti kairėn"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Išskaidyti dešinėn"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Išskaidyti viršuje"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Išskaidyti apačioje"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Vienos rankos režimo naudojimas"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Jei norite išeiti, perbraukite aukštyn nuo ekrano apačios arba palieskite bet kur virš programos"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Pradėti vienos rankos režimą"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepavyko pataisyti?\nPalieskite, kad grąžintumėte"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nėra jokių problemų dėl kameros? Palieskite, kad atsisakytumėte."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daugiau turinio ir funkcijų"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Vilkite kitoje programoje, kad galėtumėte naudoti išskaidyto ekrano režimą"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Vilkite kitoje programoje, kad galėtumėte naudoti išskaidyto ekrano režimą"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dukart palieskite už programos ribų, kad pakeistumėte jos poziciją"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Supratau"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Išskleiskite, jei reikia daugiau informacijos."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Atšaukti"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Paleisti iš naujo"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Daugiau neberodyti"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dukart palieskite, kad\nperkeltumėte šią programą"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Padidinti"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Sumažinti"</string>
<string name="close_button_text" msgid="2913281996024033299">"Uždaryti"</string>
<string name="back_button_text" msgid="1469718707134137085">"Atgal"</string>
<string name="handle_text" msgid="1766582106752184456">"Rankenėlė"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Programos piktograma"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Visas ekranas"</string>
<string name="desktop_text" msgid="1077633567027630454">"Stalinio kompiuterio režimas"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Išskaidyto ekrano režimas"</string>
<string name="more_button_text" msgid="3655388105592893530">"Daugiau"</string>
<string name="float_button_text" msgid="9221657008391364581">"Slankusis langas"</string>
+ <string name="select_text" msgid="5139083974039906583">"Pasirinkti"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Ekrano kopija"</string>
+ <string name="close_text" msgid="4986518933445178928">"Uždaryti"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Uždaryti meniu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Atidaryti meniu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index e612ddda69eb..a1fbcddb1e3a 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Mainīt lielumu"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Paslēpt"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Rādīt"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Iespējams, lietotne nedarbosies ekrāna sadalīšanas režīmā."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Iespējams, lietotne nedarbosies ekrāna sadalīšanas režīmā"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Lietotnē netiek atbalstīta ekrāna sadalīšana"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Šo lietotni var atvērt tikai vienā logā."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Lietotne, iespējams, nedarbosies sekundārajā displejā."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Lietotnē netiek atbalstīta palaišana sekundārajos displejos."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Ekrāna sadalītājs"</string>
- <string name="divider_title" msgid="5482989479865361192">"Ekrāna sadalītājs"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Ekrāna sadalītājs"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Ekrāna sadalītājs"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Kreisā daļa pa visu ekrānu"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Pa kreisi 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pa kreisi 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Augšdaļa 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Augšdaļa 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Apakšdaļu pa visu ekrānu"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Sadalījums pa kreisi"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Sadalījums pa labi"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Sadalījums augšdaļā"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Sadalījums apakšdaļā"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Vienas rokas režīma izmantošana"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Lai izietu, velciet augšup no ekrāna apakšdaļas vai pieskarieties jebkurā vietā virs lietotnes"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Pāriet vienas rokas režīmā"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Vai problēma netika novērsta?\nPieskarieties, lai atjaunotu."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Vai nav problēmu ar kameru? Pieskarieties, lai nerādītu."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Uzziniet un paveiciet vairāk"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Lai izmantotu sadalītu ekrānu, ievelciet vēl vienu lietotni"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Lai izmantotu sadalītu ekrānu, ievelciet vēl vienu lietotni"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Lai pārvietotu lietotni, veiciet dubultskārienu ārpus lietotnes"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Labi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Izvērsiet, lai iegūtu plašāku informāciju."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Atcelt"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartēt"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Vairs nerādīt"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Veiciet dubultskārienu,\nlai pārvietotu šo lietotni"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimizēt"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizēt"</string>
<string name="close_button_text" msgid="2913281996024033299">"Aizvērt"</string>
<string name="back_button_text" msgid="1469718707134137085">"Atpakaļ"</string>
<string name="handle_text" msgid="1766582106752184456">"Turis"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Lietotnes ikona"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pilnekrāna režīms"</string>
<string name="desktop_text" msgid="1077633567027630454">"Darbvirsmas režīms"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Sadalīt ekrānu"</string>
<string name="more_button_text" msgid="3655388105592893530">"Vairāk"</string>
<string name="float_button_text" msgid="9221657008391364581">"Peldošs"</string>
+ <string name="select_text" msgid="5139083974039906583">"Atlasīt"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Ekrānuzņēmums"</string>
+ <string name="close_text" msgid="4986518933445178928">"Aizvērt"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Atvērt izvēlni"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 3c5449c22690..1567d61d833f 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промени големина"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сокријте"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Прикажете"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Апликацијата може да не работи со поделен екран."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликацијата не поддржува поделен екран."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Апликацијата можеби нема да работи со поделен екран"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Апликацијата не поддржува поделен екран"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Апликацијава може да се отвори само во еден прозорец."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликацијата може да не функционира на друг екран."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Апликацијата не поддржува стартување на други екрани."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Разделник на поделен екран"</string>
- <string name="divider_title" msgid="5482989479865361192">"Разделник на поделен екран"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Разделник на поделен екран"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Разделник на поделен екран"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левиот на цел екран"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Левиот 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левиот 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горниот 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Горниот 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Долниот на цел екран"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Подели налево"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Подели надесно"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Подели нагоре"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Подели долу"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Користење на режимот со една рака"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"За да излезете, повлечете нагоре од дното на екранот или допрете каде било над апликацијата"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Започни го режимот со една рака"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Управувајте"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отфрлено."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Допрете за да ја рестартирате апликацијава за подобар приказ."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"За подобар приказ, допрете за да ја рестартирате апликацијава."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми со камерата?\nДопрете за да се совпадне повторно"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не се поправи?\nДопрете за враќање"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нема проблеми со камерата? Допрете за отфрлање."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Погледнете и направете повеќе"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Повлечете во друга апликација за поделен екран"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Повлечете друга апликација за поделен екран"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Допрете двапати надвор од некоја апликација за да ја преместите"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Сфатив"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширете за повеќе информации."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Откажи"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартирај"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Не прикажувај повторно"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Допрете двапати за да ја\nпоместите апликацијава"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Зголеми"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Минимизирај"</string>
<string name="close_button_text" msgid="2913281996024033299">"Затвори"</string>
<string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
<string name="handle_text" msgid="1766582106752184456">"Прекар"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Икона на апликацијата"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Цел екран"</string>
<string name="desktop_text" msgid="1077633567027630454">"Режим за компјутер"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Поделен екран"</string>
<string name="more_button_text" msgid="3655388105592893530">"Повеќе"</string>
<string name="float_button_text" msgid="9221657008391364581">"Лебдечко"</string>
+ <string name="select_text" msgid="5139083974039906583">"Изберете"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Слика од екранот"</string>
+ <string name="close_text" msgid="4986518933445178928">"Затворете"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Отвори го менито"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 0df5c3a84a42..5cca248e0dd4 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"വലുപ്പം മാറ്റുക"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"സ്റ്റാഷ് ചെയ്യൽ"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"അൺസ്റ്റാഷ് ചെയ്യൽ"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"സ്‌ക്രീൻ വിഭജന മോഡിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"സ്‌ക്രീൻ വിഭജന മോഡിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"സ്‌ക്രീൻ വിഭജന മോഡിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ഈ ആപ്പ് ഒരു വിൻഡോയിൽ മാത്രമേ തുറക്കാനാകൂ."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"രണ്ടാം ഡിസ്‌പ്ലേയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"രണ്ടാം ഡിസ്‌പ്ലേകളിൽ സമാരംഭിക്കുന്നതിനെ ആപ്പ് അനുവദിക്കുന്നില്ല."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"സ്പ്ലിറ്റ്-സ്ക്രീൻ ഡിവൈഡർ"</string>
- <string name="divider_title" msgid="5482989479865361192">"സ്‌ക്രീൻ വിഭജന മോഡ് ഡിവൈഡർ"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"സ്‌ക്രീൻ വിഭജന മോഡ് ഡിവൈഡർ"</string>
+ <string name="divider_title" msgid="1963391955593749442">"സ്‌ക്രീൻ വിഭജന മോഡ് ഡിവൈഡർ"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ഇടത് പൂർണ്ണ സ്ക്രീൻ"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ഇടത് 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ഇടത് 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"മുകളിൽ 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"മുകളിൽ 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"താഴെ പൂർണ്ണ സ്ക്രീൻ"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"ഇടത് ഭാഗത്തേക്ക് വിഭജിക്കുക"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"വലത് ഭാഗത്തേക്ക് വിഭജിക്കുക"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"മുകളിലേക്ക് വിഭജിക്കുക"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"താഴേക്ക് വിഭജിക്കുക"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"ഒറ്റക്കൈ മോഡ് എങ്ങനെ ഉപയോഗിക്കാം"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"പുറത്ത് കടക്കാൻ, സ്ക്രീനിന്റെ ചുവടെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക അല്ലെങ്കിൽ ആപ്പിന് മുകളിലായി എവിടെയെങ്കിലും ടാപ്പ് ചെയ്യുക"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ഒറ്റക്കൈ മോഡ് ആരംഭിച്ചു"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"അത് പരിഹരിച്ചില്ലേ?\nപുനഃസ്ഥാപിക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ക്യാമറാ പ്രശ്നങ്ങളൊന്നുമില്ലേ? നിരസിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"കൂടുതൽ കാണുക, ചെയ്യുക"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"സ്‌ക്രീൻ വിഭജന മോഡിന്, മറ്റൊരു ആപ്പ് വലിച്ചിടുക"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"സ്‌ക്രീൻ വിഭജന മോഡിന്, മറ്റൊരു ആപ്പ് വലിച്ചിടുക"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ആപ്പിന്റെ സ്ഥാനം മാറ്റാൻ അതിന് പുറത്ത് ഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"മനസ്സിലായി"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"കൂടുതൽ വിവരങ്ങൾക്ക് വികസിപ്പിക്കുക."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"റദ്ദാക്കുക"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"റീസ്റ്റാർട്ട് ചെയ്യൂ"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"വീണ്ടും കാണിക്കരുത്"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ഈ ആപ്പ് നീക്കാൻ\nഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"വലുതാക്കുക"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ചെറുതാക്കുക"</string>
<string name="close_button_text" msgid="2913281996024033299">"അടയ്ക്കുക"</string>
<string name="back_button_text" msgid="1469718707134137085">"മടങ്ങുക"</string>
<string name="handle_text" msgid="1766582106752184456">"ഹാൻഡിൽ"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ആപ്പ് ഐക്കൺ"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"പൂർണ്ണസ്ക്രീൻ"</string>
<string name="desktop_text" msgid="1077633567027630454">"ഡെസ്‌ക്ടോപ്പ് മോഡ്"</string>
<string name="split_screen_text" msgid="1396336058129570886">"സ്‌ക്രീൻ വിഭജനം"</string>
<string name="more_button_text" msgid="3655388105592893530">"കൂടുതൽ"</string>
<string name="float_button_text" msgid="9221657008391364581">"ഫ്ലോട്ട്"</string>
+ <string name="select_text" msgid="5139083974039906583">"തിരഞ്ഞെടുക്കുക"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"സ്ക്രീൻഷോട്ട്"</string>
+ <string name="close_text" msgid="4986518933445178928">"അടയ്ക്കുക"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"മെനു തുറക്കുക"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 5f9d3db43e41..72e54fcf8711 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Хэмжээг өөрчлөх"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Нуух"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ил гаргах"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Апп хуваагдсан дэлгэц дээр ажиллахгүй байж болзошгүй."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Энэ апп нь дэлгэц хуваах тохиргоог дэмждэггүй."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Апп дэлгэцийг хуваах горимтой ажиллахгүй байж магадгүй"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Апп дэлгэцийг хуваах горимыг дэмждэггүй"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Энэ аппыг зөвхөн 1 цонхонд нээх боломжтой."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апп хоёрдогч дэлгэцэд ажиллахгүй."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Аппыг хоёрдогч дэлгэцэд эхлүүлэх боломжгүй."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"\"Дэлгэц хуваах\" хуваагч"</string>
- <string name="divider_title" msgid="5482989479865361192">"\"Дэлгэцийг хуваах\" хуваагч"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Дэлгэцийг хуваах хуваагч"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Дэлгэцийг хуваах хуваагч"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Зүүн талын бүтэн дэлгэц"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Зүүн 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Зүүн 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Дээд 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Дээд 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Доод бүтэн дэлгэц"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Зүүн талд хуваах"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Баруун талд хуваах"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Дээд талд хуваах"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Доод талд хуваах"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Нэг гарын горимыг ашиглаж байна"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Гарахын тулд дэлгэцийн доод хэсгээс дээш шударч эсвэл апп дээр хүссэн газраа товшино уу"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Нэг гарын горимыг эхлүүлэх"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Үүнийг засаагүй юу?\nБуцаахын тулд товшино уу"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерын асуудал байхгүй юу? Хаахын тулд товшино уу."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Харж илүү ихийг хий"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Дэлгэцийг хуваахын тулд өөр апп руу чирнэ үү"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Дэлгэц хуваах горимд ашиглахын тулд өөр аппыг чирнэ үү"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Аппыг дахин байрлуулахын тулд гадна талд нь хоёр товшино"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ойлголоо"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Нэмэлт мэдээлэл авах бол дэлгэнэ үү."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Цуцлах"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Дахин эхлүүлэх"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Дахиж бүү харуул"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Энэ аппыг зөөхийн тулд\nхоёр товшино уу"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Томруулах"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Багасгах"</string>
<string name="close_button_text" msgid="2913281996024033299">"Хаах"</string>
<string name="back_button_text" msgid="1469718707134137085">"Буцах"</string>
<string name="handle_text" msgid="1766582106752184456">"Бариул"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Aппын дүрс тэмдэг"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Бүтэн дэлгэц"</string>
<string name="desktop_text" msgid="1077633567027630454">"Дэлгэцийн горим"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Дэлгэцийг хуваах"</string>
<string name="more_button_text" msgid="3655388105592893530">"Бусад"</string>
<string name="float_button_text" msgid="9221657008391364581">"Хөвөгч"</string>
+ <string name="select_text" msgid="5139083974039906583">"Сонгох"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Дэлгэцийн агшин"</string>
+ <string name="close_text" msgid="4986518933445178928">"Хаах"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Цэс нээх"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 4e29c11b2299..a9e6319a2110 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदला"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"स्टॅश करा"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्टॅश करा"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"अ‍ॅप कदाचित स्प्लिट स्क्रीनसह काम करू शकत नाही."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अ‍ॅप स्क्रीन-विभाजनास समर्थन देत नाही."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"अ‍ॅप कदाचित स्प्लिट स्क्रीनसह काम करणार नाही"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"अ‍ॅप हे स्प्लिट स्क्रीनला सपोर्ट करत नाही"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"हे अ‍ॅप फक्त एका विंडोमध्ये उघडले जाऊ शकते."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"दुसऱ्या डिस्प्लेवर अ‍ॅप कदाचित चालणार नाही."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"दुसऱ्या डिस्प्लेवर अ‍ॅप लाँच होणार नाही."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रीन विभाजक"</string>
- <string name="divider_title" msgid="5482989479865361192">"स्प्लिट-स्क्रीन विभाजक"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"स्प्लिट स्क्रीन विभाजक"</string>
+ <string name="divider_title" msgid="1963391955593749442">"स्प्लिट स्क्रीन विभाजक"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"डावी फुल स्क्रीन"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"डावी 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"डावी 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"शीर्ष 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"शीर्ष 10"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"तळाशी फुल स्क्रीन"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"डावीकडे स्प्लिट करा"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"उजवीकडे स्प्लिट करा"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"सर्वात वरती स्प्लिट करा"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"खालती स्प्लिट करा"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"एकहाती मोड वापरणे"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"बाहेर पडण्यासाठी स्क्रीनच्या खालून वरच्या दिशेने स्वाइप करा किंवा ॲपवर कोठेही टॅप करा"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"एकहाती मोड सुरू करा"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"निराकरण झाले नाही?\nरिव्हर्ट करण्यासाठी कृपया टॅप करा"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"कॅमेराशी संबंधित कोणत्याही समस्या नाहीत का? डिसमिस करण्‍यासाठी टॅप करा."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पहा आणि आणखी बरेच काही करा"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"स्प्लिट-स्क्रीन वापरण्यासाठी दुसऱ्या ॲपमध्ये ड्रॅग करा"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप ड्रॅग करा"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ॲपची स्थिती पुन्हा बदलण्यासाठी, त्याच्या बाहेर दोनदा टॅप करा"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"समजले"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"अधिक माहितीसाठी विस्तार करा."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"रद्द करा"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"रीस्टार्ट करा"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"पुन्हा दाखवू नका"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"हे ॲप हलवण्यासाठी\nदोनदा टॅप करा"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"मोठे करा"</string>
<string name="minimize_button_text" msgid="271592547935841753">"लहान करा"</string>
<string name="close_button_text" msgid="2913281996024033299">"बंद करा"</string>
<string name="back_button_text" msgid="1469718707134137085">"मागे जा"</string>
<string name="handle_text" msgid="1766582106752184456">"हँडल"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"अ‍ॅप आयकन"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"फुलस्‍क्रीन"</string>
<string name="desktop_text" msgid="1077633567027630454">"डेस्कटॉप मोड"</string>
<string name="split_screen_text" msgid="1396336058129570886">"स्प्लिट स्क्रीन"</string>
<string name="more_button_text" msgid="3655388105592893530">"आणखी"</string>
<string name="float_button_text" msgid="9221657008391364581">"फ्लोट"</string>
+ <string name="select_text" msgid="5139083974039906583">"निवडा"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"स्क्रीनशॉट"</string>
+ <string name="close_text" msgid="4986518933445178928">"बंद करा"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"मेनू उघडा"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
index 8a8977979217..89654d0a5750 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
@@ -24,7 +24,7 @@
<string name="pip_move" msgid="158770205886688553">"हलवा"</string>
<string name="pip_expand" msgid="1051966011679297308">"विस्तार करा"</string>
<string name="pip_collapse" msgid="3903295106641385962">"कोलॅप्स करा"</string>
- <string name="pip_edu_text" msgid="7930546669915337998">"नियंत्रणांसाठी "<annotation icon="home_icon">"होम"</annotation>" दोनदा दाबा"</string>
+ <string name="pip_edu_text" msgid="7930546669915337998">"नियंत्रणांसाठी "<annotation icon="home_icon">"होम"</annotation>" दोनदा प्रेस करा"</string>
<string name="a11y_pip_menu_entered" msgid="5106343214776801614">"चित्रात-चित्र मेनू."</string>
<string name="a11y_action_pip_move_left" msgid="6612980937817141583">"डावीकडे हलवा"</string>
<string name="a11y_action_pip_move_right" msgid="1119409122645529936">"उजवीकडे हलवा"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 27844728b8aa..b47531711863 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah saiz"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Sembunyikan"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Tunjukkan"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Apl mungkin tidak berfungsi dengan skrin pisah."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Apl tidak menyokong skrin pisah."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Apl mungkin tidak berfungsi dengan skrin pisah"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Apl tidak menyokong skrin pisah"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Apl ini hanya boleh dibuka dalam 1 tetingkap."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Apl mungkin tidak berfungsi pada paparan kedua."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Apl tidak menyokong pelancaran pada paparan kedua."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Pembahagi skrin pisah"</string>
- <string name="divider_title" msgid="5482989479865361192">"Pembahagi skrin pisah"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Pembahagi skrin pisah"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Pembahagi skrin pisah"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Skrin penuh kiri"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kiri 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Atas 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Skrin penuh bawah"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Pisah kiri"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Pisah kanan"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Pisah atas"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Pisah bawah"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Menggunakan mod sebelah tangan"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Untuk keluar, leret ke atas daripada bahagian bawah skrin atau ketik pada mana-mana di bahagian atas apl"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Mulakan mod sebelah tangan"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Isu tidak dibetulkan?\nKetik untuk kembali"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tiada isu kamera? Ketik untuk mengetepikan."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Seret apl lain untuk skrin pisah"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Seret masuk apl lain untuk menggunakan skrin pisah"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketik dua kali di luar apl untuk menempatkan semula apl itu"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kembangkan untuk mendapatkan maklumat lanjut."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Batal"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Mulakan semula"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Jangan tunjukkan lagi"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ketik dua kali untuk\nalih apl ini"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimumkan"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimumkan"</string>
<string name="close_button_text" msgid="2913281996024033299">"Tutup"</string>
<string name="back_button_text" msgid="1469718707134137085">"Kembali"</string>
<string name="handle_text" msgid="1766582106752184456">"Pemegang"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikon Apl"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Skrin penuh"</string>
<string name="desktop_text" msgid="1077633567027630454">"Mod Desktop"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Skrin Pisah"</string>
<string name="more_button_text" msgid="3655388105592893530">"Lagi"</string>
<string name="float_button_text" msgid="9221657008391364581">"Terapung"</string>
+ <string name="select_text" msgid="5139083974039906583">"Pilih"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Tangkapan skrin"</string>
+ <string name="close_text" msgid="4986518933445178928">"Tutup"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Buka Menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 2b781069695f..cb6a1df95b33 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"အရွယ်အစားပြောင်းရန်"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"သိုဝှက်ရန်"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"မသိုဝှက်ရန်"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းဖြင့် အက်ပ်သည် အလုပ်မလုပ်ပါ။"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"အက်ပ်သည် မျက်နှာပြင်ခွဲပြရန် ပံ့ပိုးထားခြင်းမရှိပါ။"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းဖြင့် အက်ပ်သည် အလုပ်မလုပ်ပါ"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"အက်ပ်တွင် မျက်နှာပြင် ခွဲ၍ပြသခြင်းကို မပံ့ပိုးပါ"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ဤအက်ပ်ကို ဝင်းဒိုး ၁ ခုတွင်သာ ဖွင့်နိုင်သည်။"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ဤအက်ပ်အနေဖြင့် ဒုတိယဖန်သားပြင်ပေါ်တွင် အလုပ်လုပ်မည် မဟုတ်ပါ။"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ဤအက်ပ်အနေဖြင့် ဖွင့်ရန်စနစ်ကို ဒုတိယဖန်သားပြင်မှ အသုံးပြုရန် ပံ့ပိုးမထားပါ။"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"မျက်နှာပြင်ခွဲခြမ်း ပိုင်းခြားပေးသည့်စနစ်"</string>
- <string name="divider_title" msgid="5482989479865361192">"မျက်နှာပြင်ခွဲ၍ပြသသည့် စနစ်"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း ပိုင်းခြားစနစ်"</string>
+ <string name="divider_title" msgid="1963391955593749442">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း ပိုင်းခြားစနစ်"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ဘယ်ဘက် မျက်နှာပြင်အပြည့်"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ဘယ်ဘက်မျက်နှာပြင် ၇၀%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ဘယ်ဘက် မျက်နှာပြင် ၅၀%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"အပေါ်ဘက် မျက်နှာပြင် ၅၀%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"အပေါ်ဘက် မျက်နှာပြင် ၃၀%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"အောက်ခြေ မျက်နှာပြင်အပြည့်"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"ဘယ်ဘက်ကို ခွဲရန်"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"ညာဘက်ကို ခွဲရန်"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"ထိပ်ပိုင်းကို ခွဲရန်"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"အောက်ခြေကို ခွဲရန်"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"လက်တစ်ဖက်သုံးမုဒ် အသုံးပြုခြင်း"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"ထွက်ရန် ဖန်သားပြင်၏အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ သို့မဟုတ် အက်ပ်အပေါ်ဘက် မည်သည့်နေရာတွင်မဆို တို့ပါ"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"လက်တစ်ဖက်သုံးမုဒ်ကို စတင်လိုက်သည်"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ကောင်းမသွားဘူးလား။\nပြန်ပြောင်းရန် တို့ပါ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ကင်မရာပြဿနာ မရှိဘူးလား။ ပယ်ရန် တို့ပါ။"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ကြည့်ပြီး ပိုမိုလုပ်ဆောင်ပါ"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"မျက်နှာပြင် ခွဲ၍ပြသနိုင်ရန် နောက်အက်ပ်တစ်ခုကို ဖိဆွဲပါ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းအတွက် အက်ပ်နောက်တစ်ခုကို ဖိဆွဲပါ"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"နေရာပြန်ချရန် အက်ပ်အပြင်ဘက်ကို နှစ်ချက်တို့ပါ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"နားလည်ပြီ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"နောက်ထပ်အချက်အလက်များအတွက် ချဲ့နိုင်သည်။"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"မလုပ်တော့"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"ပြန်စရန်"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"နောက်ထပ်မပြပါနှင့်"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ဤအက်ပ်ကို ရွှေ့ရန်\nနှစ်ချက်တို့ပါ"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ချဲ့ရန်"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ချုံ့ရန်"</string>
<string name="close_button_text" msgid="2913281996024033299">"ပိတ်ရန်"</string>
<string name="back_button_text" msgid="1469718707134137085">"နောက်သို့"</string>
<string name="handle_text" msgid="1766582106752184456">"သုံးသူအမည်"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"အက်ပ်သင်္ကေတ"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ဖန်သားပြင်အပြည့်"</string>
<string name="desktop_text" msgid="1077633567027630454">"ဒက်စ်တော့မုဒ်"</string>
<string name="split_screen_text" msgid="1396336058129570886">"မျက်နှာပြင် ခွဲ၍ပြသရန်"</string>
<string name="more_button_text" msgid="3655388105592893530">"ပိုပြပါ"</string>
<string name="float_button_text" msgid="9221657008391364581">"မျှောရန်"</string>
+ <string name="select_text" msgid="5139083974039906583">"ရွေးရန်"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
+ <string name="close_text" msgid="4986518933445178928">"ပိတ်ရန်"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"မီနူး ဖွင့်ရန်"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 3e7c63a53bfc..6c80144fee18 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Endre størrelse"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Oppbevar"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Avslutt oppbevaring"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Det kan hende at appen ikke fungerer med delt skjerm."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen støtter ikke delt skjerm."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Det kan hende at appen ikke fungerer med delt skjerm"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Appen støtter ikke delt skjerm"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Denne appen kan bare åpnes i ett vindu."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer kanskje ikke på en sekundær skjerm."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke kjøres på sekundære skjermer."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Skilleelement for delt skjerm"</string>
- <string name="divider_title" msgid="5482989479865361192">"Skilleelement for delt skjerm"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Skilleelement for delt skjerm"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Skilleelement for delt skjerm"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Utvid den venstre delen av skjermen til hele skjermen"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Sett størrelsen på den venstre delen av skjermen til 70 %"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sett størrelsen på den venstre delen av skjermen til 50 %"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Sett størrelsen på den øverste delen av skjermen til 50 %"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Sett størrelsen på den øverste delen av skjermen til 30 %"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Utvid den nederste delen av skjermen til hele skjermen"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Del opp til venstre"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Del opp til høyre"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Del opp øverst"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Del opp nederst"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bruk av enhåndsmodus"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"For å avslutte, sveip opp fra bunnen av skjermen eller trykk hvor som helst over appen"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Start enhåndsmodus"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen kameraproblemer? Trykk for å lukke."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gjør mer"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Dra inn en annen app for å bruke delt skjerm"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Dra inn en annen app for å bruke delt skjerm"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dobbelttrykk utenfor en app for å flytte den"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Greit"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vis for å få mer informasjon."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Avbryt"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Start på nytt"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ikke vis dette igjen"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dobbelttrykk for\nå flytte denne appen"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimer"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string>
<string name="close_button_text" msgid="2913281996024033299">"Lukk"</string>
<string name="back_button_text" msgid="1469718707134137085">"Tilbake"</string>
<string name="handle_text" msgid="1766582106752184456">"Håndtak"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Fullskjerm"</string>
<string name="desktop_text" msgid="1077633567027630454">"Skrivebordmodus"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Delt skjerm"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mer"</string>
<string name="float_button_text" msgid="9221657008391364581">"Svevende"</string>
+ <string name="select_text" msgid="5139083974039906583">"Velg"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Skjermdump"</string>
+ <string name="close_text" msgid="4986518933445178928">"Lukk"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Åpne menyen"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 1865ee5b5102..f9f580530f8b 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदल्नुहोस्"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"स्ट्यास गर्नुहोस्"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्ट्यास गर्नुहोस्"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"एप विभाजित स्क्रिनमा काम नगर्न सक्छ।"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"यो एपले स्प्लिट स्क्रिन मोडमा काम नगर्न सक्छ"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"यो एप स्प्लिट स्क्रिन मोडमा प्रयोग गर्न मिल्दैन"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"यो एप एउटा विन्डोमा मात्र खोल्न मिल्छ।"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो एपले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"अनुप्रयोगले सहायक प्रदर्शनहरूमा लञ्च सुविधालाई समर्थन गर्दैन।"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रिन छुट्याउने"</string>
- <string name="divider_title" msgid="5482989479865361192">"स्प्लिट स्क्रिन डिभाइडर"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"स्प्लिट स्क्रिन डिभाइडर"</string>
+ <string name="divider_title" msgid="1963391955593749442">"स्प्लिट स्क्रिन डिभाइडर"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बायाँ भाग फुल स्क्रिन"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"बायाँ भाग ७०%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बायाँ भाग ५०%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"माथिल्लो भाग ५०%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"माथिल्लो भाग ३०%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"तल्लो भाग फुल स्क्रिन"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"बायाँतिर स्प्लिट गर्नुहोस्"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"दायाँतिर स्प्लिट गर्नुहोस्"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"सिरानतिर स्प्लिट गर्नुहोस्"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"पुछारतिर स्प्लिट गर्नुहोस्"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"एक हाते मोड प्रयोग गरिँदै छ"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"बाहिर निस्कन, स्क्रिनको पुछारबाट माथितिर स्वाइप गर्नुहोस् वा एपभन्दा माथि जुनसुकै ठाउँमा ट्याप गर्नुहोस्"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"एक हाते मोड सुरु गर्नुहोस्"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"समस्या हल भएन?\nपहिलेको जस्तै बनाउन ट्याप गर्नुहोस्"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्यामेरासम्बन्धी कुनै पनि समस्या छैन? खारेज गर्न ट्याप गर्नुहोस्।"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"थप कुरा हेर्नुहोस् र गर्नुहोस्"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"स्प्लिट स्क्रिन मोड प्रयोग गर्न अर्को एप ड्रयाग एन्ड ड्रप गर्नुहोस्"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"स्प्लिट स्क्रिन मोड प्रयोग गर्न अर्को एप ड्रयाग एन्ड ड्रप गर्नुहोस्"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"तपाईं जुन एपको स्थिति मिलाउन चाहनुहुन्छ सोही एपको बाहिर डबल ट्याप गर्नुहोस्"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"बुझेँ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"थप जानकारी प्राप्त गर्न चाहनुहुन्छ भने एक्स्पान्ड गर्नुहोस्।"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"रद्द गर्नुहोस्"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"रिस्टार्ट गर्नुहोस्"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"फेरि नदेखाइयोस्"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"यो एप सार्न डबल\nट्याप गर्नुहोस्"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ठुलो बनाउनुहोस्"</string>
<string name="minimize_button_text" msgid="271592547935841753">"मिनिमाइज गर्नुहोस्"</string>
<string name="close_button_text" msgid="2913281996024033299">"बन्द गर्नुहोस्"</string>
<string name="back_button_text" msgid="1469718707134137085">"पछाडि"</string>
<string name="handle_text" msgid="1766582106752184456">"ह्यान्डल"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"एपको आइकन"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"फुल स्क्रिन"</string>
<string name="desktop_text" msgid="1077633567027630454">"डेस्कटप मोड"</string>
<string name="split_screen_text" msgid="1396336058129570886">"स्प्लिट स्क्रिन"</string>
<string name="more_button_text" msgid="3655388105592893530">"थप"</string>
<string name="float_button_text" msgid="9221657008391364581">"फ्लोट"</string>
+ <string name="select_text" msgid="5139083974039906583">"चयन गर्नुहोस्"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"स्क्रिनसट"</string>
+ <string name="close_text" msgid="4986518933445178928">"बन्द गर्नुहोस्"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"मेनु खोल्नुहोस्"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 91437ac2302f..3064cccba7cc 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Formaat aanpassen"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Verbergen"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Niet meer verbergen"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"De app werkt mogelijk niet met gesplitst scherm."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App biedt geen ondersteuning voor gesplitst scherm."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"De app werkt misschien niet met gesplitst scherm"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"App ondersteunt geen gesplitst scherm"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Deze app kan slechts in 1 venster worden geopend."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App werkt mogelijk niet op een secundair scherm."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App kan niet op secundaire displays worden gestart."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Scheiding voor gesplitst scherm"</string>
- <string name="divider_title" msgid="5482989479865361192">"Scheiding voor gesplitst scherm"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Scheiding voor gesplitst scherm"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Scheiding voor gesplitst scherm"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Linkerscherm op volledig scherm"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Linkerscherm 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Linkerscherm 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bovenste scherm 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Bovenste scherm 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Onderste scherm op volledig scherm"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Gesplitst scherm links"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Gesplitst scherm rechts"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Gesplitst scherm boven"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Gesplitst scherm onder"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bediening met 1 hand gebruiken"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Als je wilt afsluiten, swipe je omhoog vanaf de onderkant van het scherm of tik je ergens boven de app"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bediening met 1 hand starten"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Is dit geen oplossing?\nTik om terug te zetten."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen cameraproblemen? Tik om te sluiten."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zie en doe meer"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Sleep een andere app hier naartoe om het scherm te splitsen"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Sleep een andere app hier naartoe om het scherm te splitsen"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik naast een app om deze opnieuw te positioneren"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Uitvouwen voor meer informatie."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuleren"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Opnieuw opstarten"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Niet opnieuw tonen"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dubbeltik om\ndeze app te verplaatsen"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximaliseren"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimaliseren"</string>
<string name="close_button_text" msgid="2913281996024033299">"Sluiten"</string>
<string name="back_button_text" msgid="1469718707134137085">"Terug"</string>
<string name="handle_text" msgid="1766582106752184456">"Gebruikersnaam"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"App-icoon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Volledig scherm"</string>
<string name="desktop_text" msgid="1077633567027630454">"Desktopmodus"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Gesplitst scherm"</string>
<string name="more_button_text" msgid="3655388105592893530">"Meer"</string>
<string name="float_button_text" msgid="9221657008391364581">"Zwevend"</string>
+ <string name="select_text" msgid="5139083974039906583">"Selecteren"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Sluiten"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Menu openen"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index d330749c82d3..267b8a38a6d7 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -26,19 +26,19 @@
<string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> \"ଛବି-ଭିତରେ-ଛବି\"ରେ ଅଛି"</string>
<string name="pip_notification_message" msgid="8854051911700302620">"ଏହି ବୈଶିଷ୍ଟ୍ୟ <xliff:g id="NAME">%s</xliff:g> ବ୍ୟବହାର ନକରିବାକୁ ଯଦି ଆପଣ ଚାହାଁନ୍ତି, ସେଟିଙ୍ଗ ଖୋଲିବାକୁ ଟାପ୍‍ କରନ୍ତୁ ଏବଂ ଏହା ଅଫ୍‍ କରିଦିଅନ୍ତୁ।"</string>
<string name="pip_play" msgid="3496151081459417097">"ପ୍ଲେ କରନ୍ତୁ"</string>
- <string name="pip_pause" msgid="690688849510295232">"ପଜ୍‍ କରନ୍ତୁ"</string>
+ <string name="pip_pause" msgid="690688849510295232">"ବିରତ କରନ୍ତୁ"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"ପରବର୍ତ୍ତୀକୁ ଯାଆନ୍ତୁ"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"ପୂର୍ବବର୍ତ୍ତୀକୁ ଛାଡ଼ନ୍ତୁ"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ରିସାଇଜ୍ କରନ୍ତୁ"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ଲୁଚାନ୍ତୁ"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ଦେଖାନ୍ତୁ"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରିନରେ ଆପ୍ କାମ କରିନପାରେ।"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ଆପ୍‍ ସ୍ପ୍ଲିଟ୍‍-ସ୍କ୍ରୀନକୁ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନରେ ଆପ କାମ କରିନପାରେ"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ଆପ ସମର୍ଥନ କରେ ନାହିଁ"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ଏହି ଆପକୁ କେବଳ 1ଟି ୱିଣ୍ଡୋରେ ଖୋଲାଯାଇପାରିବ।"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍‍ କାମ ନକରିପାରେ।"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍‍ ଲଞ୍ଚ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"ସ୍ପ୍ଲିଟ୍‍-ସ୍କ୍ରୀନ ବିଭାଜକ"</string>
- <string name="divider_title" msgid="5482989479865361192">"ସ୍ପ୍ଲିଟ-ସ୍କ୍ରିନ ଡିଭାଇଡର"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ଡିଭାଇଡର"</string>
+ <string name="divider_title" msgid="1963391955593749442">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ଡିଭାଇଡର"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ବାମ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍ କରନ୍ତୁ"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ବାମ ପଟକୁ 70% କରନ୍ତୁ"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ବାମ ପଟକୁ 50% କରନ୍ତୁ"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ଉପର ଆଡ଼କୁ 50% କରନ୍ତୁ"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ଉପର ଆଡ଼କୁ 30% କରନ୍ତୁ"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ତଳ ଅଂଶର ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"ବାମପଟକୁ ସ୍ପ୍ଲିଟ କରନ୍ତୁ"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"ଡାହାଣପଟକୁ ସ୍ପ୍ଲିଟ କରନ୍ତୁ"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"ଶୀର୍ଷକୁ ସ୍ପ୍ଲିଟ କରନ୍ତୁ"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"ନିମ୍ନକୁ ସ୍ଲିଟ କରନ୍ତୁ"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"ଏକ-ହାତ ମୋଡ୍ ବ୍ୟବହାର କରି"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"ବାହାରି ଯିବା ପାଇଁ, ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ କିମ୍ବା ଆପରେ ଯେ କୌଣସି ସ୍ଥାନରେ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ଏକ-ହାତ ମୋଡ୍ ଆରମ୍ଭ କରନ୍ତୁ"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ଏହାର ସମାଧାନ ହୋଇନାହିଁ?\nଫେରିଯିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"କ୍ୟାମେରାରେ କିଛି ସମସ୍ୟା ନାହିଁ? ଖାରଜ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ଦେଖନ୍ତୁ ଏବଂ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ସ୍ପ୍ଲିଟ-ସ୍କ୍ରିନ ପାଇଁ ଅନ୍ୟ ଏକ ଆପକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ପାଇଁ ଅନ୍ୟ ଏକ ଆପକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ଏକ ଆପକୁ ରିପୋଜିସନ କରିବା ପାଇଁ ଏହାର ବାହାରେ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ବୁଝିଗଲି"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ଅଧିକ ସୂଚନା ପାଇଁ ବିସ୍ତାର କରନ୍ତୁ।"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"ବାତିଲ କରନ୍ତୁ"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ଏହି ଆପକୁ ମୁଭ\nକରିବା ପାଇଁ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ବଡ଼ କରନ୍ତୁ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ଛୋଟ କରନ୍ତୁ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="back_button_text" msgid="1469718707134137085">"ପଛକୁ ଫେରନ୍ତୁ"</string>
<string name="handle_text" msgid="1766582106752184456">"ହେଣ୍ଡେଲ"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ଆପ ଆଇକନ"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ପୂର୍ଣ୍ଣସ୍କ୍ରିନ"</string>
<string name="desktop_text" msgid="1077633567027630454">"ଡେସ୍କଟପ ମୋଡ"</string>
<string name="split_screen_text" msgid="1396336058129570886">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ"</string>
<string name="more_button_text" msgid="3655388105592893530">"ଅଧିକ"</string>
<string name="float_button_text" msgid="9221657008391364581">"ଫ୍ଲୋଟ"</string>
+ <string name="select_text" msgid="5139083974039906583">"ଚୟନ କରନ୍ତୁ"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"ସ୍କ୍ରିନସଟ"</string>
+ <string name="close_text" msgid="4986518933445178928">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"ମେନୁ ଖୋଲନ୍ତୁ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 51d491b50c40..d9f7f340a889 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ਆਕਾਰ ਬਦਲੋ"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ਸਟੈਸ਼"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ਅਣਸਟੈਸ਼"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"ਐਪ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ਇਹ ਐਪ ਸਿਰਫ਼ 1 ਵਿੰਡੋ ਵਿੱਚ ਖੋਲ੍ਹੀ ਜਾ ਸਕਦੀ ਹੈ।"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇ \'ਤੇ ਕੰਮ ਨਾ ਕਰੇ।"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇਆਂ \'ਤੇ ਲਾਂਚ ਕਰਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਡਿਵਾਈਡਰ"</string>
- <string name="divider_title" msgid="5482989479865361192">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਵਿਭਾਜਕ"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਿਭਾਜਕ"</string>
+ <string name="divider_title" msgid="1963391955593749442">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਿਭਾਜਕ"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ਖੱਬੇ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ਖੱਬੇ 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ਖੱਬੇ 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ਉੱਪਰ 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ਉੱਪਰ 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ਹੇਠਾਂ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"ਖੱਬੇ ਪਾਸੇ ਵੰਡੋ"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"ਸੱਜੇ ਪਾਸੇ ਵੰਡੋ"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"ਸਿਖਰ \'ਤੇ ਵੰਡੋ"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"ਹੇਠਾਂ ਵੰਡੋ"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"ਇੱਕ ਹੱਥ ਮੋਡ ਵਰਤਣਾ"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"ਬਾਹਰ ਜਾਣ ਲਈ, ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ ਜਾਂ ਐਪ \'ਤੇ ਕਿਤੇ ਵੀ ਟੈਪ ਕਰੋ"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ਇੱਕ ਹੱਥ ਮੋਡ ਸ਼ੁਰੂ ਕਰੋ"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ਕੀ ਇਹ ਠੀਕ ਨਹੀਂ ਹੋਈ?\nਵਾਪਸ ਉਹੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਹੈ? ਖਾਰਜ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ਦੇਖੋ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਕਰੋ"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੇ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਵਿੱਚ ਘਸੀਟੋ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੇ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਵਿੱਚ ਘਸੀਟੋ"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ਕਿਸੇ ਐਪ ਦੀ ਜਗ੍ਹਾ ਬਦਲਣ ਲਈ ਉਸ ਦੇ ਬਾਹਰ ਡਬਲ ਟੈਪ ਕਰੋ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ਸਮਝ ਲਿਆ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਵਿਸਤਾਰ ਕਰੋ।"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"ਰੱਦ ਕਰੋ"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ਇਸ ਐਪ ਦਾ ਟਿਕਾਣਾ ਬਦਲਣ ਲਈ\nਡਬਲ ਟੈਪ ਕਰੋ"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ਵੱਡਾ ਕਰੋ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ਛੋਟਾ ਕਰੋ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ਬੰਦ ਕਰੋ"</string>
<string name="back_button_text" msgid="1469718707134137085">"ਪਿੱਛੇ"</string>
<string name="handle_text" msgid="1766582106752184456">"ਹੈਂਡਲ"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ਐਪ ਪ੍ਰਤੀਕ"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ਪੂਰੀ-ਸਕ੍ਰੀਨ"</string>
<string name="desktop_text" msgid="1077633567027630454">"ਡੈਸਕਟਾਪ ਮੋਡ"</string>
<string name="split_screen_text" msgid="1396336058129570886">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string>
<string name="more_button_text" msgid="3655388105592893530">"ਹੋਰ"</string>
<string name="float_button_text" msgid="9221657008391364581">"ਫ਼ਲੋਟ"</string>
+ <string name="select_text" msgid="5139083974039906583">"ਚੁਣੋ"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
+ <string name="close_text" msgid="4986518933445178928">"ਬੰਦ ਕਰੋ"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"ਮੀਨੂ ਬੰਦ ਕਰੋ"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"ਮੀਨੂ ਖੋਲ੍ਹੋ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 32e9840ac791..0699f5df99ab 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmień rozmiar"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Przenieś do schowka"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zabierz ze schowka"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacja może nie działać przy podzielonym ekranie."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacja nie obsługuje dzielonego ekranu."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Aplikacja może nie działać przy podzielonym ekranie"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikacja nie obsługuje podzielonego ekranu"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ta aplikacja może być otwarta tylko w 1 oknie."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacja może nie działać na dodatkowym ekranie."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacja nie obsługuje uruchamiania na dodatkowych ekranach."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Linia dzielenia ekranu"</string>
- <string name="divider_title" msgid="5482989479865361192">"Linia dzielenia ekranu"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Linia dzielenia ekranu"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Linia dzielenia ekranu"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lewa część ekranu na pełnym ekranie"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% lewej części ekranu"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% lewej części ekranu"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% górnej części ekranu"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% górnej części ekranu"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Dolna część ekranu na pełnym ekranie"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Podziel po lewej"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Podziel po prawej"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Podziel u góry"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Podziel u dołu"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Korzystanie z trybu jednej ręki"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Aby zamknąć, przesuń palcem z dołu ekranu w górę lub kliknij dowolne miejsce nad aplikacją"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Uruchom tryb jednej ręki"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Naprawa się nie udała?\nKliknij, aby cofnąć"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Brak problemów z aparatem? Kliknij, aby zamknąć"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobacz i zrób więcej"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Przeciągnij drugą aplikację, aby podzielić ekran"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Aby podzielić ekran, przeciągnij drugą aplikację"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kliknij dwukrotnie poza aplikacją, aby ją przenieść"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozwiń, aby wyświetlić więcej informacji."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Anuluj"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Uruchom ponownie"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nie pokazuj ponownie"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Aby przenieść aplikację,\nkliknij dwukrotnie"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksymalizuj"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimalizuj"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zamknij"</string>
<string name="back_button_text" msgid="1469718707134137085">"Wstecz"</string>
<string name="handle_text" msgid="1766582106752184456">"Uchwyt"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacji"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pełny ekran"</string>
<string name="desktop_text" msgid="1077633567027630454">"Tryb pulpitu"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Podzielony ekran"</string>
<string name="more_button_text" msgid="3655388105592893530">"Więcej"</string>
<string name="float_button_text" msgid="9221657008391364581">"Pływające"</string>
+ <string name="select_text" msgid="5139083974039906583">"Wybierz"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Zrzut ekranu"</string>
+ <string name="close_text" msgid="4986518933445178928">"Zamknij"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Zamknij menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Otwórz menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 1a29af24587a..eea9be26f432 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ocultar"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Exibir"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"É possível que o app não funcione com a tela dividida"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"O app não oferece suporte à divisão de tela"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Este app só pode ser aberto em uma única janela."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"O app não é compatível com a inicialização em telas secundárias."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Divisor de tela"</string>
- <string name="divider_title" msgid="5482989479865361192">"Divisor de tela"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Divisor de tela"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Divisor de tela"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lado esquerdo em tela cheia"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Esquerda a 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Parte superior a 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Parte inferior em tela cheia"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Dividir para a esquerda"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Dividir para a direita"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Dividir para cima"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Dividir para baixo"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Como usar o modo para uma mão"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para sair, deslize de baixo para cima na tela ou toque em qualquer lugar acima do app"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar o modo para uma mão"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arraste outro app para a tela dividida"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outro app para dividir a tela"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes para\nmover o app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fechar"</string>
<string name="back_button_text" msgid="1469718707134137085">"Voltar"</string>
<string name="handle_text" msgid="1766582106752184456">"Alça"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string>
<string name="desktop_text" msgid="1077633567027630454">"Modo área de trabalho"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mais"</string>
<string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string>
+ <string name="select_text" msgid="5139083974039906583">"Selecionar"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Captura de tela"</string>
+ <string name="close_text" msgid="4986518933445178928">"Fechar"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Abrir o menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index b2d8e0809b99..a3d6ce5a4c5a 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -24,7 +24,7 @@
<string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
<string name="pip_menu_accessibility_title" msgid="8129016817688656249">"Menu de ecrã no ecrã"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"A app <xliff:g id="NAME">%s</xliff:g> está no modo de ecrã no ecrã"</string>
- <string name="pip_notification_message" msgid="8854051911700302620">"Se não pretende que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Se não quer que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
<string name="pip_play" msgid="3496151081459417097">"Reproduzir"</string>
<string name="pip_pause" msgid="690688849510295232">"Pausar"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"Mudar para o seguinte"</string>
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Armazenar"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Remover do armazenamento"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"A app pode não funcionar com o ecrã dividido."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A app não é compatível com o ecrã dividido."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"A app pode não funcionar com o ecrã dividido"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"A app não é compatível com o ecrã dividido"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta app só pode ser aberta em 1 janela."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"A app pode não funcionar num ecrã secundário."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"A app não é compatível com o início em ecrãs secundários."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Divisor do ecrã dividido"</string>
- <string name="divider_title" msgid="5482989479865361192">"Divisor do ecrã dividido"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Divisor do ecrã dividido"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Divisor do ecrã dividido"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ecrã esquerdo inteiro"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% no ecrã esquerdo"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% no ecrã esquerdo"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% no ecrã superior"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% no ecrã superior"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ecrã inferior inteiro"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Divisão à esquerda"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Divisão à direita"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Divisão na parte superior"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Divisão na parte inferior"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utilize o modo para uma mão"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para sair, deslize rapidamente para cima a partir da parte inferior do ecrã ou toque em qualquer ponto acima da app."</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar o modo para uma mão"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Balão"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerir"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão ignorado."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Toque para reiniciar esta app e ficar com uma melhor visão."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Toque para reiniciar esta app e ver melhor."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmara?\nToque aqui para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nenhum problema com a câmara? Toque para ignorar."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arraste outra app para usar o ecrã dividido"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outra app para usar o ecrã dividido"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de uma app para a reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expandir para obter mais informações"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar de novo"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes\npara mover esta app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fechar"</string>
<string name="back_button_text" msgid="1469718707134137085">"Anterior"</string>
<string name="handle_text" msgid="1766582106752184456">"Indicador"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ícone da app"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Ecrã inteiro"</string>
<string name="desktop_text" msgid="1077633567027630454">"Modo de ambiente de trabalho"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Ecrã dividido"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mais"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flutuar"</string>
+ <string name="select_text" msgid="5139083974039906583">"Selecionar"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Captura de ecrã"</string>
+ <string name="close_text" msgid="4986518933445178928">"Fechar"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Abrir menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 1a29af24587a..eea9be26f432 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ocultar"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Exibir"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"É possível que o app não funcione com a tela dividida"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"O app não oferece suporte à divisão de tela"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Este app só pode ser aberto em uma única janela."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"O app não é compatível com a inicialização em telas secundárias."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Divisor de tela"</string>
- <string name="divider_title" msgid="5482989479865361192">"Divisor de tela"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Divisor de tela"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Divisor de tela"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lado esquerdo em tela cheia"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Esquerda a 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Parte superior a 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Parte inferior em tela cheia"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Dividir para a esquerda"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Dividir para a direita"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Dividir para cima"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Dividir para baixo"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Como usar o modo para uma mão"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para sair, deslize de baixo para cima na tela ou toque em qualquer lugar acima do app"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar o modo para uma mão"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arraste outro app para a tela dividida"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outro app para dividir a tela"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes para\nmover o app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fechar"</string>
<string name="back_button_text" msgid="1469718707134137085">"Voltar"</string>
<string name="handle_text" msgid="1766582106752184456">"Alça"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string>
<string name="desktop_text" msgid="1077633567027630454">"Modo área de trabalho"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mais"</string>
<string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string>
+ <string name="select_text" msgid="5139083974039906583">"Selecionar"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Captura de tela"</string>
+ <string name="close_text" msgid="4986518933445178928">"Fechar"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Abrir o menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 8f609791f20b..58ad60a87982 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionează"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stochează"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Anulează stocarea"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplicația nu acceptă ecranul împărțit."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplicația nu acceptă ecranul împărțit"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aplicația poate fi deschisă într-o singură fereastră."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Este posibil ca aplicația să nu funcționeze pe un ecran secundar."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplicația nu acceptă lansare pe ecrane secundare."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Separator pentru ecranul împărțit"</string>
- <string name="divider_title" msgid="5482989479865361192">"Separator pentru ecranul împărțit"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Separator pentru ecranul împărțit"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Separator pentru ecranul împărțit"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Partea stângă pe ecran complet"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Partea stângă: 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Partea stângă: 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Partea de sus: 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Partea de sus: 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Partea de jos pe ecran complet"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Împarte în stânga"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Împarte în dreapta"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Împarte în sus"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Împarte în jos"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Folosirea modului cu o mână"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pentru a ieși, glisează în sus din partea de jos a ecranului sau atinge oriunde deasupra ferestrei aplicației"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Activează modul cu o mână"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionează"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balonul a fost respins."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Atinge ca să repornești aplicația pentru o vizualizare mai bună."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Atinge ca să repornești aplicația pentru o afișare mai bună."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Ai probleme cu camera foto?\nAtinge pentru a reîncadra"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ai remediat problema?\nAtinge pentru a reveni"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu ai probleme cu camera foto? Atinge pentru a închide."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vezi și fă mai multe"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Trage în altă aplicație pentru a folosi ecranul împărțit"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Trage în altă aplicație pentru a folosi ecranul împărțit"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Atinge de două ori lângă o aplicație pentru a o repoziționa"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Extinde pentru mai multe informații"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Anulează"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Repornește"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nu mai afișa"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Atinge de două ori\nca să muți aplicația"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizează"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizează"</string>
<string name="close_button_text" msgid="2913281996024033299">"Închide"</string>
<string name="back_button_text" msgid="1469718707134137085">"Înapoi"</string>
<string name="handle_text" msgid="1766582106752184456">"Ghidaj"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Pictograma aplicației"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Ecran complet"</string>
<string name="desktop_text" msgid="1077633567027630454">"Modul desktop"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Ecran împărțit"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mai multe"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flotantă"</string>
+ <string name="select_text" msgid="5139083974039906583">"Selectează"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Captură de ecran"</string>
+ <string name="close_text" msgid="4986518933445178928">"Închide"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Închide meniul"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Deschide meniul"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 0c1e4a9ad351..a7db44dda901 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Изменить размер"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Скрыть"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показать"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"В режиме разделения экрана приложение может работать нестабильно."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложение не поддерживает разделение экрана."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Когда включено разделение экрана, приложение может работать нестабильно."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Приложение не поддерживает разделение экрана."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Это приложение можно открыть только в одном окне."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Приложение может не работать на дополнительном экране"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Приложение не поддерживает запуск на дополнительных экранах"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Разделитель экрана"</string>
- <string name="divider_title" msgid="5482989479865361192">"Разделитель экрана"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Разделитель экрана"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Разделитель экрана"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левый во весь экран"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Левый на 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левый на 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхний на 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Верхний на 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Нижний во весь экран"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Приложение слева"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Приложение справа"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Приложение сверху"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Приложение снизу"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Использование режима управления одной рукой"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Чтобы выйти, проведите по экрану снизу вверх или коснитесь области за пределами приложения."</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Запустить режим управления одной рукой"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не помогло?\nНажмите, чтобы отменить изменения."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нет проблем с камерой? Нажмите, чтобы закрыть."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Выполняйте несколько задач одновременно"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Перетащите сюда другое приложение, чтобы использовать разделение экрана."</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Перетащите сюда другое приложение, чтобы использовать разделение экрана."</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Чтобы переместить приложение, дважды нажмите рядом с ним."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОК"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Развернуть, чтобы узнать больше."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Отмена"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Перезапустить"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Больше не показывать"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Дважды нажмите, чтобы\nпереместить приложение."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Развернуть"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Свернуть"</string>
<string name="close_button_text" msgid="2913281996024033299">"Закрыть"</string>
<string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
<string name="handle_text" msgid="1766582106752184456">"Маркер"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Значок приложения"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Полноэкранный режим"</string>
<string name="desktop_text" msgid="1077633567027630454">"Режим компьютера"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Разделить экран"</string>
<string name="more_button_text" msgid="3655388105592893530">"Ещё"</string>
<string name="float_button_text" msgid="9221657008391364581">"Плавающее окно"</string>
+ <string name="select_text" msgid="5139083974039906583">"Выбрать"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string>
+ <string name="close_text" msgid="4986518933445178928">"Закрыть"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыть меню"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Открыть меню"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 13ac51823937..4153ce2bcf1f 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ප්‍රතිප්‍රමාණ කරන්න"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"සඟවා තබන්න"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"සඟවා තැබීම ඉවත් කරන්න"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"යෙදුම බෙදුම් තිරය සමග ක්‍රියා නොකළ හැකිය"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"යෙදුම බෙදුණු-තිරය සඳහා සහාය නොදක්වයි."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"යෙදුම බෙදීම් තිරය සමග ක්‍රියා නොකළ හැක"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"යෙදුම බෙදුම් තිරයට සහාය නොදක්වයි"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"මෙම යෙදුම විවෘත කළ හැක්කේ 1 කවුළුවක පමණයි."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"යෙදුම ද්විතියික සංදර්ශකයක ක්‍රියා නොකළ හැකිය."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"යෙදුම ද්විතීයික සංදර්ශක මත දියත් කිරීම සඳහා සහාය නොදක්වයි."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"බෙදුම්-තිර වෙන්කරණය"</string>
- <string name="divider_title" msgid="5482989479865361192">"බෙදුම්-තිර වෙන්කරණය"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"බෙදුම් තිර වෙන්කරණය"</string>
+ <string name="divider_title" msgid="1963391955593749442">"බෙදුම් තිර වෙන්කරණය"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"වම් පූර්ණ තිරය"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"වම් 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"වම් 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ඉහළම 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ඉහළම 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"පහළ පූර්ණ තිරය"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"වම බෙදන්න"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"දකුණ බෙදන්න"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"ඉහළ බෙදන්න"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"පහළ බෙදන්න"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"තනි-අත් ප්‍රකාරය භාවිත කරමින්"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"පිටවීමට, තිරයේ පහළ සිට ඉහළට ස්වයිප් කරන්න හෝ යෙදුමට ඉහළින් ඕනෑම තැනක තට්ටු කරන්න"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"තනි අත් ප්‍රකාරය ආරම්භ කරන්න"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"එය විසඳුවේ නැතිද?\nප්‍රතිවර්තනය කිරීමට තට්ටු කරන්න"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"කැමරා ගැටලු නොමැතිද? ඉවත දැමීමට තට්ටු කරන්න"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"බලන්න සහ තවත් දේ කරන්න"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"බෙදුම් තිරය සඳහා වෙනත් යෙදුමකට අදින්න"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"බෙදුම් තිරය සඳහා වෙනත් යෙදුමකට අදින්න"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"යෙදුමක් නැවත ස්ථානගත කිරීමට පිටතින් දෙවරක් තට්ටු කරන්න"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"තේරුණා"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"වැඩිදුර තොරතුරු සඳහා දිග හරින්න"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"අවලංගු කරන්න"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"යළි අරඹන්න"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"නැවත නොපෙන්වන්න"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"මෙම යෙදුම ගෙන යාමට\nදෙවරක් තට්ටු කරන්න"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"විහිදන්න"</string>
<string name="minimize_button_text" msgid="271592547935841753">"කුඩා කරන්න"</string>
<string name="close_button_text" msgid="2913281996024033299">"වසන්න"</string>
<string name="back_button_text" msgid="1469718707134137085">"ආපසු"</string>
<string name="handle_text" msgid="1766582106752184456">"හැඬලය"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"යෙදුම් නිරූපකය"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"පූර්ණ තිරය"</string>
<string name="desktop_text" msgid="1077633567027630454">"ඩෙස්ක්ටොප් ප්‍රකාරය"</string>
<string name="split_screen_text" msgid="1396336058129570886">"බෙදුම් තිරය"</string>
<string name="more_button_text" msgid="3655388105592893530">"තව"</string>
<string name="float_button_text" msgid="9221657008391364581">"පාවෙන"</string>
+ <string name="select_text" msgid="5139083974039906583">"තෝරන්න"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"තිර රුව"</string>
+ <string name="close_text" msgid="4986518933445178928">"වසන්න"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"මෙනුව වසන්න"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"මෙනුව විවෘත කරන්න"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index c91856c7e383..4e38943662ea 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmeniť veľkosť"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Skryť"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušiť skrytie"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikácia nemusí fungovať s rozdelenou obrazovkou."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikácia nepodporuje rozdelenú obrazovku."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Aplikácia nemusí fungovať s rozdelenou obrazovkou"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikácia nepodporuje rozdelenú obrazovku"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Táto aplikácia môže byť otvorená iba v jednom okne."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikácia nemusí fungovať na sekundárnej obrazovke."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikácia nepodporuje spúšťanie na sekundárnych obrazovkách."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Rozdeľovač obrazovky"</string>
- <string name="divider_title" msgid="5482989479865361192">"Rozdeľovač obrazovky"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Rozdeľovač obrazovky"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Rozdeľovač obrazovky"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ľavá – na celú obrazovku"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ľavá – 70 %"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ľavá – 50 %"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Horná – 50 %"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Horná – 30 %"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Dolná – na celú obrazovku"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Rozdeliť vľavo"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Rozdeliť vpravo"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Rozdeliť hore"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Rozdeliť dole"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Používanie režimu jednej ruky"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Ukončíte potiahnutím z dolnej časti obrazovky nahor alebo klepnutím kdekoľvek nad aplikáciu"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Spustiť režim jednej ruky"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nevyriešilo sa to?\nKlepnutím sa vráťte."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemáte problémy s kamerou? Klepnutím zatvoríte."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobrazte si a zvládnite toho viac"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Rozdelenú obrazovku aktivujete presunutím ďalšie aplikácie"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Rozdelenú obrazovku môžete použiť presunutím do inej aplikácie"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikácie zmeníte jej pozíciu"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Dobre"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Po rozbalení sa dozviete viac."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Zrušiť"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Reštartovať"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Už nezobrazovať"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Túto aplikáciu\npresuniete dvojitým klepnutím"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovať"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimalizovať"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zavrieť"</string>
<string name="back_button_text" msgid="1469718707134137085">"Späť"</string>
<string name="handle_text" msgid="1766582106752184456">"Rukoväť"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikácie"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Celá obrazovka"</string>
<string name="desktop_text" msgid="1077633567027630454">"Režim počítača"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Rozdelená obrazovka"</string>
<string name="more_button_text" msgid="3655388105592893530">"Viac"</string>
<string name="float_button_text" msgid="9221657008391364581">"Plávajúce"</string>
+ <string name="select_text" msgid="5139083974039906583">"Vybrať"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Snímka obrazovky"</string>
+ <string name="close_text" msgid="4986518933445178928">"Zavrieť"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Zavrieť ponuku"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Otvoriť ponuku"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 744492ca2ea2..b0e67a771653 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Spremeni velikost"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Zakrij"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Razkrij"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija morda ne deluje v načinu razdeljenega zaslona."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podpira načina razdeljenega zaslona."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Aplikacija morda ne deluje v načinu razdeljenega zaslona."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikacija ne podpira načina razdeljenega zaslona."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"To aplikacijo je mogoče odpreti samo v enem oknu."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija morda ne bo delovala na sekundarnem zaslonu."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podpira zagona na sekundarnih zaslonih."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Razdelilnik zaslonov"</string>
- <string name="divider_title" msgid="5482989479865361192">"Razdelilnik zaslonov"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Razdelilnik zaslonov"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Razdelilnik zaslonov"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Levi v celozaslonski način"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Levi 70 %"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Levi 50 %"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Zgornji 50 %"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Zgornji 30 %"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Spodnji v celozaslonski način"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Delitev levo"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Delitev desno"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Delitev zgoraj"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Delitev spodaj"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Uporaba enoročnega načina"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Za izhod povlecite z dna zaslona navzgor ali se dotaknite na poljubnem mestu nad aplikacijo"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Zagon enoročnega načina"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"To ni odpravilo težave?\nDotaknite se za povrnitev"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nimate težav s fotoaparatom? Dotaknite se za opustitev."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Oglejte si in naredite več"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Za razdeljeni zaslon povlecite sem še eno aplikacijo."</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Za razdeljeni zaslon povlecite sem še eno aplikacijo."</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvakrat se dotaknite zunaj aplikacije, če jo želite prestaviti."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"V redu"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Razširitev za več informacij"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Prekliči"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Znova zaženi"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikaži več"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvakrat se dotaknite\nza premik te aplikacije"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimiraj"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimiraj"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zapri"</string>
<string name="back_button_text" msgid="1469718707134137085">"Nazaj"</string>
<string name="handle_text" msgid="1766582106752184456">"Ročica"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Celozaslonsko"</string>
<string name="desktop_text" msgid="1077633567027630454">"Namizni način"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Razdeljen zaslon"</string>
<string name="more_button_text" msgid="3655388105592893530">"Več"</string>
<string name="float_button_text" msgid="9221657008391364581">"Lebdeče"</string>
+ <string name="select_text" msgid="5139083974039906583">"Izberi"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Posnetek zaslona"</string>
+ <string name="close_text" msgid="4986518933445178928">"Zapri"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Zapri meni"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Odpri meni"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 9afbbbacb6a3..29bfb9268f47 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ndrysho përmasat"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Fshih"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Mos e fshih"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacioni mund të mos funksionojë me ekranin e ndarë."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacioni nuk mbështet ekranin e ndarë."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Aplikacioni mund të mos funksionojë me ekranin e ndarë"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikacioni nuk mbështet ekranin e ndarë"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ky aplikacion mund të hapet vetëm në 1 dritare."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacioni mund të mos funksionojë në një ekran dytësor."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacioni nuk mbështet nisjen në ekrane dytësore."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Ndarësi i ekranit të ndarë"</string>
- <string name="divider_title" msgid="5482989479865361192">"Ndarësi i ekranit të ndarë"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Ndarësi i ekranit të ndarë"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Ndarësi i ekranit të ndarë"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ekrani i plotë majtas"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Majtas 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Majtas 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Lart 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Lart 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ekrani i plotë poshtë"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Ndaj majtas"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Ndaj djathtas"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Ndaj lart"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Ndaj në fund"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Po përdor modalitetin e përdorimit me një dorë"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Për të dalë, rrëshqit lart nga fundi i ekranit ose trokit diku mbi aplikacion"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Modaliteti i përdorimit me një dorë"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nuk u rregullua?\nTrokit për ta rikthyer"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nuk ka probleme me kamerën? Trokit për ta shpërfillur."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Shiko dhe bëj më shumë"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Zvarrite në një aplikacion tjetër për ekranin e ndarë"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Zvarrite në një aplikacion tjetër për ekranin e ndarë"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Trokit dy herë jashtë një aplikacioni për ta ripozicionuar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"E kuptova"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Zgjeroje për më shumë informacion."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Anulo"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Rinis"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Mos e shfaq përsëri"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Trokit dy herë për të\nlëvizur këtë aplikacion"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimizo"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizo"</string>
<string name="close_button_text" msgid="2913281996024033299">"Mbyll"</string>
<string name="back_button_text" msgid="1469718707134137085">"Pas"</string>
<string name="handle_text" msgid="1766582106752184456">"Emërtimi"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ikona e aplikacionit"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Ekrani i plotë"</string>
<string name="desktop_text" msgid="1077633567027630454">"Modaliteti i desktopit"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Ekrani i ndarë"</string>
<string name="more_button_text" msgid="3655388105592893530">"Më shumë"</string>
<string name="float_button_text" msgid="9221657008391364581">"Pluskuese"</string>
+ <string name="select_text" msgid="5139083974039906583">"Zgjidh"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Pamja e ekranit"</string>
+ <string name="close_text" msgid="4986518933445178928">"Mbyll"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Hap menynë"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index c252fd7d8962..85798cf9f784 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промените величину"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ставите у тајну меморију"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Уклоните из тајне меморије"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Апликација можда неће радити са подељеним екраном."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликација не подржава подељени екран."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Апликација можда неће радити са подељеним екраном."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Апликација не подржава подељени екран."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ова апликација може да се отвори само у једном прозору."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликација можда неће функционисати на секундарном екрану."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Апликација не подржава покретање на секундарним екранима."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Разделник подељеног екрана"</string>
- <string name="divider_title" msgid="5482989479865361192">"Разделник подељеног екрана"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Разделник подељеног екрана"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Разделник подељеног екрана"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Режим целог екрана за леви екран"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Леви екран 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Леви екран 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горњи екран 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Горњи екран 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Режим целог екрана за доњи екран"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Поделите лево"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Поделите десно"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Поделите у врху"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Поделите у дну"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Коришћење режима једном руком"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Да бисте изашли, превуците нагоре од дна екрана или додирните било где изнад апликације"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Покрените режим једном руком"</string>
@@ -88,23 +84,30 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблем није решен?\nДодирните да бисте вратили"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немате проблема са камером? Додирните да бисте одбацили."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Видите и урадите више"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Превуците другу апликацију да бисте користили подељени екран"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Превуците другу апликацију да бисте користили подељени екран"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двапут додирните изван апликације да бисте променили њену позицију"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Важи"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширите за још информација."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Желите ли да рестартујете ради бољег приказа?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Можете да рестартујете апликацију да би изгледала боље на екрану, с тим што можете да изгубите оно што сте урадили или несачуване промене, ако их има"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Можете да рестартујете апликацију да би изгледала боље на екрану, али можете да изгубите напредак или несачуване промене"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Откажи"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартуј"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Не приказуј поново"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Двапут додирните да бисте\nпреместили ову апликацију"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Увећајте"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Умањите"</string>
<string name="close_button_text" msgid="2913281996024033299">"Затворите"</string>
<string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
<string name="handle_text" msgid="1766582106752184456">"Идентификатор"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Икона апликације"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Преко целог екрана"</string>
<string name="desktop_text" msgid="1077633567027630454">"Режим за рачунаре"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Подељени екран"</string>
<string name="more_button_text" msgid="3655388105592893530">"Још"</string>
<string name="float_button_text" msgid="9221657008391364581">"Плутајуће"</string>
+ <string name="select_text" msgid="5139083974039906583">"Изаберите"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Снимак екрана"</string>
+ <string name="close_text" msgid="4986518933445178928">"Затворите"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Отворите мени"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 92622cb92a70..33652cd74fda 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ändra storlek"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Utför stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Återställ stash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Appen kanske inte fungerar med delad skärm."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen har inte stöd för delad skärm."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Appen kanske inte fungerar med delad skärm"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Appen har inte stöd för delad skärm"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Denna app kan bara vara öppen i ett fönster."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen kanske inte fungerar på en sekundär skärm."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan inte köras på en sekundär skärm."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Avdelare för delad skärm"</string>
- <string name="divider_title" msgid="5482989479865361192">"Avdelare för delad skärm"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Avdelare för delad skärm"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Avdelare för delad skärm"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Helskärm på vänster skärm"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vänster 70 %"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vänster 50 %"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Övre 50 %"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Övre 30 %"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Helskärm på nedre skärm"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Till vänster på delad skärm"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Till höger på delad skärm"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Upptill på delad skärm"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Nedtill på delad skärm"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Använda enhandsläge"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Avsluta genom att svepa uppåt från skärmens nederkant eller trycka ovanför appen"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Starta enhandsläge"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Löstes inte problemet?\nTryck för att återställa"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Inga problem med kameran? Tryck för att ignorera."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se och gör mer"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Dra till en annan app för läget Delad skärm"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Dra till en annan app för att dela upp skärmen"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryck snabbt två gånger utanför en app för att flytta den"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Utöka för mer information."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Avbryt"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Starta om"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Visa inte igen"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tryck snabbt två gånger\nför att flytta denna app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Utöka"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimera"</string>
<string name="close_button_text" msgid="2913281996024033299">"Stäng"</string>
<string name="back_button_text" msgid="1469718707134137085">"Tillbaka"</string>
<string name="handle_text" msgid="1766582106752184456">"Handtag"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Helskärm"</string>
<string name="desktop_text" msgid="1077633567027630454">"Datorläge"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Delad skärm"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mer"</string>
<string name="float_button_text" msgid="9221657008391364581">"Svävande"</string>
+ <string name="select_text" msgid="5139083974039906583">"Välj"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Skärmbild"</string>
+ <string name="close_text" msgid="4986518933445178928">"Stäng"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Stäng menyn"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Öppna menyn"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 6d92040b7933..fe2ad1f1846d 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Badilisha ukubwa"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ficha"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Fichua"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Huenda programu isifanye kazi kwenye skrini inayogawanywa."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programu haiwezi kutumia skrini iliyogawanywa."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Huenda programu isifanye kazi kwenye skrini iliyogawanywa"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Programu haifanyi kazi kwenye skrini iliyogawanywa"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Programu hii inaweza kufunguliwa katika dirisha 1 pekee."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Huenda programu isifanye kazi kwenye dirisha lingine."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Programu hii haiwezi kufunguliwa kwenye madirisha mengine."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Kitenganishi cha skrini inayogawanywa"</string>
- <string name="divider_title" msgid="5482989479865361192">"Kitenganishi cha kugawa skrini"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Kitenganishi cha kugawa skrini"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Kitenganishi cha kugawa skrini"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Skrini nzima ya kushoto"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kushoto 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kushoto 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Juu 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Juu 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Skrini nzima ya chini"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Gawanya sehemu ya kushoto"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Gawanya sehemu ya kulia"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Gawanya sehemu ya juu"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Gawanya sehemu ya chini"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Kutumia hali ya kutumia kwa mkono mmoja"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Ili ufunge, telezesha kidole juu kutoka sehemu ya chini ya skrini au uguse mahali popote juu ya programu"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Anzisha hali ya kutumia kwa mkono mmoja"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Umeshindwa kurekebisha?\nGusa ili urejeshe nakala ya awali"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Je, hakuna hitilafu za kamera? Gusa ili uondoe."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Angalia na ufanye zaidi"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Buruta ndani programu nyingine ili utumie hali ya skrini iliyogawanywa"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Buruta katika programu nyingine ili utumie skrini iliyogawanywa"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Gusa mara mbili nje ya programu ili uihamishe"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Nimeelewa"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Panua ili upate maelezo zaidi."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Ghairi"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Zima kisha uwashe"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Usionyeshe tena"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Gusa mara mbili ili\nusogeze programu hii"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Panua"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Punguza"</string>
<string name="close_button_text" msgid="2913281996024033299">"Funga"</string>
<string name="back_button_text" msgid="1469718707134137085">"Rudi nyuma"</string>
<string name="handle_text" msgid="1766582106752184456">"Ncha"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Aikoni ya Programu"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Skrini nzima"</string>
<string name="desktop_text" msgid="1077633567027630454">"Hali ya Kompyuta ya mezani"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Gawa Skrini"</string>
<string name="more_button_text" msgid="3655388105592893530">"Zaidi"</string>
<string name="float_button_text" msgid="9221657008391364581">"Inayoelea"</string>
+ <string name="select_text" msgid="5139083974039906583">"Chagua"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Picha ya skrini"</string>
+ <string name="close_text" msgid="4986518933445178928">"Funga"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Funga Menyu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Fungua Menyu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 8cf631b5355d..5bb4c27ed6c7 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"அளவு மாற்று"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"திரைப் பிரிப்பு அம்சத்தில் ஆப்ஸ் செயல்படாமல் போகக்கூடும்."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"திரையைப் பிரிப்பதைப் ஆப்ஸ் ஆதரிக்கவில்லை."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"திரைப் பிரிப்புப் பயன்முறையில் ஆப்ஸ் செயல்படாமல் போகக்கூடும்"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"திரைப் பிரிப்புப் பயன்முறையை ஆப்ஸ் ஆதரிக்காது"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"இந்த ஆப்ஸை 1 சாளரத்தில் மட்டுமே திறக்க முடியும்."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"இரண்டாம்நிலைத் திரையில் ஆப்ஸ் வேலை செய்யாமல் போகக்கூடும்."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"இரண்டாம்நிலைத் திரைகளில் பயன்பாட்டைத் தொடங்க முடியாது."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"திரையைப் பிரிக்கும் பிரிப்பான்"</string>
- <string name="divider_title" msgid="5482989479865361192">"திரைப் பிரிப்பான்"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"திரைப் பிரிப்பான்"</string>
+ <string name="divider_title" msgid="1963391955593749442">"திரைப் பிரிப்பான்"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"இடது புறம் முழுத் திரை"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"இடது புறம் 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"இடது புறம் 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"மேலே 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"மேலே 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"கீழ்ப்புறம் முழுத் திரை"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"இடதுபுறமாகப் பிரிக்கும்"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"வலதுபுறமாகப் பிரிக்கும்"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"மேற்புறமாகப் பிரிக்கும்"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"கீழ்புறமாகப் பிரிக்கும்"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"ஒற்றைக் கைப் பயன்முறையைப் பயன்படுத்துதல்"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"வெளியேற, திரையின் கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்யவும் அல்லது ஆப்ஸுக்கு மேலே ஏதேனும் ஓர் இடத்தில் தட்டவும்"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ஒற்றைக் கைப் பயன்முறையைத் தொடங்கும்"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"பபிள்"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"நிர்வகி"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"குமிழ் நிராகரிக்கப்பட்டது."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"இங்கு தட்டுவதன் மூலம் இந்த ஆப்ஸை மீண்டும் தொடங்கி, ஆப்ஸ் காட்டப்படும் விதத்தை இன்னும் சிறப்பாக்கலாம்."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"இங்கு தட்டி ஆப்ஸை மீண்டும் தொடங்கி, ஆப்ஸ் காட்சியை இன்னும் சிறப்பாக்கலாம்."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"கேமரா தொடர்பான சிக்கல்களா?\nமீண்டும் பொருத்த தட்டவும்"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமாற்றியமைக்க தட்டவும்"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"கேமரா தொடர்பான சிக்கல்கள் எதுவும் இல்லையா? நிராகரிக்க தட்டவும்."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"பலவற்றைப் பார்த்தல் மற்றும் செய்தல்"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"திரைப் பிரிப்புக்கு மற்றொரு ஆப்ஸை இழுக்கலாம்"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"திரைப் பிரிப்புக்கு மற்றொரு ஆப்ஸை இழுக்கலாம்"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ஆப்ஸை இடம் மாற்ற அதன் வெளியில் இருமுறை தட்டலாம்"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"சரி"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"கூடுதல் தகவல்களுக்கு விரிவாக்கலாம்."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"ரத்துசெய்"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"மீண்டும் தொடங்கு"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"மீண்டும் காட்டாதே"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"இந்த ஆப்ஸை நகர்த்த\nஇருமுறை தட்டவும்"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"பெரிதாக்கும்"</string>
<string name="minimize_button_text" msgid="271592547935841753">"சிறிதாக்கும்"</string>
<string name="close_button_text" msgid="2913281996024033299">"மூடும்"</string>
<string name="back_button_text" msgid="1469718707134137085">"பின்செல்லும்"</string>
<string name="handle_text" msgid="1766582106752184456">"ஹேண்டில்"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ஆப்ஸ் ஐகான்"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"முழுத்திரை"</string>
<string name="desktop_text" msgid="1077633567027630454">"டெஸ்க்டாப் பயன்முறை"</string>
<string name="split_screen_text" msgid="1396336058129570886">"திரையைப் பிரிக்கும்"</string>
<string name="more_button_text" msgid="3655388105592893530">"கூடுதல் விருப்பத்தேர்வுகள்"</string>
<string name="float_button_text" msgid="9221657008391364581">"மிதக்கும் சாளரம்"</string>
+ <string name="select_text" msgid="5139083974039906583">"தேர்ந்தெடுக்கும்"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"ஸ்கிரீன்ஷாட்"</string>
+ <string name="close_text" msgid="4986518933445178928">"மூடும்"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"மெனுவை மூடும்"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"மெனுவைத் திற"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index a4dcd950f321..6f95aa9c8305 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"సైజ్‌ మార్చు"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"స్టాచ్"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ఆన్‌స్టాచ్"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"స్క్రీన్ విభజనతో యాప్‌ పని చేయకపోవచ్చు."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"యాప్‌లో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"స్ప్లిట్ స్క్రీన్‌తో యాప్ పని చేయకపోవచ్చు"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"యాప్‌లో స్ప్లిట్ స్క్రీన్‌కు సపోర్ట్ లేదు"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ఈ యాప్‌ను 1 విండోలో మాత్రమే తెరవవచ్చు."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ప్రత్యామ్నాయ డిస్‌ప్లేలో యాప్ పని చేయకపోవచ్చు."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ప్రత్యామ్నాయ డిస్‌ప్లేల్లో ప్రారంభానికి యాప్ మద్దతు లేదు."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"విభజన స్క్రీన్ విభాగిని"</string>
- <string name="divider_title" msgid="5482989479865361192">"స్ప్లిట్ స్క్రీన్ డివైడర్"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"స్ప్లిట్ స్క్రీన్ డివైడర్"</string>
+ <string name="divider_title" msgid="1963391955593749442">"స్ప్లిట్ స్క్రీన్ డివైడర్"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ఎడమవైపు ఫుల్-స్క్రీన్‌"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ఎడమవైపు 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ఎడమవైపు 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ఎగువ 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ఎగువ 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"దిగువ ఫుల్-స్క్రీన్‌"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"ఎడమ వైపున్న భాగంలో విభజించండి"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"కుడి వైపున్న భాగంలో విభజించండి"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"ఎగువ భాగంలో విభజించండి"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"దిగువ భాగంలో విభజించండి"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"వన్-హ్యాండెడ్ మోడ్‌ను ఉపయోగించడం"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"నిష్క్రమించడానికి, స్క్రీన్ కింది భాగం నుండి పైకి స్వైప్ చేయండి లేదా యాప్ పైన ఎక్కడైనా ట్యాప్ చేయండి"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"వన్-హ్యాండెడ్ మోడ్‌ను ప్రారంభిస్తుంది"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"దాని సమస్యను పరిష్కరించలేదా?\nపూర్వస్థితికి మార్చడానికి ట్యాప్ చేయండి"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"కెమెరా సమస్యలు లేవా? తీసివేయడానికి ట్యాప్ చేయండి."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"చూసి, మరిన్ని చేయండి"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"స్ప్లిట్-స్క్రీన్ కోసం మరొక యాప్‌లోకి లాగండి"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"స్ప్లిట్ స్క్రీన్ కోసం మరొక యాప్‌లోకి లాగండి"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"యాప్ స్థానాన్ని మార్చడానికి దాని వెలుపల డబుల్-ట్యాప్ చేయండి"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"అర్థమైంది"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"మరింత సమాచారం కోసం విస్తరించండి."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"రద్దు చేయండి"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"రీస్టార్ట్ చేయండి"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"మళ్లీ చూపవద్దు"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ఈ యాప్‌ను తరలించడానికి\nడబుల్-ట్యాప్ చేయండి"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"గరిష్టీకరించండి"</string>
<string name="minimize_button_text" msgid="271592547935841753">"కుదించండి"</string>
<string name="close_button_text" msgid="2913281996024033299">"మూసివేయండి"</string>
<string name="back_button_text" msgid="1469718707134137085">"వెనుకకు"</string>
<string name="handle_text" msgid="1766582106752184456">"హ్యాండిల్"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"యాప్ చిహ్నం"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ఫుల్-స్క్రీన్"</string>
<string name="desktop_text" msgid="1077633567027630454">"డెస్క్‌టాప్ మోడ్"</string>
<string name="split_screen_text" msgid="1396336058129570886">"స్ప్లిట్ స్క్రీన్"</string>
<string name="more_button_text" msgid="3655388105592893530">"మరిన్ని"</string>
<string name="float_button_text" msgid="9221657008391364581">"ఫ్లోట్"</string>
+ <string name="select_text" msgid="5139083974039906583">"ఎంచుకోండి"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"స్క్రీన్‌షాట్"</string>
+ <string name="close_text" msgid="4986518933445178928">"మూసివేయండి"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"మెనూను మూసివేయండి"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"మెనూను తెరవండి"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 1e900d8ad81f..6733940fd445 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ปรับขนาด"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"เก็บเข้าที่เก็บส่วนตัว"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"เอาออกจากที่เก็บส่วนตัว"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"แอปอาจใช้ไม่ได้กับโหมดแบ่งหน้าจอ"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"แอปไม่สนับสนุนการแยกหน้าจอ"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"แอปอาจใช้ไม่ได้กับโหมดแยกหน้าจอ"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"แอปไม่รองรับการแยกหน้าจอ"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"แอปนี้เปิดได้ใน 1 หน้าต่างเท่านั้น"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"แอปอาจไม่ทำงานในจอแสดงผลรอง"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"แอปไม่รองรับการเรียกใช้ในจอแสดงผลรอง"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"เส้นแบ่งหน้าจอ"</string>
- <string name="divider_title" msgid="5482989479865361192">"เส้นแยกหน้าจอ"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"เส้นแยกหน้าจอ"</string>
+ <string name="divider_title" msgid="1963391955593749442">"เส้นแยกหน้าจอ"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"เต็มหน้าจอทางซ้าย"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ซ้าย 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ซ้าย 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ด้านบน 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ด้านบน 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"เต็มหน้าจอด้านล่าง"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"แยกไปทางซ้าย"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"แยกไปทางขวา"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"แยกไปด้านบน"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"แยกไปด้านล่าง"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"การใช้โหมดมือเดียว"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"หากต้องการออก ให้เลื่อนขึ้นจากด้านล่างของหน้าจอหรือแตะที่ใดก็ได้เหนือแอป"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"เริ่มโหมดมือเดียว"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"หากไม่ได้แก้ไข\nแตะเพื่อเปลี่ยนกลับ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"หากไม่พบปัญหากับกล้อง แตะเพื่อปิด"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"รับชมและทำสิ่งต่างๆ ได้มากขึ้น"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ลากไปไว้ในแอปอื่นเพื่อแยกหน้าจอ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ลากไปไว้ในแอปอื่นเพื่อแยกหน้าจอ"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"แตะสองครั้งด้านนอกแอปเพื่อเปลี่ยนตำแหน่ง"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"รับทราบ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ขยายเพื่อดูข้อมูลเพิ่มเติม"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"ยกเลิก"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"รีสตาร์ท"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ไม่ต้องแสดงข้อความนี้อีก"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"แตะสองครั้ง\nเพื่อย้ายแอปนี้"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ขยายใหญ่สุด"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ย่อ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ปิด"</string>
<string name="back_button_text" msgid="1469718707134137085">"กลับ"</string>
<string name="handle_text" msgid="1766582106752184456">"แฮนเดิล"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ไอคอนแอป"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"เต็มหน้าจอ"</string>
<string name="desktop_text" msgid="1077633567027630454">"โหมดเดสก์ท็อป"</string>
<string name="split_screen_text" msgid="1396336058129570886">"แยกหน้าจอ"</string>
<string name="more_button_text" msgid="3655388105592893530">"เพิ่มเติม"</string>
<string name="float_button_text" msgid="9221657008391364581">"ล่องลอย"</string>
+ <string name="select_text" msgid="5139083974039906583">"เลือก"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"ภาพหน้าจอ"</string>
+ <string name="close_text" msgid="4986518933445178928">"ปิด"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"เปิดเมนู"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 8d5d0ed7b8da..8cf4eb484378 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"I-resize"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"I-stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"I-unstash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Posibleng hindi gumana ang app sa split screen."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Hindi sinusuportahan ng app ang split-screen."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Posibleng hindi gumana sa split screen ang app"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Hindi sinusuportahan ng app ang split-screen"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Sa 1 window lang puwedeng buksan ang app na ito."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Maaaring hindi gumana ang app sa pangalawang display."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Hindi sinusuportahan ng app ang paglulunsad sa mga pangalawang display."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Divider ng split-screen"</string>
- <string name="divider_title" msgid="5482989479865361192">"Divider ng split-screen"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Divider ng split screen"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Divider ng split screen"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"I-full screen ang nasa kaliwa"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Gawing 70% ang nasa kaliwa"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Gawing 50% ang nasa kaliwa"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gawing 50% ang nasa itaas"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gawing 30% ang nasa itaas"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"I-full screen ang nasa ibaba"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Hatiin sa kaliwa"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Hatiin sa kanan"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Hatiin sa itaas"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Hatiin sa ilalim"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Paggamit ng one-hand mode"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para lumabas, mag-swipe pataas mula sa ibaba ng screen o mag-tap kahit saan sa itaas ng app"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Simulan ang one-hand mode"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Hindi ito naayos?\nI-tap para i-revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Walang isyu sa camera? I-tap para i-dismiss."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Tumingin at gumawa ng higit pa"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Mag-drag ng ibang app para sa split screen"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Mag-drag ng isa pang app para sa split screen"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Mag-double tap sa labas ng app para baguhin ang posisyon nito"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"I-expand para sa higit pang impormasyon."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Kanselahin"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"I-restart"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Huwag nang ipakita ulit"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"I-double tap para\nilipat ang app na ito"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"I-maximize"</string>
<string name="minimize_button_text" msgid="271592547935841753">"I-minimize"</string>
<string name="close_button_text" msgid="2913281996024033299">"Isara"</string>
<string name="back_button_text" msgid="1469718707134137085">"Bumalik"</string>
<string name="handle_text" msgid="1766582106752184456">"Handle"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Icon ng App"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string>
<string name="desktop_text" msgid="1077633567027630454">"Desktop Mode"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Split Screen"</string>
<string name="more_button_text" msgid="3655388105592893530">"Higit pa"</string>
<string name="float_button_text" msgid="9221657008391364581">"Float"</string>
+ <string name="select_text" msgid="5139083974039906583">"Piliin"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Isara"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Buksan ang Menu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 341d8f113943..1454435b3de7 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Yeniden boyutlandır"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Depola"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Depolama"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Uygulama bölünmüş ekranda çalışmayabilir."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uygulama bölünmüş ekranı desteklemiyor."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Uygulama bölünmüş ekranda çalışmayabilir"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Uygulama bölünmüş ekranı desteklemiyor."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Bu uygulama yalnızca 1 pencerede açılabilir."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uygulama ikincil ekranda çalışmayabilir."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Uygulama ikincil ekranlarda başlatılmayı desteklemiyor."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Bölünmüş ekran ayırıcı"</string>
- <string name="divider_title" msgid="5482989479865361192">"Bölünmüş ekran ayırıcı"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Bölünmüş ekran ayırıcı"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Bölünmüş ekran ayırıcı"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Solda tam ekran"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Solda %70"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Solda %50"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Üstte %50"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Üstte %30"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Altta tam ekran"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Sol tarafta böl"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Sağ tarafta böl"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Üst tarafta böl"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Alt tarafta böl"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Tek el modunu kullanma"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Çıkmak için ekranın alt kısmından yukarı kaydırın veya uygulamanın üzerinde herhangi bir yere dokunun"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Tek el modunu başlat"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bu işlem sorunu düzeltmedi mi?\nİşlemi geri almak için dokunun"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kameranızda sorun yok mu? Kapatmak için dokunun."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daha fazlasını görün ve yapın"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Bölünmüş ekran için başka bir uygulamayı sürükleyin"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Bölünmüş ekran için başka bir uygulamayı sürükleyin"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Yeniden konumlandırmak için uygulamanın dışına iki kez dokunun"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Daha fazla bilgi için genişletin."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"İptal"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Yeniden başlat"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Bir daha gösterme"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Bu uygulamayı taşımak için\niki kez dokunun"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Ekranı Kapla"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Küçült"</string>
<string name="close_button_text" msgid="2913281996024033299">"Kapat"</string>
<string name="back_button_text" msgid="1469718707134137085">"Geri"</string>
<string name="handle_text" msgid="1766582106752184456">"Herkese açık kullanıcı adı"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Uygulama Simgesi"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Tam Ekran"</string>
<string name="desktop_text" msgid="1077633567027630454">"Masaüstü Modu"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Bölünmüş Ekran"</string>
<string name="more_button_text" msgid="3655388105592893530">"Daha Fazla"</string>
<string name="float_button_text" msgid="9221657008391364581">"Havada Süzülen"</string>
+ <string name="select_text" msgid="5139083974039906583">"Seç"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Ekran görüntüsü"</string>
+ <string name="close_text" msgid="4986518933445178928">"Kapat"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Menüyü kapat"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Menüyü Aç"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 5b017c653e4a..78df129d8f50 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змінити розмір"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сховати"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показати"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Додаток може не працювати в режимі розділеного екрана."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Додаток не підтримує розділення екрана."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Додаток може не працювати в режимі розділення екрана"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Додаток не підтримує розділення екрана"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Цей додаток можна відкрити лише в одному вікні."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Додаток може не працювати на додатковому екрані."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Додаток не підтримує запуск на додаткових екранах."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Розділювач екрана"</string>
- <string name="divider_title" msgid="5482989479865361192">"Розділювач екрана"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Розділювач екрана"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Розділювач екрана"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ліве вікно на весь екран"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ліве вікно на 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ліве вікно на 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхнє вікно на 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Верхнє вікно на 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Нижнє вікно на весь екран"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Розділити зліва"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Розділити справа"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Розділити вгорі"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Розділити внизу"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Як користуватися режимом керування однією рукою"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Щоб вийти, проведіть пальцем по екрану знизу вгору або торкніться екрана над додатком"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Увімкнути режим керування однією рукою"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблему не вирішено?\nНатисніть, щоб скасувати зміни"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немає проблем із камерою? Торкніться, щоб закрити."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Більше простору та можливостей"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Щоб перейти в режим розділення екрана, перетягніть сюди інший додаток"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Щоб перейти в режим розділення екрана, перетягніть сюди інший додаток"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Щоб перемістити додаток, двічі торкніться області поза ним"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Розгорніть, щоб дізнатися більше."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Скасувати"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Перезапустити"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Більше не показувати"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Двічі торкніться, щоб\nперемістити цей додаток"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Збільшити"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Згорнути"</string>
<string name="close_button_text" msgid="2913281996024033299">"Закрити"</string>
<string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
<string name="handle_text" msgid="1766582106752184456">"Маркер"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Значок додатка"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"На весь екран"</string>
<string name="desktop_text" msgid="1077633567027630454">"Режим комп’ютера"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Розділити екран"</string>
<string name="more_button_text" msgid="3655388105592893530">"Більше"</string>
<string name="float_button_text" msgid="9221657008391364581">"Плаваюче вікно"</string>
+ <string name="select_text" msgid="5139083974039906583">"Вибрати"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Знімок екрана"</string>
+ <string name="close_text" msgid="4986518933445178928">"Закрити"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Закрити меню"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Відкрити меню"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 649356951189..ca1642488768 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -21,8 +21,8 @@
<string name="pip_phone_expand" msgid="2579292903468287504">"پھیلائیں"</string>
<string name="pip_phone_settings" msgid="5468987116750491918">"ترتیبات"</string>
<string name="pip_phone_enter_split" msgid="7042877263880641911">"اسپلٹ اسکرین تک رسائی"</string>
- <string name="pip_menu_title" msgid="5393619322111827096">"مینو"</string>
- <string name="pip_menu_accessibility_title" msgid="8129016817688656249">"تصویر میں تصویر کا مینو"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"مینیو"</string>
+ <string name="pip_menu_accessibility_title" msgid="8129016817688656249">"تصویر میں تصویر کا مینیو"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> تصویر میں تصویر میں ہے"</string>
<string name="pip_notification_message" msgid="8854051911700302620">"اگر آپ نہیں چاہتے ہیں کہ <xliff:g id="NAME">%s</xliff:g> اس خصوصیت کا استعمال کرے تو ترتیبات کھولنے کے لیے تھپتھپا کر اسے آف کرے۔"</string>
<string name="pip_play" msgid="3496151081459417097">"چلائیں"</string>
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"سائز تبدیل کریں"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن ہے کہ ایپ اسپلٹ اسکرین کے ساتھ کام نہ کرے۔"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"ممکن ہے کہ ایپ اسپلٹ اسکرین کے ساتھ کام نہ کرے"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"ایپ اسپلٹ اسکرین کو سپورٹ نہیں کرتی ہے"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"یہ ایپ صرف 1 ونڈو میں کھولی جا سکتی ہے۔"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن ہے ایپ ثانوی ڈسپلے پر کام نہ کرے۔"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ایپ ثانوی ڈسپلیز پر شروعات کا تعاون نہیں کرتی۔"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"سپلٹ اسکرین تقسیم کار"</string>
- <string name="divider_title" msgid="5482989479865361192">"اسپلٹ اسکرین ڈیوائیڈر"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"اسپلٹ اسکرین ڈیوائیڈر"</string>
+ <string name="divider_title" msgid="1963391955593749442">"اسپلٹ اسکرین ڈیوائیڈر"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"بائیں فل اسکرین"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"بائیں %70"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"بائیں %50"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"اوپر %50"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"اوپر %30"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"نچلی فل اسکرین"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"دائیں طرف تقسیم کریں"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"بائیں طرف تقسیم کریں"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"اوپر کی طرف تقسیم کریں"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"نیچے کی طرف تقسیم کریں"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"ایک ہاتھ کی وضع کا استعمال کرنا"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"باہر نکلنے کیلئے، اسکرین کے نیچے سے اوپر کی طرف سوائپ کریں یا ایپ کے اوپر کہیں بھی تھپتھپائیں"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ایک ہاتھ کی وضع شروع کریں"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"یہ حل نہیں ہوا؟\nلوٹانے کیلئے تھپتھپائیں"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"کوئی کیمرے کا مسئلہ نہیں ہے؟ برخاست کرنے کیلئے تھپتھپائیں۔"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"دیکھیں اور بہت کچھ کریں"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"اسپلٹ اسکرین کے ليے دوسری ایپ میں گھسیٹیں"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"اسپلٹ اسکرین کے ليے دوسری ایپ میں گھسیٹیں"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"کسی ایپ کی پوزیشن تبدیل کرنے کے لیے اس ایپ کے باہر دو بار تھپتھپائیں"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"سمجھ آ گئی"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"مزید معلومات کے لیے پھیلائیں۔"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"منسوخ کریں"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"ری اسٹارٹ کریں"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"دوبارہ نہ دکھائیں"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"اس ایپ کو منتقل کرنے کیلئے\nدو بار تھپتھپائیں"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"بڑا کریں"</string>
<string name="minimize_button_text" msgid="271592547935841753">"چھوٹا کریں"</string>
<string name="close_button_text" msgid="2913281996024033299">"بند کریں"</string>
<string name="back_button_text" msgid="1469718707134137085">"پیچھے"</string>
<string name="handle_text" msgid="1766582106752184456">"ہینڈل"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"ایپ کا آئیکن"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"مکمل اسکرین"</string>
<string name="desktop_text" msgid="1077633567027630454">"ڈیسک ٹاپ موڈ"</string>
<string name="split_screen_text" msgid="1396336058129570886">"اسپلٹ اسکرین"</string>
<string name="more_button_text" msgid="3655388105592893530">"مزید"</string>
<string name="float_button_text" msgid="9221657008391364581">"فلوٹ"</string>
+ <string name="select_text" msgid="5139083974039906583">"منتخب کریں"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"اسکرین شاٹ"</string>
+ <string name="close_text" msgid="4986518933445178928">"بند کریں"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"مینیو بند کریں"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"مینو کھولیں"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
index 42b9564ff549..d0f011c0b4cf 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
@@ -25,7 +25,7 @@
<string name="pip_expand" msgid="1051966011679297308">"پھیلائیں"</string>
<string name="pip_collapse" msgid="3903295106641385962">"سکیڑیں"</string>
<string name="pip_edu_text" msgid="7930546669915337998">"کنٹرولز کے لیے "<annotation icon="home_icon">"ہوم "</annotation>" کو دو بار دبائیں"</string>
- <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"تصویر میں تصویر کا مینو۔"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"تصویر میں تصویر کا مینیو۔"</string>
<string name="a11y_action_pip_move_left" msgid="6612980937817141583">"دائیں منتقل کریں"</string>
<string name="a11y_action_pip_move_right" msgid="1119409122645529936">"بائیں منتقل کریں"</string>
<string name="a11y_action_pip_move_up" msgid="98502616918621959">"اوپر منتقل کریں"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index fdca0d61e2c4..c0dc03366cd6 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Oʻlchamini oʻzgartirish"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Berkitish"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Chiqarish"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Bu ilova ekranni ikkiga ajratish rejimini dastaklamaydi."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Bu ilova ekranni bo‘lish xususiyatini qo‘llab-quvvatlamaydi."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Bu ilovada ekranni ikkiga ajratish rejimi ishlamaydi."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Bu ilovada ekranni ikkiga ajratish ishlamaydi."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Bu ilovani faqat 1 ta oynada ochish mumkin."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Bu ilova qo‘shimcha ekranda ishlamasligi mumkin."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Bu ilova qo‘shimcha ekranlarda ishga tushmaydi."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Ekranni ikkiga bo‘lish chizig‘i"</string>
- <string name="divider_title" msgid="5482989479865361192">"Ekranni ikkiga ajratish chizigʻi"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Ekranni ikkiga ajratish chizigʻi"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Ekranni ikkiga ajratish chizigʻi"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Chapda to‘liq ekran"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Chapda 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Chapda 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Tepada 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Tepada 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pastda to‘liq ekran"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Chapga ajratish"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Oʻngga ajratish"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Yuqoriga ajratish"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Pastga ajratish"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Ixcham rejimdan foydalanish"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Chiqish uchun ekran pastidan tepaga suring yoki ilovaning tepasidagi istalgan joyga bosing."</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Ixcham rejimni ishga tushirish"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tuzatilmadimi?\nQaytarish uchun bosing"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera muammosizmi? Yopish uchun bosing."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Yana boshqa amallar"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Ekranni ikkiga ajratish uchun boshqa ilovani bu yerga torting"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Ekranni ikkiga ajratish uchun boshqa ilovani bu yerga torting"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Qayta joylash uchun ilova tashqarisiga ikki marta bosing"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Batafsil axborot olish uchun kengaytiring."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Bekor qilish"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Qaytadan"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Boshqa chiqmasin"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Bu ilovani siljitish uchun\nikki marta bosing"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Yoyish"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Kichraytirish"</string>
<string name="close_button_text" msgid="2913281996024033299">"Yopish"</string>
<string name="back_button_text" msgid="1469718707134137085">"Orqaga"</string>
<string name="handle_text" msgid="1766582106752184456">"Identifikator"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Ilova belgisi"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Butun ekran"</string>
<string name="desktop_text" msgid="1077633567027630454">"Desktop rejimi"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Ekranni ikkiga ajratish"</string>
<string name="more_button_text" msgid="3655388105592893530">"Yana"</string>
<string name="float_button_text" msgid="9221657008391364581">"Pufakli"</string>
+ <string name="select_text" msgid="5139083974039906583">"Tanlash"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Skrinshot"</string>
+ <string name="close_text" msgid="4986518933445178928">"Yopish"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Menyuni yopish"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Menyuni ochish"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 8fd25514b115..0281c1c8c396 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Đổi kích thước"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ẩn"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Hiện"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Ứng dụng có thể không hoạt động với tính năng chia đôi màn hình."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Có thể ứng dụng không dùng được chế độ chia đôi màn hình"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Ứng dụng không hỗ trợ chế độ chia đôi màn hình"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ứng dụng này chỉ có thể mở 1 cửa sổ."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Ứng dụng có thể không hoạt động trên màn hình phụ."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Ứng dụng không hỗ trợ khởi chạy trên màn hình phụ."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Bộ chia chia đôi màn hình"</string>
- <string name="divider_title" msgid="5482989479865361192">"Bộ chia màn hình"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Trình chia đôi màn hình"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Trình chia đôi màn hình"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Toàn màn hình bên trái"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Trái 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Trái 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Trên 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Trên 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Toàn màn hình phía dưới"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Chia đôi màn hình về bên trái"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Chia đôi màn hình về bên phải"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Chia đôi màn hình lên trên cùng"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Chia đôi màn hình xuống dưới cùng"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Cách dùng chế độ một tay"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Để thoát, hãy vuốt lên từ cuối màn hình hoặc nhấn vào vị trí bất kỳ phía trên ứng dụng"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bắt đầu chế độ một tay"</string>
@@ -83,12 +79,12 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bong bóng"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Quản lý"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Đã đóng bong bóng."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Nhấn để khởi động lại ứng dụng này để xem tốt hơn."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Nhấn để khởi động lại ứng dụng để có trải nghiệm xem tốt hơn."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Có vấn đề với máy ảnh?\nHãy nhấn để sửa lỗi"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bạn chưa khắc phục vấn đề?\nHãy nhấn để hủy bỏ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Không có vấn đề với máy ảnh? Hãy nhấn để đóng."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Xem và làm được nhiều việc hơn"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Kéo vào một ứng dụng khác để chia đôi màn hình"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Kéo một ứng dụng khác vào để chia đôi màn hình"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Nhấn đúp bên ngoài ứng dụng để đặt lại vị trí"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mở rộng để xem thêm thông tin."</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Huỷ"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Khởi động lại"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Không hiện lại"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Nhấn đúp để\ndi chuyển ứng dụng này"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Phóng to"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Thu nhỏ"</string>
<string name="close_button_text" msgid="2913281996024033299">"Đóng"</string>
<string name="back_button_text" msgid="1469718707134137085">"Quay lại"</string>
<string name="handle_text" msgid="1766582106752184456">"Xử lý"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Biểu tượng ứng dụng"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Toàn màn hình"</string>
<string name="desktop_text" msgid="1077633567027630454">"Chế độ máy tính"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Chia đôi màn hình"</string>
<string name="more_button_text" msgid="3655388105592893530">"Tuỳ chọn khác"</string>
<string name="float_button_text" msgid="9221657008391364581">"Nổi"</string>
+ <string name="select_text" msgid="5139083974039906583">"Chọn"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Ảnh chụp màn hình"</string>
+ <string name="close_text" msgid="4986518933445178928">"Đóng"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Đóng trình đơn"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Mở Trình đơn"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-watch/colors.xml b/libs/WindowManager/Shell/res/values-watch/colors.xml
new file mode 100644
index 000000000000..82492bf2af80
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-watch/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2020, 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.
+ */
+-->
+<resources>
+ <color name="splash_window_background_default">@color/splash_screen_bg_dark</color>
+</resources>
+
diff --git a/libs/WindowManager/Shell/res/values-watch/dimen.xml b/libs/WindowManager/Shell/res/values-watch/dimen.xml
new file mode 100644
index 000000000000..362e72cb4d2d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-watch/dimen.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 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.
+-->
+<resources>
+ <!-- The acceptable area ratio of fg icon area/bg icon area, i.e. (48 X 48) / (72 x 72) -->
+ <item type="dimen" format="float" name="splash_icon_enlarge_foreground_threshold">0.44</item>
+ <!-- Scaling factor applied to splash icons without provided background i.e. (60 / 48) -->
+ <item type="dimen" format="float" name="splash_icon_no_background_scale_factor">1.25</item>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index ba78d1b8db11..d1f50dba1ce1 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"调整大小"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"隐藏"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消隐藏"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"应用可能无法在分屏模式下正常运行。"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"应用不支持分屏。"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"应用可能无法在分屏模式下正常运行"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"应用不支持分屏"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"此应用只能在 1 个窗口中打开。"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"应用可能无法在辅显示屏上正常运行。"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"应用不支持在辅显示屏上启动。"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"分屏分隔线"</string>
- <string name="divider_title" msgid="5482989479865361192">"分屏分隔线"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"分屏分隔线"</string>
+ <string name="divider_title" msgid="1963391955593749442">"分屏分隔线"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左侧全屏"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"左侧 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左侧 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"顶部 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"顶部 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"底部全屏"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"左分屏"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"右分屏"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"上分屏"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"下分屏"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"使用单手模式"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"如需退出,请从屏幕底部向上滑动,或点按应用上方的任意位置"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"启动单手模式"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"没有解决此问题?\n点按即可恢复"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相机没有问题?点按即可忽略。"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"查看和处理更多任务"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"拖入另一个应用,即可使用分屏模式"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖入另一个应用,即可使用分屏模式"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在某个应用外连续点按两次,即可调整它的位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展开即可了解详情。"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"取消"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"重启"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不再显示"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"点按两次\n即可移动此应用"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
<string name="minimize_button_text" msgid="271592547935841753">"最小化"</string>
<string name="close_button_text" msgid="2913281996024033299">"关闭"</string>
<string name="back_button_text" msgid="1469718707134137085">"返回"</string>
<string name="handle_text" msgid="1766582106752184456">"处理"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"应用图标"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"全屏"</string>
<string name="desktop_text" msgid="1077633567027630454">"桌面模式"</string>
<string name="split_screen_text" msgid="1396336058129570886">"分屏"</string>
<string name="more_button_text" msgid="3655388105592893530">"更多"</string>
<string name="float_button_text" msgid="9221657008391364581">"悬浮"</string>
+ <string name="select_text" msgid="5139083974039906583">"选择"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"屏幕截图"</string>
+ <string name="close_text" msgid="4986518933445178928">"关闭"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"关闭菜单"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"打开菜单"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index b3bc5b694f50..3d33ecaccc38 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -24,7 +24,7 @@
<string name="pip_menu_title" msgid="5393619322111827096">"選單"</string>
<string name="pip_menu_accessibility_title" msgid="8129016817688656249">"畫中畫選單"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"「<xliff:g id="NAME">%s</xliff:g>」目前在畫中畫模式"</string>
- <string name="pip_notification_message" msgid="8854051911700302620">"如果您不想「<xliff:g id="NAME">%s</xliff:g>」使用此功能,請輕按以開啟設定,然後停用此功能。"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"如果你不想「<xliff:g id="NAME">%s</xliff:g>」使用此功能,請輕按以開啟設定,然後停用此功能。"</string>
<string name="pip_play" msgid="3496151081459417097">"播放"</string>
<string name="pip_pause" msgid="690688849510295232">"暫停"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一個"</string>
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"保護"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消保護"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"應用程式不支援分割畫面。"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"應用程式可能無法在分割螢幕中運作"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"應用程式不支援分割螢幕"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"此應用程式只可在 1 個視窗中開啟"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示屏上運作。"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"應用程式無法在次要顯示屏上啟動。"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"分割畫面分隔線"</string>
- <string name="divider_title" msgid="5482989479865361192">"分割螢幕分隔線"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"分割螢幕分隔線"</string>
+ <string name="divider_title" msgid="1963391955593749442">"分割螢幕分隔線"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左邊全螢幕"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"左邊 70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左邊 50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"頂部 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"頂部 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"底部全螢幕"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"分割左側區域"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"分割右側區域"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"分割上方區域"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"分割下方區域"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"使用單手模式"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"如要退出,請從螢幕底部向上滑動,或輕按應用程式上方的任何位置"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"開始單手模式"</string>
@@ -88,23 +84,30 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未能修正問題?\n輕按即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機冇問題?㩒一下就可以即可閂咗佢。"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"拖入另一個應用程式即可分割螢幕"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖入另一個應用程式即可分割螢幕"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕按兩下即可調整位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳情。"</string>
- <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"要重新啟動改善檢視畫面嗎?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"您可重新啟動應用程式,讓系統更新檢視畫面;但系統可能不會儲存目前進度及您作出的任何變更"</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"要重新啟動以改善檢視畫面嗎?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"你可重新啟動應用程式,讓系統更新檢視畫面;但系統可能不會儲存目前進度及你作出的任何變更"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"取消"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"重新啟動"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不要再顯示"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"輕按兩下\n即可移動此應用程式"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
<string name="minimize_button_text" msgid="271592547935841753">"最小化"</string>
<string name="close_button_text" msgid="2913281996024033299">"關閉"</string>
<string name="back_button_text" msgid="1469718707134137085">"返去"</string>
<string name="handle_text" msgid="1766582106752184456">"控點"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"全螢幕"</string>
<string name="desktop_text" msgid="1077633567027630454">"桌面模式"</string>
<string name="split_screen_text" msgid="1396336058129570886">"分割螢幕"</string>
<string name="more_button_text" msgid="3655388105592893530">"更多"</string>
<string name="float_button_text" msgid="9221657008391364581">"浮動"</string>
+ <string name="select_text" msgid="5139083974039906583">"選取"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"螢幕截圖"</string>
+ <string name="close_text" msgid="4986518933445178928">"關閉"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"打開選單"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index e7444614a4b0..4ca49e167118 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"暫時隱藏"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消暫時隱藏"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"這個應用程式不支援分割畫面。"</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"應用程式可能無法在分割畫面中運作"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"這個應用程式不支援分割畫面"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"這個應用程式只能在 1 個視窗中開啟。"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示器上運作。"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"應用程式無法在次要顯示器上啟動。"</string>
- <string name="accessibility_divider" msgid="703810061635792791">"分割畫面分隔線"</string>
- <string name="divider_title" msgid="5482989479865361192">"分割畫面分隔線"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"分割畫面分隔線"</string>
+ <string name="divider_title" msgid="1963391955593749442">"分割畫面分隔線"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"以全螢幕顯示左側畫面"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"以 70% 的螢幕空間顯示左側畫面"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"以 50% 的螢幕空間顯示左側畫面"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"以 50% 的螢幕空間顯示頂端畫面"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"以 30% 的螢幕空間顯示頂端畫面"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"以全螢幕顯示底部畫面"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"分割左側區域"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"分割右側區域"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"分割上方區域"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"分割下方區域"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"使用單手模式"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"如要退出,請從螢幕底部向上滑動,或輕觸應用程式上方的任何位置"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"啟動單手模式"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未修正問題嗎?\n輕觸即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機沒問題嗎?輕觸即可關閉。"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"拖進另一個應用程式即可使用分割畫面模式"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖進另一個應用程式即可使用分割畫面模式"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕觸兩下即可調整位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"我知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳細資訊。"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"取消"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"重新啟動"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不要再顯示"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"輕觸兩下即可\n移動這個應用程式"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
<string name="minimize_button_text" msgid="271592547935841753">"最小化"</string>
<string name="close_button_text" msgid="2913281996024033299">"關閉"</string>
<string name="back_button_text" msgid="1469718707134137085">"返回"</string>
<string name="handle_text" msgid="1766582106752184456">"控點"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"全螢幕"</string>
<string name="desktop_text" msgid="1077633567027630454">"電腦模式"</string>
<string name="split_screen_text" msgid="1396336058129570886">"分割畫面"</string>
<string name="more_button_text" msgid="3655388105592893530">"更多"</string>
<string name="float_button_text" msgid="9221657008391364581">"浮動"</string>
+ <string name="select_text" msgid="5139083974039906583">"選取"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"螢幕截圖"</string>
+ <string name="close_text" msgid="4986518933445178928">"關閉"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"開啟選單"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 913e68f95cb4..478b5a62c8a5 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -32,13 +32,13 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Shintsha usayizi"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Yenza isiteshi"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Susa isiteshi"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Izinhlelo zokusebenza kungenzeka zingasebenzi ngesikrini esihlukanisiwe."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"Ama-app okungenzeka angasebenzi ngesikrini esihlukanisiwe"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"I-app ayisekeli isikrini esihlukanisiwe."</string>
<string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Le-app ingavulwa kuphela ewindini eli-1."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uhlelo lokusebenza kungenzeka lungasebenzi kusibonisi sesibili."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Uhlelo lokusebenza alusekeli ukuqalisa kuzibonisi zesibili."</string>
- <string name="accessibility_divider" msgid="703810061635792791">"Isihlukanisi sokuhlukanisa isikrini"</string>
- <string name="divider_title" msgid="5482989479865361192">"Isihlukanisi sokuhlukanisa isikrini"</string>
+ <string name="accessibility_divider" msgid="6407584574218956849">"Isihlukanisi sokuhlukanisa isikrini"</string>
+ <string name="divider_title" msgid="1963391955593749442">"Isihlukanisi sokuhlukanisa isikrini"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Isikrini esigcwele esingakwesokunxele"</string>
<string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kwesokunxele ngo-70%"</string>
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kwesokunxele ngo-50%"</string>
@@ -49,14 +49,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Okuphezulu okungu-50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Okuphezulu okungu-30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ngaphansi kwesikrini esigcwele"</string>
- <!-- no translation found for accessibility_split_left (1713683765575562458) -->
- <skip />
- <!-- no translation found for accessibility_split_right (8441001008181296837) -->
- <skip />
- <!-- no translation found for accessibility_split_top (2789329702027147146) -->
- <skip />
- <!-- no translation found for accessibility_split_bottom (8694551025220868191) -->
- <skip />
+ <string name="accessibility_split_left" msgid="1713683765575562458">"Hlukanisa ngakwesobunxele"</string>
+ <string name="accessibility_split_right" msgid="8441001008181296837">"Hlukanisa ngakwesokudla"</string>
+ <string name="accessibility_split_top" msgid="2789329702027147146">"Hlukanisa phezulu"</string>
+ <string name="accessibility_split_bottom" msgid="8694551025220868191">"Hlukanisa phansi"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Ukusebenzisa imodi yesandla esisodwa"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Ukuze uphume, swayipha ngaphezulu kusuka ngezansi kwesikrini noma thepha noma kuphi ngenhla kohlelo lokusebenza"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Qalisa imodi yesandla esisodwa"</string>
@@ -88,7 +84,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Akuyilungisanga?\nThepha ukuze ubuyele"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Azikho izinkinga zekhamera? Thepha ukuze ucashise."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Bona futhi wenze okuningi"</string>
- <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Hudula kwenye i-app mayelana nokuhlukanisa isikrini"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Hudula kwenye i-app mayelana nokuhlukanisa isikrini"</string>
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Thepha kabili ngaphandle kwe-app ukuze uyimise kabusha"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ngiyezwa"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Nweba ukuze uthole ulwazi olwengeziwe"</string>
@@ -97,14 +93,21 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Khansela"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Qala kabusha"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ungabonisi futhi"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Thepha kabili ukuze\nuhambise le-app"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Khulisa"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Nciphisa"</string>
<string name="close_button_text" msgid="2913281996024033299">"Vala"</string>
<string name="back_button_text" msgid="1469718707134137085">"Emuva"</string>
<string name="handle_text" msgid="1766582106752184456">"Isibambo"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Isithonjana Se-app"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Isikrini esigcwele"</string>
<string name="desktop_text" msgid="1077633567027630454">"Imodi Yedeskithophu"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Hlukanisa isikrini"</string>
<string name="more_button_text" msgid="3655388105592893530">"Okwengeziwe"</string>
<string name="float_button_text" msgid="9221657008391364581">"Iflowuthi"</string>
+ <string name="select_text" msgid="5139083974039906583">"Khetha"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Isithombe-skrini"</string>
+ <string name="close_text" msgid="4986518933445178928">"Vala"</string>
+ <string name="collapse_menu_text" msgid="7515008122450342029">"Vala Imenyu"</string>
+ <string name="expand_menu_text" msgid="3847736164494181168">"Vula Imenyu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 171a6b2fe5fb..b2ec98bc1b15 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -30,6 +30,9 @@
<color name="bubbles_light">#FFFFFF</color>
<color name="bubbles_dark">@color/GM2_grey_800</color>
<color name="bubbles_icon_tint">@color/GM2_grey_700</color>
+ <color name="bubble_bar_expanded_view_handle_light">#EBffffff</color>
+ <color name="bubble_bar_expanded_view_handle_dark">#99000000</color>
+ <color name="bubble_bar_expanded_view_menu_close">#DC362E</color>
<!-- PiP -->
<color name="pip_custom_close_bg">#D93025</color>
@@ -61,6 +64,8 @@
<color name="desktop_mode_caption_expand_button_dark">#48473A</color>
<color name="desktop_mode_caption_close_button_light">#EFF1F2</color>
<color name="desktop_mode_caption_close_button_dark">#1C1C17</color>
+ <color name="desktop_mode_caption_maximize_button_light">#EFF1F2</color>
+ <color name="desktop_mode_caption_maximize_button_dark">#1C1C17</color>
<color name="desktop_mode_caption_app_name_light">#EFF1F2</color>
<color name="desktop_mode_caption_app_name_dark">#1C1C17</color>
<color name="desktop_mode_caption_menu_text_color">#191C1D</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 2be34c90a661..ac73e1d87ba2 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -226,10 +226,26 @@
<dimen name="bubble_user_education_padding_end">58dp</dimen>
<!-- Padding between the bubble and the user education text. -->
<dimen name="bubble_user_education_stack_padding">16dp</dimen>
- <!-- Size of the bubble bar (height), should match transient_taskbar_size in Launcher. -->
- <dimen name="bubblebar_size">72dp</dimen>
- <!-- The size of the drag handle / menu shown along with a bubble bar expanded view. -->
- <dimen name="bubblebar_expanded_view_menu_size">16dp</dimen>
+ <!-- The size of the caption bar inset at the top of bubble bar expanded view. -->
+ <dimen name="bubble_bar_expanded_view_caption_height">32dp</dimen>
+ <!-- The height of the dots shown for the caption menu in the bubble bar expanded view.. -->
+ <dimen name="bubble_bar_expanded_view_caption_dot_size">4dp</dimen>
+ <!-- The spacing between the dots for the caption menu in the bubble bar expanded view.. -->
+ <dimen name="bubble_bar_expanded_view_caption_dot_spacing">4dp</dimen>
+ <!-- Minimum width of the bubble bar manage menu. -->
+ <dimen name="bubble_bar_manage_menu_min_width">200dp</dimen>
+ <!-- Size of the dismiss icon in the bubble bar manage menu. -->
+ <dimen name="bubble_bar_manage_menu_dismiss_icon_size">16dp</dimen>
+ <!-- Padding of the bubble bar manage menu, provides space for menu shadows -->
+ <dimen name="bubble_bar_manage_menu_padding">8dp</dimen>
+ <!-- Top padding of the bubble bar manage menu -->
+ <dimen name="bubble_bar_manage_menu_padding_top">2dp</dimen>
+ <!-- Spacing between sections of the bubble bar manage menu -->
+ <dimen name="bubble_bar_manage_menu_section_spacing">2dp</dimen>
+ <!-- Height of an item in the bubble bar manage menu. -->
+ <dimen name="bubble_bar_manage_menu_item_height">52dp</dimen>
+ <!-- Size of the icons in the bubble bar manage menu. -->
+ <dimen name="bubble_bar_manage_menu_item_icon_size">20dp</dimen>
<!-- Bottom and end margin for compat buttons. -->
<dimen name="compat_button_margin">24dp</dimen>
@@ -398,7 +414,16 @@
<!-- The radius of the caption menu shadow. -->
<dimen name="desktop_mode_handle_menu_shadow_radius">2dp</dimen>
- <dimen name="freeform_resize_handle">30dp</dimen>
+ <dimen name="freeform_resize_handle">15dp</dimen>
<dimen name="freeform_resize_corner">44dp</dimen>
+
+ <!-- The height of the area at the top of the screen where a freeform task will transition to
+ fullscreen if dragged until the top bound of the task is within the area. -->
+ <dimen name="desktop_mode_transition_area_height">16dp</dimen>
+
+ <!-- The acceptable area ratio of fg icon area/bg icon area, i.e. (72 x 72) / (108 x 108) -->
+ <item type="dimen" format="float" name="splash_icon_enlarge_foreground_threshold">0.44</item>
+ <!-- Scaling factor applied to splash icons without provided background i.e. (192 / 160) -->
+ <item type="dimen" format="float" name="splash_icon_no_background_scale_factor">1.2</item>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
index 39f861de1ba0..5cf9175073c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
@@ -50,7 +50,7 @@ class ActivityEmbeddingAnimationAdapter {
final SurfaceControl mLeash;
/** Area in absolute coordinate that the animation surface shouldn't go beyond. */
@NonNull
- private final Rect mWholeAnimationBounds = new Rect();
+ final Rect mWholeAnimationBounds = new Rect();
/**
* Area in absolute coordinate that should represent all the content to show for this window.
* This should be the end bounds for opening window, and start bounds for closing window in case
@@ -229,20 +229,7 @@ class ActivityEmbeddingAnimationAdapter {
mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
t.setAlpha(mLeash, mTransformation.getAlpha());
-
- // The following applies an inverse scale to the clip-rect so that it crops "after" the
- // scale instead of before.
- mVecs[1] = mVecs[2] = 0;
- mVecs[0] = mVecs[3] = 1;
- mTransformation.getMatrix().mapVectors(mVecs);
- mVecs[0] = 1.f / mVecs[0];
- mVecs[3] = 1.f / mVecs[3];
- final Rect clipRect = mTransformation.getClipRect();
- mRect.left = (int) (clipRect.left * mVecs[0] + 0.5f);
- mRect.right = (int) (clipRect.right * mVecs[0] + 0.5f);
- mRect.top = (int) (clipRect.top * mVecs[3] + 0.5f);
- mRect.bottom = (int) (clipRect.bottom * mVecs[3] + 0.5f);
- t.setCrop(mLeash, mRect);
+ t.setWindowCrop(mLeash, mWholeAnimationBounds.width(), mWholeAnimationBounds.height());
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index 1793a3d0feb4..4640106b5f1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -26,7 +26,6 @@ import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
-import android.view.animation.ClipRectAnimation;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.ScaleAnimation;
@@ -189,14 +188,6 @@ class ActivityEmbeddingAnimationSpec {
startBounds.top - endBounds.top, 0);
endTranslate.setDuration(CHANGE_ANIMATION_DURATION);
endSet.addAnimation(endTranslate);
- // The end leash is resizing, we should update the window crop based on the clip rect.
- final Rect startClip = new Rect(startBounds);
- final Rect endClip = new Rect(endBounds);
- startClip.offsetTo(0, 0);
- endClip.offsetTo(0, 0);
- final Animation clipAnim = new ClipRectAnimation(startClip, endClip);
- clipAnim.setDuration(CHANGE_ANIMATION_DURATION);
- endSet.addAnimation(clipAnim);
endSet.initialize(startBounds.width(), startBounds.height(), parentBounds.width(),
parentBounds.height());
endSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
index 57d374b2b8f5..06ce37148eaf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
@@ -186,6 +186,6 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
if (callback == null) {
throw new IllegalStateException("No finish callback found");
}
- callback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ callback.onTransitionFinished(null /* wct */);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
index 798250de89d0..26edd7d2268b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
@@ -117,6 +117,20 @@ public class FlingAnimationUtils {
* @param endValue the end value of the animator
* @param velocity the current velocity of the motion
*/
+ public void apply(androidx.core.animation.Animator animator,
+ float currValue, float endValue, float velocity) {
+ apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
+ }
+
+ /**
+ * Applies the interpolator and length to the animator, such that the fling animation is
+ * consistent with the finger motion.
+ *
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
+ */
public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
float velocity) {
apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
@@ -152,6 +166,24 @@ public class FlingAnimationUtils {
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
+ public void apply(androidx.core.animation.Animator animator,
+ float currValue, float endValue, float velocity, float maxDistance) {
+ AnimatorProperties properties = getProperties(currValue, endValue, velocity, maxDistance);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.getInterpolator());
+ }
+
+ /**
+ * Applies the interpolator and length to the animator, such that the fling animation is
+ * consistent with the finger motion.
+ *
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
+ * @param maxDistance the maximum distance for this interaction; the maximum animation length
+ * gets multiplied by the ratio between the actual distance and this value
+ */
public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
float velocity, float maxDistance) {
AnimatorProperties properties = getProperties(currValue, endValue, velocity,
@@ -367,6 +399,11 @@ public class FlingAnimationUtils {
private static class AnimatorProperties {
Interpolator mInterpolator;
long mDuration;
+
+ /** Get an AndroidX interpolator wrapper of the current mInterpolator */
+ public androidx.core.animation.Interpolator getInterpolator() {
+ return mInterpolator::getInterpolation;
+ }
}
/** Builder for {@link #FlingAnimationUtils}. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING
index 837d5ff3b073..f02559f36169 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING
@@ -12,19 +12,19 @@
]
},
{
- "name": "CtsWindowManagerDeviceTestCases",
+ "name": "CtsWindowManagerDeviceBackNavigation",
"options": [
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
},
{
- "include-filter": "android.server.wm.BackGestureInvokedTest"
+ "include-filter": "android.server.wm.backnavigation.BackGestureInvokedTest"
},
{
- "include-filter": "android.server.wm.BackNavigationTests"
+ "include-filter": "android.server.wm.backnavigation.BackNavigationTests"
},
{
- "include-filter": "android.server.wm.OnBackInvokedCallbackGestureTest"
+ "include-filter": "android.server.wm.backnavigation.OnBackInvokedCallbackGestureTest"
}
]
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 102f2cb4b8d0..7e09c989e1b3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -422,6 +422,7 @@ public class Bubble implements BubbleViewProvider {
}
if (mBubbleBarExpandedView != null) {
mBubbleBarExpandedView.cleanUpExpandedState();
+ mBubbleBarExpandedView = null;
}
if (mIntent != null) {
mIntent.unregisterCancelListener(mIntentCancelListener);
@@ -549,10 +550,10 @@ public class Bubble implements BubbleViewProvider {
/**
* Set visibility of bubble in the expanded state.
*
- * @param visibility {@code true} if the expanded bubble should be visible on the screen.
- *
- * Note that this contents visibility doesn't affect visibility at {@link android.view.View},
+ * <p>Note that this contents visibility doesn't affect visibility at {@link android.view.View},
* and setting {@code false} actually means rendering the expanded view in transparent.
+ *
+ * @param visibility {@code true} if the expanded bubble should be visible on the screen.
*/
@Override
public void setTaskViewVisibility(boolean visibility) {
@@ -855,7 +856,8 @@ public class Bubble implements BubbleViewProvider {
return mIsAppBubble;
}
- Intent getSettingsIntent(final Context context) {
+ /** Creates open app settings intent */
+ public Intent getSettingsIntent(final Context context) {
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
final int uid = getUid(context);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 0fdfbb8c0c61..66b9ade6aea0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -64,7 +64,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.NotificationListenerService;
@@ -92,6 +91,7 @@ import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
+import com.android.wm.shell.bubbles.properties.BubbleProperties;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -143,16 +143,6 @@ public class BubbleController implements ConfigurationChangeListener,
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
- // TODO(b/256873975) Should use proper flag when available to shell/launcher
- /**
- * Whether bubbles are showing in the bubble bar from launcher. This is only available
- * on large screens and {@link BubbleController#isShowingAsBubbleBar()} should be used
- * to check all conditions that indicate if the bubble bar is in use.
- */
- private static final boolean BUBBLE_BAR_ENABLED =
- SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
-
-
/**
* Common interface to send updates to bubble views.
*/
@@ -195,6 +185,7 @@ public class BubbleController implements ConfigurationChangeListener,
private final ShellController mShellController;
private final ShellCommandHandler mShellCommandHandler;
private final IWindowManager mWmService;
+ private final BubbleProperties mBubbleProperties;
// Used to post to main UI thread
private final ShellExecutor mMainExecutor;
@@ -291,7 +282,8 @@ public class BubbleController implements ConfigurationChangeListener,
@ShellBackgroundThread ShellExecutor bgExecutor,
TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue,
- IWindowManager wmService) {
+ IWindowManager wmService,
+ BubbleProperties bubbleProperties) {
mContext = context;
mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
@@ -328,6 +320,7 @@ public class BubbleController implements ConfigurationChangeListener,
mDragAndDropController = dragAndDropController;
mSyncQueue = syncQueue;
mWmService = wmService;
+ mBubbleProperties = bubbleProperties;
shellInit.addInitCallback(this::onInit, this);
}
@@ -336,16 +329,20 @@ public class BubbleController implements ConfigurationChangeListener,
new OneHandedTransitionCallback() {
@Override
public void onStartFinished(Rect bounds) {
- if (mStackView != null) {
- mStackView.onVerticalOffsetChanged(bounds.top);
- }
+ mMainExecutor.execute(() -> {
+ if (mStackView != null) {
+ mStackView.onVerticalOffsetChanged(bounds.top);
+ }
+ });
}
@Override
public void onStopFinished(Rect bounds) {
- if (mStackView != null) {
- mStackView.onVerticalOffsetChanged(bounds.top);
- }
+ mMainExecutor.execute(() -> {
+ if (mStackView != null) {
+ mStackView.onVerticalOffsetChanged(bounds.top);
+ }
+ });
}
});
}
@@ -518,11 +515,14 @@ public class BubbleController implements ConfigurationChangeListener,
/**
* Sets a listener to be notified of bubble updates. This is used by launcher so that
* it may render bubbles in itself. Only one listener is supported.
+ *
+ * <p>If bubble bar is supported, bubble views will be updated to switch to bar mode.
*/
public void registerBubbleStateListener(Bubbles.BubbleStateListener listener) {
- if (isShowingAsBubbleBar()) {
- // Only set the listener if bubble bar is showing.
+ if (canShowAsBubbleBar() && listener != null) {
+ // Only set the listener if we can show the bubble bar.
mBubbleStateListener = listener;
+ setUpBubbleViewsForMode();
sendInitialListenerUpdate();
} else {
mBubbleStateListener = null;
@@ -531,9 +531,15 @@ public class BubbleController implements ConfigurationChangeListener,
/**
* Unregisters the {@link Bubbles.BubbleStateListener}.
+ *
+ * <p>If there's an existing listener, then we're switching back to stack mode and bubble views
+ * will be updated accordingly.
*/
public void unregisterBubbleStateListener() {
- mBubbleStateListener = null;
+ if (mBubbleStateListener != null) {
+ mBubbleStateListener = null;
+ setUpBubbleViewsForMode();
+ }
}
/**
@@ -645,8 +651,12 @@ public class BubbleController implements ConfigurationChangeListener,
/** Whether bubbles are showing in the bubble bar. */
public boolean isShowingAsBubbleBar() {
- // TODO(b/269670598): should also check that we're in gesture nav
- return BUBBLE_BAR_ENABLED && mBubblePositioner.isLargeScreen();
+ return canShowAsBubbleBar() && mBubbleStateListener != null;
+ }
+
+ /** Whether the current configuration supports showing as bubble bar. */
+ private boolean canShowAsBubbleBar() {
+ return mBubbleProperties.isBubbleBarEnabled() && mBubblePositioner.isLargeScreen();
}
/** Whether this userId belongs to the current user. */
@@ -719,6 +729,7 @@ public class BubbleController implements ConfigurationChangeListener,
// TODO(b/273312602): consider foldables where we do need a stack view when folded
if (mLayerView == null) {
mLayerView = new BubbleBarLayerView(mContext, this);
+ mLayerView.setUnBubbleConversationCallback(mSysuiProxy::onUnbubbleConversation);
}
} else {
if (mStackView == null) {
@@ -773,12 +784,12 @@ public class BubbleController implements ConfigurationChangeListener,
try {
mAddedToWindowManager = true;
registerBroadcastReceiver();
- mBubbleData.getOverflow().initialize(this);
+ mBubbleData.getOverflow().initialize(this, isShowingAsBubbleBar());
// (TODO: b/273314541) some duplication in the inset listener
if (isShowingAsBubbleBar()) {
mWindowManager.addView(mLayerView, mWmLayoutParams);
mLayerView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
- if (!windowInsets.equals(mWindowInsets)) {
+ if (!windowInsets.equals(mWindowInsets) && mLayerView != null) {
mWindowInsets = windowInsets;
mBubblePositioner.update();
mLayerView.onDisplaySizeChanged();
@@ -788,7 +799,7 @@ public class BubbleController implements ConfigurationChangeListener,
} else {
mWindowManager.addView(mStackView, mWmLayoutParams);
mStackView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
- if (!windowInsets.equals(mWindowInsets)) {
+ if (!windowInsets.equals(mWindowInsets) && mStackView != null) {
mWindowInsets = windowInsets;
mBubblePositioner.update();
mStackView.onDisplaySizeChanged();
@@ -810,13 +821,17 @@ public class BubbleController implements ConfigurationChangeListener,
* @param interceptBack whether back should be intercepted or not.
*/
void updateWindowFlagsForBackpress(boolean interceptBack) {
- if (mStackView != null && mAddedToWindowManager) {
+ if (mAddedToWindowManager) {
mWmLayoutParams.flags = interceptBack
? 0
: WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- mWindowManager.updateViewLayout(mStackView, mWmLayoutParams);
+ if (mStackView != null) {
+ mWindowManager.updateViewLayout(mStackView, mWmLayoutParams);
+ } else if (mLayerView != null) {
+ mWindowManager.updateViewLayout(mLayerView, mWmLayoutParams);
+ }
}
}
@@ -1042,6 +1057,20 @@ public class BubbleController implements ConfigurationChangeListener,
mBubbleData.setExpanded(false /* expanded */);
}
+ /**
+ * Update expanded state when a single bubble is dragged in Launcher.
+ * Will be called only when bubble bar is expanded.
+ * @param bubbleKey key of the bubble to collapse/expand
+ * @param isBeingDragged whether the bubble is being dragged
+ */
+ public void onBubbleDrag(String bubbleKey, boolean isBeingDragged) {
+ if (mBubbleData.getSelectedBubble() != null
+ && mBubbleData.getSelectedBubble().getKey().equals(bubbleKey)) {
+ // Should collapse/expand only if equals to selected bubble.
+ mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ !isBeingDragged);
+ }
+ }
+
@VisibleForTesting
public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) {
boolean isSuppressedBubble = (mBubbleData.hasAnyBubbleWithKey(key)
@@ -1065,9 +1094,19 @@ public class BubbleController implements ConfigurationChangeListener,
* Expands and selects the provided bubble as long as it already exists in the stack or the
* overflow.
*
- * This is used by external callers (launcher).
+ * <p>This is used by external callers (launcher).
*/
- public void expandStackAndSelectBubbleFromLauncher(String key) {
+ @VisibleForTesting
+ public void expandStackAndSelectBubbleFromLauncher(String key, int bubbleBarOffsetX,
+ int bubbleBarOffsetY) {
+ mBubblePositioner.setBubbleBarPosition(bubbleBarOffsetX, bubbleBarOffsetY);
+
+ if (BubbleOverflow.KEY.equals(key)) {
+ mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow());
+ mLayerView.showExpandedView(mBubbleData.getOverflow());
+ return;
+ }
+
Bubble b = mBubbleData.getAnyBubbleWithkey(key);
if (b == null) {
return;
@@ -1220,6 +1259,13 @@ public class BubbleController implements ConfigurationChangeListener,
}
/**
+ * Dismiss bubble if it exists and remove it from the stack
+ */
+ public void dismissBubble(Bubble bubble, @Bubbles.DismissReason int reason) {
+ mBubbleData.dismissBubbleWithKey(bubble.getKey(), reason);
+ }
+
+ /**
* Performs a screenshot that may exclude the bubble layer, if one is present. The screenshot
* can be access via the supplied {@link SynchronousScreenCaptureListener#getBuffer()}
* asynchronously.
@@ -1259,7 +1305,9 @@ public class BubbleController implements ConfigurationChangeListener,
return;
}
mOverflowDataLoadNeeded = false;
- mDataRepository.loadBubbles(mCurrentUserId, (bubbles) -> {
+ List<UserInfo> users = mUserManager.getAliveUsers();
+ List<Integer> userIds = users.stream().map(userInfo -> userInfo.id).toList();
+ mDataRepository.loadBubbles(mCurrentUserId, userIds, (bubbles) -> {
bubbles.forEach(bubble -> {
if (mBubbleData.hasAnyBubbleWithKey(bubble.getKey())) {
// if the bubble is already active, there's no need to push it to overflow
@@ -1278,6 +1326,50 @@ public class BubbleController implements ConfigurationChangeListener,
});
}
+ void setUpBubbleViewsForMode() {
+ mBubbleViewCallback = isShowingAsBubbleBar()
+ ? mBubbleBarViewCallback
+ : mBubbleStackViewCallback;
+
+ // reset the overflow so that it can be re-added later if needed.
+ if (mStackView != null) {
+ mStackView.resetOverflowView();
+ mStackView.removeAllViews();
+ }
+ // cleanup existing bubble views so they can be recreated later if needed.
+ mBubbleData.getBubbles().forEach(Bubble::cleanupViews);
+
+ // remove the current bubble container from window manager, null it out, and create a new
+ // container based on the current mode.
+ removeFromWindowManagerMaybe();
+ mLayerView = null;
+ mStackView = null;
+ ensureBubbleViewsAndWindowCreated();
+
+ // inflate bubble views
+ BubbleViewInfoTask.Callback callback = null;
+ if (!isShowingAsBubbleBar()) {
+ callback = b -> {
+ if (mStackView != null) {
+ mStackView.addBubble(b);
+ mStackView.setSelectedBubble(b);
+ } else {
+ Log.w(TAG, "Tried to add a bubble to the stack but the stack is null");
+ }
+ };
+ }
+ for (int i = mBubbleData.getBubbles().size() - 1; i >= 0; i--) {
+ Bubble bubble = mBubbleData.getBubbles().get(i);
+ bubble.inflate(callback,
+ mContext,
+ this,
+ mStackView,
+ mLayerView,
+ mBubbleIconFactory,
+ false /* skipInflation */);
+ }
+ }
+
/**
* Adds or updates a bubble associated with the provided notification entry.
*
@@ -1364,6 +1456,17 @@ public class BubbleController implements ConfigurationChangeListener,
}
}
+ /**
+ * Removes all the bubbles.
+ * <p>
+ * Must be called from the main thread.
+ */
+ @VisibleForTesting
+ @MainThread
+ public void removeAllBubbles(@Bubbles.DismissReason int reason) {
+ mBubbleData.dismissAll(reason);
+ }
+
private void onEntryAdded(BubbleEntry entry) {
if (canLaunchInTaskView(mContext, entry)) {
updateBubble(entry);
@@ -1738,7 +1841,7 @@ public class BubbleController implements ConfigurationChangeListener,
// Update the cached state for queries from SysUI
mImpl.mCachedState.update(update);
- if (isShowingAsBubbleBar() && mBubbleStateListener != null) {
+ if (isShowingAsBubbleBar()) {
BubbleBarUpdate bubbleBarUpdate = update.toBubbleBarUpdate();
// Some updates aren't relevant to the bubble bar so check first.
if (bubbleBarUpdate.anythingChanged()) {
@@ -1846,7 +1949,7 @@ public class BubbleController implements ConfigurationChangeListener,
if (mStackView != null) {
mStackView.setVisibility(VISIBLE);
}
- if (mLayerView != null && isStackExpanded()) {
+ if (mLayerView != null) {
mLayerView.setVisibility(VISIBLE);
}
}
@@ -1860,10 +1963,17 @@ public class BubbleController implements ConfigurationChangeListener,
}
@VisibleForTesting
+ @Nullable
public BubbleStackView getStackView() {
return mStackView;
}
+ @VisibleForTesting
+ @Nullable
+ public BubbleBarLayerView getLayerView() {
+ return mLayerView;
+ }
+
/**
* Check if notification panel is in an expanded state.
* Makes a call to System UI process and delivers the result via {@code callback} on the
@@ -2002,27 +2112,30 @@ public class BubbleController implements ConfigurationChangeListener,
@Override
public void registerBubbleListener(IBubblesListener listener) {
- mMainExecutor.execute(() -> {
- mListener.register(listener);
- });
+ mMainExecutor.execute(() -> mListener.register(listener));
}
@Override
public void unregisterBubbleListener(IBubblesListener listener) {
- mMainExecutor.execute(() -> mListener.unregister());
+ mMainExecutor.execute(mListener::unregister);
}
@Override
- public void showBubble(String key, boolean onLauncherHome) {
- mMainExecutor.execute(() -> {
- mBubblePositioner.setShowingInBubbleBar(onLauncherHome);
- mController.expandStackAndSelectBubbleFromLauncher(key);
- });
+ public void showBubble(String key, int bubbleBarOffsetX, int bubbleBarOffsetY) {
+ mMainExecutor.execute(
+ () -> mController.expandStackAndSelectBubbleFromLauncher(
+ key, bubbleBarOffsetX, bubbleBarOffsetY));
+ }
+
+ @Override
+ public void removeBubble(String key) {
+ mMainExecutor.execute(
+ () -> mController.removeBubble(key, Bubbles.DISMISS_USER_GESTURE));
}
@Override
- public void removeBubble(String key, int reason) {
- // TODO (b/271466616) allow removals from launcher
+ public void removeAllBubbles() {
+ mMainExecutor.execute(() -> mController.removeAllBubbles(Bubbles.DISMISS_USER_GESTURE));
}
@Override
@@ -2031,8 +2144,8 @@ public class BubbleController implements ConfigurationChangeListener,
}
@Override
- public void onTaskbarStateChanged(int newState) {
- // TODO (b/269670598)
+ public void onBubbleDrag(String bubbleKey, boolean isBeingDragged) {
+ mMainExecutor.execute(() -> mController.onBubbleDrag(bubbleKey, isBeingDragged));
}
}
@@ -2144,7 +2257,7 @@ public class BubbleController implements ConfigurationChangeListener,
pw.println(" suppressing: " + key);
}
- pw.print("mAppBubbleTaskIds: " + mAppBubbleTaskIds.values());
+ pw.println("mAppBubbleTaskIds: " + mAppBubbleTaskIds.values());
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index e37c785f15f5..df12999afc9d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -17,7 +17,6 @@ package com.android.wm.shell.bubbles
import android.annotation.SuppressLint
import android.annotation.UserIdInt
-import android.content.Context
import android.content.pm.LauncherApps
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC
@@ -25,6 +24,8 @@ import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LA
import android.content.pm.UserInfo
import android.os.UserHandle
import android.util.Log
+import android.util.SparseArray
+import com.android.internal.annotations.VisibleForTesting
import com.android.wm.shell.bubbles.Bubbles.BubbleMetadataFlagListener
import com.android.wm.shell.bubbles.storage.BubbleEntity
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
@@ -33,19 +34,19 @@ import com.android.wm.shell.common.ShellExecutor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
-internal class BubbleDataRepository(
- context: Context,
+class BubbleDataRepository(
private val launcherApps: LauncherApps,
- private val mainExecutor: ShellExecutor
+ private val mainExecutor: ShellExecutor,
+ private val persistentRepository: BubblePersistentRepository,
) {
private val volatileRepository = BubbleVolatileRepository(launcherApps)
- private val persistentRepository = BubblePersistentRepository(context)
- private val ioScope = CoroutineScope(Dispatchers.IO)
+ private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private var job: Job? = null
// For use in Bubble construction.
@@ -98,6 +99,44 @@ internal class BubbleDataRepository(
if (volatileRepository.sanitizeBubbles(userIds)) persistToDisk()
}
+ /**
+ * Removes all entities that don't have a user in the activeUsers list, if any entities were
+ * removed it persists the new list to disk.
+ */
+ @VisibleForTesting
+ fun filterForActiveUsersAndPersist(
+ activeUsers: List<Int>,
+ entitiesByUser: SparseArray<List<BubbleEntity>>
+ ): SparseArray<List<BubbleEntity>> {
+ val validEntitiesByUser = SparseArray<List<BubbleEntity>>()
+ var entitiesChanged = false
+ for (i in 0 until entitiesByUser.size()) {
+ val parentUserId = entitiesByUser.keyAt(i)
+ if (activeUsers.contains(parentUserId)) {
+ val validEntities = mutableListOf<BubbleEntity>()
+ // Check if each of the bubbles in the top-level user still has a valid user
+ // as it could belong to a profile and have a different id from the parent.
+ for (entity in entitiesByUser.get(parentUserId)) {
+ if (activeUsers.contains(entity.userId)) {
+ validEntities.add(entity)
+ } else {
+ entitiesChanged = true
+ }
+ }
+ if (validEntities.isNotEmpty()) {
+ validEntitiesByUser.put(parentUserId, validEntities)
+ }
+ } else {
+ entitiesChanged = true
+ }
+ }
+ if (entitiesChanged) {
+ persistToDisk(validEntitiesByUser)
+ return validEntitiesByUser
+ }
+ return entitiesByUser
+ }
+
private fun transform(bubbles: List<Bubble>): List<BubbleEntity> {
return bubbles.mapNotNull { b ->
BubbleEntity(
@@ -129,15 +168,18 @@ internal class BubbleDataRepository(
* Job C resumes and reaches yield() and is then cancelled
* Job D resumes and performs another blocking I/O
*/
- private fun persistToDisk() {
+ @VisibleForTesting
+ fun persistToDisk(
+ entitiesByUser: SparseArray<List<BubbleEntity>> = volatileRepository.bubbles
+ ) {
val prev = job
- job = ioScope.launch {
+ job = coroutineScope.launch {
// if there was an ongoing disk I/O operation, they can be cancelled
prev?.cancelAndJoin()
// check for cancellation before disk I/O
yield()
// save to disk
- persistentRepository.persistsToDisk(volatileRepository.bubbles)
+ persistentRepository.persistsToDisk(entitiesByUser)
}
}
@@ -148,7 +190,11 @@ internal class BubbleDataRepository(
* bubbles.
*/
@SuppressLint("WrongConstant")
- fun loadBubbles(userId: Int, cb: (List<Bubble>) -> Unit) = ioScope.launch {
+ fun loadBubbles(
+ userId: Int,
+ currentUsers: List<Int>,
+ cb: (List<Bubble>) -> Unit
+ ) = coroutineScope.launch {
/**
* Load BubbleEntity from disk.
* e.g.
@@ -159,7 +205,12 @@ internal class BubbleDataRepository(
* ]
*/
val entitiesByUser = persistentRepository.readFromDisk()
- val entities = entitiesByUser.get(userId) ?: return@launch
+
+ // Before doing anything, validate that the entities we loaded are valid & have an existing
+ // user.
+ val validEntitiesByUser = filterForActiveUsersAndPersist(currentUsers, entitiesByUser)
+
+ val entities = validEntitiesByUser.get(userId) ?: return@launch
volatileRepository.addBubbles(userId, entities)
/**
* Extract userId/packageName from these entities.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index e1a3f3a1ac5d..e6986012dd88 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -312,9 +312,13 @@ public class BubbleExpandedView extends LinearLayout {
+ " bubble=" + getBubbleKey());
}
if (mBubble != null) {
- // Must post because this is called from a binder thread.
- post(() -> mController.removeBubble(
- mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED));
+ mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+ }
+ if (mTaskView != null) {
+ // Release the surface
+ mTaskView.release();
+ removeView(mTaskView);
+ mTaskView = null;
}
}
@@ -948,9 +952,9 @@ public class BubbleExpandedView extends LinearLayout {
mTaskView.onLocationChanged();
}
if (mIsOverflow) {
- post(() -> {
- mOverflowView.show();
- });
+ // post this to the looper so that the view has a chance to be laid out before it can
+ // calculate row and column sizes correctly.
+ post(() -> mOverflowView.show());
}
}
@@ -1058,8 +1062,10 @@ public class BubbleExpandedView extends LinearLayout {
}
/**
- * Cleans up anything related to the task and {@code TaskView}. If this view should be reused
- * after this method is called, then
+ * Cleans up anything related to the task. The TaskView itself is released after the task
+ * has been removed.
+ *
+ * If this view should be reused after this method is called, then
* {@link #initialize(BubbleController, BubbleStackView, boolean)} must be invoked first.
*/
public void cleanUpExpandedState() {
@@ -1081,10 +1087,7 @@ public class BubbleExpandedView extends LinearLayout {
}
}
if (mTaskView != null) {
- // Release the surface & other task view related things
- mTaskView.release();
- removeView(mTaskView);
- mTaskView = null;
+ mTaskView.setVisibility(GONE);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index df7f5b4f0150..df19757203eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -44,6 +44,7 @@ class BubbleOverflow(private val context: Context, private val positioner: Bubbl
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var expandedView: BubbleExpandedView?
+ private var bubbleBarExpandedView: BubbleBarExpandedView? = null
private var overflowBtn: BadgedImageView?
init {
@@ -53,19 +54,26 @@ class BubbleOverflow(private val context: Context, private val positioner: Bubbl
}
/** Call before use and again if cleanUpExpandedState was called. */
- fun initialize(controller: BubbleController) {
- createExpandedView()
- getExpandedView()?.initialize(controller, controller.stackView, true /* isOverflow */)
+ fun initialize(controller: BubbleController, forBubbleBar: Boolean) {
+ if (forBubbleBar) {
+ createBubbleBarExpandedView().initialize(controller, true /* isOverflow */)
+ } else {
+ createExpandedView()
+ .initialize(controller, controller.stackView, true /* isOverflow */)
+ }
}
fun cleanUpExpandedState() {
expandedView?.cleanUpExpandedState()
expandedView = null
+ bubbleBarExpandedView?.cleanUpExpandedState()
+ bubbleBarExpandedView = null
}
fun update() {
updateResources()
getExpandedView()?.applyThemeAttrs()
+ getBubbleBarExpandedView()?.applyThemeAttrs()
// Apply inset and new style to fresh icon drawable.
getIconView()?.setIconImageResource(R.drawable.bubble_ic_overflow_button)
updateBtnTheme()
@@ -151,26 +159,39 @@ class BubbleOverflow(private val context: Context, private val positioner: Bubbl
overflowBtn?.updateDotVisibility(true /* animate */)
}
- fun createExpandedView(): BubbleExpandedView? {
- expandedView =
+ /** Creates the expanded view for bubbles showing in the stack view. */
+ private fun createExpandedView(): BubbleExpandedView {
+ val view =
inflater.inflate(
R.layout.bubble_expanded_view,
null /* root */,
false /* attachToRoot */
) as BubbleExpandedView
- expandedView?.applyThemeAttrs()
+ view.applyThemeAttrs()
+ expandedView = view
updateResources()
- return expandedView
+ return view
}
override fun getExpandedView(): BubbleExpandedView? {
return expandedView
}
- override fun getBubbleBarExpandedView(): BubbleBarExpandedView? {
- return null
+ /** Creates the expanded view for bubbles showing in the bubble bar. */
+ private fun createBubbleBarExpandedView(): BubbleBarExpandedView {
+ val view =
+ inflater.inflate(
+ R.layout.bubble_bar_expanded_view,
+ null, /* root */
+ false /* attachToRoot*/
+ ) as BubbleBarExpandedView
+ view.applyThemeAttrs()
+ bubbleBarExpandedView = view
+ return view
}
+ override fun getBubbleBarExpandedView(): BubbleBarExpandedView? = bubbleBarExpandedView
+
override fun getDotColor(): Int {
return dotColor
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index d101b0c4d7e8..2c100653dae0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -102,10 +103,7 @@ public class BubblePositioner {
private int[] mPaddings = new int[4];
private boolean mShowingInBubbleBar;
- private boolean mBubblesOnHome;
- private int mBubbleBarSize;
- private int mBubbleBarHomeAdjustment;
- private final PointF mBubbleBarPosition = new PointF();
+ private final Point mBubbleBarPosition = new Point();
public BubblePositioner(Context context, WindowManager windowManager) {
mContext = context;
@@ -166,11 +164,9 @@ public class BubblePositioner {
mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
- mBubbleBarHomeAdjustment = mExpandedViewPadding / 2;
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mBubbleOffscreenAmount = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
- mBubbleBarSize = res.getDimensionPixelSize(R.dimen.bubblebar_size);
if (mShowingInBubbleBar) {
mExpandedViewLargeScreenWidth = isLandscape()
@@ -665,14 +661,26 @@ public class BubblePositioner {
final boolean startOnLeft =
mContext.getResources().getConfiguration().getLayoutDirection()
!= LAYOUT_DIRECTION_RTL;
- final float startingVerticalOffset = mContext.getResources().getDimensionPixelOffset(
- R.dimen.bubble_stack_starting_offset_y);
- // TODO: placement bug here because mPositionRect doesn't handle the overhanging edge
- return new BubbleStackView.RelativeStackPosition(
- startOnLeft,
- startingVerticalOffset / mPositionRect.height())
- .getAbsolutePositionInRegion(getAllowableStackPositionRegion(
- 1 /* default starts with 1 bubble */));
+ final RectF allowableStackPositionRegion = getAllowableStackPositionRegion(
+ 1 /* default starts with 1 bubble */);
+ if (isLargeScreen()) {
+ // We want the stack to be visually centered on the edge, so we need to base it
+ // of a rect that includes insets.
+ final float desiredY = mScreenRect.height() / 2f - (mBubbleSize / 2f);
+ final float offset = desiredY / mScreenRect.height();
+ return new BubbleStackView.RelativeStackPosition(
+ startOnLeft,
+ offset)
+ .getAbsolutePositionInRegion(allowableStackPositionRegion);
+ } else {
+ final float startingVerticalOffset = mContext.getResources().getDimensionPixelOffset(
+ R.dimen.bubble_stack_starting_offset_y);
+ // TODO: placement bug here because mPositionRect doesn't handle the overhanging edge
+ return new BubbleStackView.RelativeStackPosition(
+ startOnLeft,
+ startingVerticalOffset / mPositionRect.height())
+ .getAbsolutePositionInRegion(allowableStackPositionRegion);
+ }
}
/**
@@ -723,27 +731,36 @@ public class BubblePositioner {
}
/**
- * Sets whether bubbles are showing on launcher home, in which case positions are different.
+ * Sets the position of the bubble bar in screen coordinates.
+ *
+ * @param offsetX the offset of the bubble bar from the edge of the screen on the X axis
+ * @param offsetY the offset of the bubble bar from the edge of the screen on the Y axis
*/
- public void setBubblesOnHome(boolean bubblesOnHome) {
- mBubblesOnHome = bubblesOnHome;
+ public void setBubbleBarPosition(int offsetX, int offsetY) {
+ mBubbleBarPosition.set(
+ getAvailableRect().width() - offsetX,
+ getAvailableRect().height() + mInsets.top + mInsets.bottom - offsetY);
}
/**
* How wide the expanded view should be when showing from the bubble bar.
*/
- public int getExpandedViewWidthForBubbleBar() {
- return mExpandedViewLargeScreenWidth;
+ public int getExpandedViewWidthForBubbleBar(boolean isOverflow) {
+ return isOverflow ? mOverflowWidth : mExpandedViewLargeScreenWidth;
}
/**
* How tall the expanded view should be when showing from the bubble bar.
*/
- public int getExpandedViewHeightForBubbleBar() {
- return getAvailableRect().height()
- - mBubbleBarSize
- - mExpandedViewPadding * 2
- - getBubbleBarHomeAdjustment();
+ public int getExpandedViewHeightForBubbleBar(boolean isOverflow) {
+ return isOverflow
+ ? mOverflowHeight
+ : getExpandedViewBottomForBubbleBar() - mInsets.top - mExpandedViewPadding;
+ }
+
+ /** The bottom position of the expanded view when showing above the bubble bar. */
+ public int getExpandedViewBottomForBubbleBar() {
+ return mBubbleBarPosition.y - mExpandedViewPadding;
}
/**
@@ -756,19 +773,7 @@ public class BubblePositioner {
/**
* Returns the on screen co-ordinates of the bubble bar.
*/
- public PointF getBubbleBarPosition() {
- mBubbleBarPosition.set(getAvailableRect().width() - mBubbleBarSize,
- getAvailableRect().height() - mBubbleBarSize
- - mExpandedViewPadding - getBubbleBarHomeAdjustment());
+ public Point getBubbleBarPosition() {
return mBubbleBarPosition;
}
-
- /**
- * When bubbles are shown on launcher home, there's an extra bit of padding that needs to
- * be applied between the expanded view and the bubble bar. This returns the adjustment value
- * if bubbles are showing on home.
- */
- private int getBubbleBarHomeAdjustment() {
- return mBubblesOnHome ? mBubbleBarHomeAdjustment : 0;
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 68fea41e134e..f58b121ae04f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -88,6 +88,8 @@ import com.android.wm.shell.bubbles.animation.PhysicsAnimationLayout;
import com.android.wm.shell.bubbles.animation.StackAnimationController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.bubbles.DismissView;
+import com.android.wm.shell.common.bubbles.RelativeTouchListener;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import java.io.PrintWriter;
@@ -106,8 +108,10 @@ import java.util.stream.Collectors;
public class BubbleStackView extends FrameLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ // LINT.IfChange
public static final boolean ENABLE_FLING_TO_DISMISS_BUBBLE =
SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_bubble", true);
+ // LINT.ThenChange(com/android/launcher3/taskbar/bubbles/BubbleDismissController.java)
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
@@ -307,6 +311,7 @@ public class BubbleStackView extends FrameLayout
String bubblesOnScreen = BubbleDebugConfig.formatBubblesString(
getBubblesOnScreen(), getExpandedBubble());
+ pw.print(" stack visibility : "); pw.println(getVisibility());
pw.print(" bubbles on screen: "); pw.println(bubblesOnScreen);
pw.print(" gestureInProgress: "); pw.println(mIsGestureInProgress);
pw.print(" showingDismiss: "); pw.println(mDismissView.isShowing());
@@ -968,6 +973,8 @@ public class BubbleStackView extends FrameLayout
mBubbleContainer.bringToFront();
mBubbleOverflow = mBubbleData.getOverflow();
+
+ resetOverflowView();
mBubbleContainer.addView(mBubbleOverflow.getIconView(),
mBubbleContainer.getChildCount() /* index */,
new FrameLayout.LayoutParams(mPositioner.getBubbleSize(),
@@ -1179,6 +1186,7 @@ public class BubbleStackView extends FrameLayout
removeView(mDismissView);
}
mDismissView = new DismissView(getContext());
+ DismissViewUtils.setup(mDismissView);
int elevation = getResources().getDimensionPixelSize(R.dimen.bubble_elevation);
addView(mDismissView);
@@ -1494,9 +1502,6 @@ public class BubbleStackView extends FrameLayout
getViewTreeObserver().removeOnPreDrawListener(mViewUpdater);
getViewTreeObserver().removeOnDrawListener(mSystemGestureExcludeUpdater);
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
- if (mBubbleOverflow != null) {
- mBubbleOverflow.cleanUpExpandedState();
- }
}
@Override
@@ -3411,6 +3416,19 @@ public class BubbleStackView extends FrameLayout
}
/**
+ * Removes the overflow view from the stack. This allows for re-adding it later to a new stack.
+ */
+ void resetOverflowView() {
+ BadgedImageView overflowIcon = mBubbleOverflow.getIconView();
+ if (overflowIcon != null) {
+ PhysicsAnimationLayout parent = (PhysicsAnimationLayout) overflowIcon.getParent();
+ if (parent != null) {
+ parent.removeViewNoAnimation(overflowIcon);
+ }
+ }
+ }
+
+ /**
* Holds some commonly queried information about the stack.
*/
public static class StackViewState {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
index 7a5815994dd0..da4a9898a44c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
@@ -15,6 +15,7 @@
*/
package com.android.wm.shell.bubbles;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
@@ -110,6 +111,9 @@ public class BubbleTaskViewHelper {
try {
options.setTaskAlwaysOnTop(true);
options.setLaunchedFromBubble(true);
+ options.setPendingIntentBackgroundActivityStartMode(
+ MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ options.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
Intent fillInIntent = new Intent();
// Apply flags to make behaviour match documentLaunchMode=always.
@@ -117,11 +121,19 @@ public class BubbleTaskViewHelper {
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
if (mBubble.isAppBubble()) {
- PendingIntent pi = PendingIntent.getActivity(mContext, 0,
- mBubble.getAppBubbleIntent(),
- PendingIntent.FLAG_MUTABLE,
- null);
- mTaskView.startActivity(pi, fillInIntent, options, launchBounds);
+ Context context =
+ mContext.createContextAsUser(
+ mBubble.getUser(), Context.CONTEXT_RESTRICTED);
+ PendingIntent pi = PendingIntent.getActivity(
+ context,
+ /* requestCode= */ 0,
+ mBubble.getAppBubbleIntent()
+ .addFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
+ .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK),
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
+ /* options= */ null);
+ mTaskView.startActivity(pi, /* fillInIntent= */ null, options,
+ launchBounds);
} else if (mBubble.hasMetadataShortcutId()) {
options.setApplyActivityFlagsForBubbles(true);
mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index 8ab9841ff0c2..66e69300f45f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -104,7 +104,11 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
@Override
protected BubbleViewInfo doInBackground(Void... voids) {
- if (mController.get().isShowingAsBubbleBar()) {
+ if (!verifyState()) {
+ // If we're in an inconsistent state, then switched modes and should just bail now.
+ return null;
+ }
+ if (mLayerView.get() != null) {
return BubbleViewInfo.populateForBubbleBar(mContext.get(), mController.get(),
mLayerView.get(), mIconFactory, mBubble, mSkipInflation);
} else {
@@ -118,7 +122,11 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
if (isCancelled() || viewInfo == null) {
return;
}
+
mMainExecutor.execute(() -> {
+ if (!verifyState()) {
+ return;
+ }
mBubble.setViewInfo(viewInfo);
if (mCallback != null) {
mCallback.onBubbleViewsReady(mBubble);
@@ -126,6 +134,14 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
});
}
+ private boolean verifyState() {
+ if (mController.get().isShowingAsBubbleBar()) {
+ return mLayerView.get() != null;
+ } else {
+ return mStackView.get() != null;
+ }
+ }
+
/**
* Info necessary to render a bubble.
*/
@@ -160,39 +176,14 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
LayoutInflater inflater = LayoutInflater.from(c);
info.bubbleBarExpandedView = (BubbleBarExpandedView) inflater.inflate(
R.layout.bubble_bar_expanded_view, layerView, false /* attachToRoot */);
- info.bubbleBarExpandedView.initialize(controller);
- }
-
- if (b.getShortcutInfo() != null) {
- info.shortcutInfo = b.getShortcutInfo();
+ info.bubbleBarExpandedView.initialize(controller, false /* isOverflow */);
}
- // App name & app icon
- PackageManager pm = BubbleController.getPackageManagerForUser(c,
- b.getUser().getIdentifier());
- ApplicationInfo appInfo;
- Drawable badgedIcon;
- Drawable appIcon;
- try {
- appInfo = pm.getApplicationInfo(
- b.getPackageName(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE);
- if (appInfo != null) {
- info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
- }
- appIcon = pm.getApplicationIcon(b.getPackageName());
- badgedIcon = pm.getUserBadgedIcon(appIcon, b.getUser());
- } catch (PackageManager.NameNotFoundException exception) {
- // If we can't find package... don't think we should show the bubble.
- Log.w(TAG, "Unable to find package: " + b.getPackageName());
+ if (!populateCommonInfo(info, c, b, iconFactory)) {
+ // if we failed to update common fields return null
return null;
}
- info.rawBadgeBitmap = iconFactory.getBadgeBitmap(badgedIcon, false).icon;
-
return info;
}
@@ -215,66 +206,11 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
info.expandedView.initialize(controller, stackView, false /* isOverflow */);
}
- if (b.getShortcutInfo() != null) {
- info.shortcutInfo = b.getShortcutInfo();
- }
-
- // App name & app icon
- PackageManager pm = BubbleController.getPackageManagerForUser(c,
- b.getUser().getIdentifier());
- ApplicationInfo appInfo;
- Drawable badgedIcon;
- Drawable appIcon;
- try {
- appInfo = pm.getApplicationInfo(
- b.getPackageName(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE);
- if (appInfo != null) {
- info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
- }
- appIcon = pm.getApplicationIcon(b.getPackageName());
- badgedIcon = pm.getUserBadgedIcon(appIcon, b.getUser());
- } catch (PackageManager.NameNotFoundException exception) {
- // If we can't find package... don't think we should show the bubble.
- Log.w(TAG, "Unable to find package: " + b.getPackageName());
+ if (!populateCommonInfo(info, c, b, iconFactory)) {
+ // if we failed to update common fields return null
return null;
}
- // Badged bubble image
- Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
- b.getIcon());
- if (bubbleDrawable == null) {
- // Default to app icon
- bubbleDrawable = appIcon;
- }
-
- BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon,
- b.isImportantConversation());
- info.badgeBitmap = badgeBitmapInfo.icon;
- // Raw badge bitmap never includes the important conversation ring
- info.rawBadgeBitmap = b.isImportantConversation()
- ? iconFactory.getBadgeBitmap(badgedIcon, false).icon
- : badgeBitmapInfo.icon;
-
- float[] bubbleBitmapScale = new float[1];
- info.bubbleBitmap = iconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);
-
- // Dot color & placement
- Path iconPath = PathParser.createPathFromPathData(
- c.getResources().getString(com.android.internal.R.string.config_icon_mask));
- Matrix matrix = new Matrix();
- float scale = bubbleBitmapScale[0];
- float radius = DEFAULT_PATH_SIZE / 2f;
- matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
- radius /* pivot y */);
- iconPath.transform(matrix);
- info.dotPath = iconPath;
- info.dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
- Color.WHITE, WHITE_SCRIM_ALPHA);
-
// Flyout
info.flyoutMessage = b.getFlyoutMessage();
if (info.flyoutMessage != null) {
@@ -285,6 +221,75 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
}
}
+ /**
+ * Modifies the given {@code info} object and populates common fields in it.
+ *
+ * <p>This method returns {@code true} if the update was successful and {@code false} otherwise.
+ * Callers should assume that the info object is unusable if the update was unsuccessful.
+ */
+ private static boolean populateCommonInfo(
+ BubbleViewInfo info, Context c, Bubble b, BubbleIconFactory iconFactory) {
+ if (b.getShortcutInfo() != null) {
+ info.shortcutInfo = b.getShortcutInfo();
+ }
+
+ // App name & app icon
+ PackageManager pm = BubbleController.getPackageManagerForUser(c,
+ b.getUser().getIdentifier());
+ ApplicationInfo appInfo;
+ Drawable badgedIcon;
+ Drawable appIcon;
+ try {
+ appInfo = pm.getApplicationInfo(
+ b.getPackageName(),
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+ if (appInfo != null) {
+ info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
+ }
+ appIcon = pm.getApplicationIcon(b.getPackageName());
+ badgedIcon = pm.getUserBadgedIcon(appIcon, b.getUser());
+ } catch (PackageManager.NameNotFoundException exception) {
+ // If we can't find package... don't think we should show the bubble.
+ Log.w(TAG, "Unable to find package: " + b.getPackageName());
+ return false;
+ }
+
+ // Badged bubble image
+ Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo, b.getIcon());
+ if (bubbleDrawable == null) {
+ // Default to app icon
+ bubbleDrawable = appIcon;
+ }
+
+ BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon,
+ b.isImportantConversation());
+ info.badgeBitmap = badgeBitmapInfo.icon;
+ // Raw badge bitmap never includes the important conversation ring
+ info.rawBadgeBitmap = b.isImportantConversation() // is this needed for bar?
+ ? iconFactory.getBadgeBitmap(badgedIcon, false).icon
+ : badgeBitmapInfo.icon;
+
+ float[] bubbleBitmapScale = new float[1];
+ info.bubbleBitmap = iconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);
+
+ // Dot color & placement
+ Path iconPath = PathParser.createPathFromPathData(
+ c.getResources().getString(com.android.internal.R.string.config_icon_mask));
+ Matrix matrix = new Matrix();
+ float scale = bubbleBitmapScale[0];
+ float radius = DEFAULT_PATH_SIZE / 2f;
+ matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
+ radius /* pivot y */);
+ iconPath.transform(matrix);
+ info.dotPath = iconPath;
+ info.dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
+ Color.WHITE, WHITE_SCRIM_ALPHA);
+ return true;
+ }
+
@Nullable
static Drawable loadSenderAvatar(@NonNull final Context context, @Nullable final Icon icon) {
Objects.requireNonNull(context);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 4d329dd5d446..759246eb285d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -60,9 +60,11 @@ public interface Bubbles {
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
- DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_REMOVED})
+ DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_REMOVED,
+ DISMISS_SWITCH_TO_STACK})
@Target({FIELD, LOCAL_VARIABLE, PARAMETER})
- @interface DismissReason {}
+ @interface DismissReason {
+ }
int DISMISS_USER_GESTURE = 1;
int DISMISS_AGED = 2;
@@ -80,6 +82,7 @@ public interface Bubbles {
int DISMISS_NO_BUBBLE_UP = 14;
int DISMISS_RELOAD_FROM_DISK = 15;
int DISMISS_USER_REMOVED = 16;
+ int DISMISS_SWITCH_TO_STACK = 17;
/** Returns a binder that can be passed to an external process to manipulate Bubbles. */
default IBubbles createExternalInterface() {
@@ -120,8 +123,8 @@ public interface Bubbles {
/**
* This method has different behavior depending on:
- * - if an app bubble exists
- * - if an app bubble is expanded
+ * - if an app bubble exists
+ * - if an app bubble is expanded
*
* If no app bubble exists, this will add and expand a bubble with the provided intent. The
* intent must be explicit (i.e. include a package name or fully qualified component class name)
@@ -135,13 +138,13 @@ public interface Bubbles {
* the bubble or bubble stack.
*
* Some notes:
- * - Only one app bubble is supported at a time, regardless of users. Multi-users support is
- * tracked in b/273533235.
- * - Calling this method with a different intent than the existing app bubble will do nothing
+ * - Only one app bubble is supported at a time, regardless of users. Multi-users support is
+ * tracked in b/273533235.
+ * - Calling this method with a different intent than the existing app bubble will do nothing
*
* @param intent the intent to display in the bubble expanded view.
- * @param user the {@link UserHandle} of the user to start this activity for.
- * @param icon the {@link Icon} to use for the bubble view.
+ * @param user the {@link UserHandle} of the user to start this activity for.
+ * @param icon the {@link Icon} to use for the bubble view.
*/
void showOrHideAppBubble(Intent intent, UserHandle user, @Nullable Icon icon);
@@ -172,13 +175,12 @@ public interface Bubbles {
* {@link Bubble#setSuppressNotification}. For the case of suppressed summaries, we also add
* {@link BubbleData#addSummaryToSuppress}.
*
- * @param entry the notification of the BubbleEntry should be removed.
- * @param children the list of child notification of the BubbleEntry from 1st param entry,
- * this will be null if entry does have no children.
+ * @param entry the notification of the BubbleEntry should be removed.
+ * @param children the list of child notification of the BubbleEntry from 1st param entry,
+ * this will be null if entry does have no children.
* @param removeCallback the remove callback for SystemUI side to remove notification, the int
* number should be list position of children list and use -1 for
* removing the parent notification.
- *
* @return true if we want to intercept the dismissal of the entry, else false.
*/
boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
@@ -200,9 +202,9 @@ public interface Bubbles {
/**
* Called when new notification entry updated.
*
- * @param entry the {@link BubbleEntry} by the notification.
+ * @param entry the {@link BubbleEntry} by the notification.
* @param shouldBubbleUp {@code true} if this notification should bubble up.
- * @param fromSystem {@code true} if this update is from NotificationManagerService.
+ * @param fromSystem {@code true} if this update is from NotificationManagerService.
*/
void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp, boolean fromSystem);
@@ -218,7 +220,7 @@ public interface Bubbles {
* filtering and sorting. This is used to dismiss or create bubbles based on changes in
* permissions on the notification channel or the global setting.
*
- * @param rankingMap the updated ranking map from NotificationListenerService
+ * @param rankingMap the updated ranking map from NotificationListenerService
* @param entryDataByKey a map of ranking key to bubble entry and whether the entry should
* bubble up
*/
@@ -230,9 +232,9 @@ public interface Bubbles {
* Called when a notification channel is modified, in response to
* {@link NotificationListenerService#onNotificationChannelModified}.
*
- * @param pkg the package the notification channel belongs to.
- * @param user the user the notification channel belongs to.
- * @param channel the channel being modified.
+ * @param pkg the package the notification channel belongs to.
+ * @param user the user the notification channel belongs to.
+ * @param channel the channel being modified.
* @param modificationType the type of modification that occurred to the channel.
*/
void onNotificationChannelModified(
@@ -300,7 +302,7 @@ public interface Bubbles {
* Called when the expansion state of the bubble stack changes.
*
* @param isExpanding whether it's expanding or collapsing
- * @param key the notification key associated with bubble being expanded
+ * @param key the notification key associated with bubble being expanded
*/
void onBubbleExpandChanged(boolean isExpanding, String key);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt
new file mode 100644
index 000000000000..ed3624035757
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+@file:JvmName("DismissViewUtils")
+
+package com.android.wm.shell.bubbles
+
+import com.android.wm.shell.R
+import com.android.wm.shell.common.bubbles.DismissView
+
+fun DismissView.setup() {
+ setup(DismissView.Config(
+ targetSizeResId = R.dimen.dismiss_circle_size,
+ iconSizeResId = R.dimen.dismiss_target_x_size,
+ bottomMarginResId = R.dimen.floating_dismiss_bottom_margin,
+ floatingGradientHeightResId = R.dimen.floating_dismiss_gradient_height,
+ floatingGradientColorResId = android.R.color.system_neutral1_900,
+ backgroundResId = R.drawable.dismiss_circle_background,
+ iconResId = R.drawable.pip_ic_close_white
+ ))
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
index 862e818a998b..4dda0688b790 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
@@ -29,12 +29,14 @@ interface IBubbles {
oneway void unregisterBubbleListener(in IBubblesListener listener) = 2;
- oneway void showBubble(in String key, in boolean onLauncherHome) = 3;
+ oneway void showBubble(in String key, in int bubbleBarOffsetX, in int bubbleBarOffsetY) = 3;
- oneway void removeBubble(in String key, in int reason) = 4;
+ oneway void removeBubble(in String key) = 4;
- oneway void collapseBubbles() = 5;
+ oneway void removeAllBubbles() = 5;
- oneway void onTaskbarStateChanged(in int newState) = 6;
+ oneway void collapseBubbles() = 6;
+
+ oneway void onBubbleDrag(in String key, in boolean isBeingDragged) = 7;
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
index beb1c5fa6c10..f3cc514d2972 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
@@ -327,6 +327,12 @@ public class PhysicsAnimationLayout extends FrameLayout {
addViewInternal(child, index, params, false /* isReorder */);
}
+ /** Removes the child view immediately. */
+ public void removeViewNoAnimation(View view) {
+ super.removeView(view);
+ view.setTag(R.id.physics_animator_tag, null);
+ }
+
@Override
public void removeView(View view) {
if (mController != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 23f65f943aa4..689323b725ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -21,12 +21,15 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.PointF;
+import android.graphics.Point;
import android.util.Log;
import android.widget.FrameLayout;
+import androidx.annotation.Nullable;
+
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
@@ -110,7 +113,8 @@ public class BubbleBarAnimationHelper {
/**
* Animates the provided bubble's expanded view to the expanded state.
*/
- public void animateExpansion(BubbleViewProvider expandedBubble) {
+ public void animateExpansion(BubbleViewProvider expandedBubble,
+ @Nullable Runnable afterAnimation) {
mExpandedBubble = expandedBubble;
if (mExpandedBubble == null) {
return;
@@ -132,7 +136,7 @@ public class BubbleBarAnimationHelper {
bev.setVisibility(VISIBLE);
// Set the pivot point for the scale, so the view animates out from the bubble bar.
- PointF bubbleBarPosition = mPositioner.getBubbleBarPosition();
+ Point bubbleBarPosition = mPositioner.getBubbleBarPosition();
mExpandedViewContainerMatrix.setScale(
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
@@ -159,6 +163,9 @@ public class BubbleBarAnimationHelper {
bev.setAnimationMatrix(null);
updateExpandedView();
bev.setSurfaceZOrderedOnTop(false);
+ if (afterAnimation != null) {
+ afterAnimation.run();
+ }
})
.start();
}
@@ -208,6 +215,14 @@ public class BubbleBarAnimationHelper {
mExpandedViewAlphaAnimator.reverse();
}
+ /**
+ * Cancel current animations
+ */
+ public void cancelAnimations() {
+ PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
+ mExpandedViewAlphaAnimator.cancel();
+ }
+
private void updateExpandedView() {
if (mExpandedBubble == null || mExpandedBubble.getBubbleBarExpandedView() == null) {
Log.w(TAG, "Trying to update the expanded view without a bubble");
@@ -215,9 +230,10 @@ public class BubbleBarAnimationHelper {
}
BubbleBarExpandedView bbev = mExpandedBubble.getBubbleBarExpandedView();
+ boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
final int padding = mPositioner.getBubbleBarExpandedViewPadding();
- final int width = mPositioner.getExpandedViewWidthForBubbleBar();
- final int height = mPositioner.getExpandedViewHeightForBubbleBar();
+ final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
+ final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) bbev.getLayoutParams();
lp.width = width;
lp.height = height;
@@ -227,7 +243,8 @@ public class BubbleBarAnimationHelper {
} else {
bbev.setX(mPositioner.getAvailableRect().width() - width - padding);
}
- bbev.setY(mPositioner.getInsets().top + padding);
+ bbev.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
bbev.updateLocation();
+ bbev.maybeShowOverflow();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index b8f049becb6f..6b6d6baa3d39 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -16,12 +16,16 @@
package com.android.wm.shell.bubbles.bar;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.Outline;
+import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
@@ -30,9 +34,14 @@ import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.BubbleOverflowContainerView;
import com.android.wm.shell.bubbles.BubbleTaskViewHelper;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.taskview.TaskView;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
/**
* Expanded view of a bubble when it's part of the bubble bar.
*
@@ -44,12 +53,18 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
private static final int INVALID_TASK_ID = -1;
private BubbleController mController;
+ private boolean mIsOverflow;
private BubbleTaskViewHelper mBubbleTaskViewHelper;
+ private BubbleBarMenuViewController mMenuViewController;
+ private @Nullable Supplier<Rect> mLayerBoundsSupplier;
+ private @Nullable Consumer<String> mUnBubbleConversationCallback;
+
+ private BubbleBarHandleView mHandleView = new BubbleBarHandleView(getContext());
+ private @Nullable TaskView mTaskView;
+ private @Nullable BubbleOverflowContainerView mOverflowView;
- private HandleView mMenuView;
- private TaskView mTaskView;
+ private int mCaptionHeight;
- private int mMenuHeight;
private int mBackgroundColor;
private float mCornerRadius = 0f;
@@ -83,11 +98,9 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
super.onFinishInflate();
Context context = getContext();
setElevation(getResources().getDimensionPixelSize(R.dimen.bubble_elevation));
- mMenuHeight = context.getResources().getDimensionPixelSize(
- R.dimen.bubblebar_expanded_view_menu_size);
- mMenuView = new HandleView(context);
- addView(mMenuView);
-
+ mCaptionHeight = context.getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_height);
+ addView(mHandleView);
applyThemeAttrs();
setClipToOutline(true);
setOutlineProvider(new ViewOutlineProvider() {
@@ -98,23 +111,78 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
});
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ // Hide manage menu when view disappears
+ mMenuViewController.hideMenu(false /* animated */);
+ }
+
/** Set the BubbleController on the view, must be called before doing anything else. */
- public void initialize(BubbleController controller) {
+ public void initialize(BubbleController controller, boolean isOverflow) {
mController = controller;
- mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, mController,
- /* listener= */ this,
- /* viewParent= */ this);
- mTaskView = mBubbleTaskViewHelper.getTaskView();
- addView(mTaskView);
- mTaskView.setEnableSurfaceClipping(true);
- mTaskView.setCornerRadius(mCornerRadius);
+ mIsOverflow = isOverflow;
+
+ if (mIsOverflow) {
+ mOverflowView = (BubbleOverflowContainerView) LayoutInflater.from(getContext()).inflate(
+ R.layout.bubble_overflow_container, null /* root */);
+ mOverflowView.setBubbleController(mController);
+ addView(mOverflowView);
+ } else {
+
+ mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, mController,
+ /* listener= */ this,
+ /* viewParent= */ this);
+ mTaskView = mBubbleTaskViewHelper.getTaskView();
+ addView(mTaskView);
+ mTaskView.setEnableSurfaceClipping(true);
+ mTaskView.setCornerRadius(mCornerRadius);
+
+ // Handle view needs to draw on top of task view.
+ bringChildToFront(mHandleView);
+ }
+ mMenuViewController = new BubbleBarMenuViewController(mContext, this);
+ mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
+ @Override
+ public void onMenuVisibilityChanged(boolean visible) {
+ if (mTaskView == null || mLayerBoundsSupplier == null) return;
+ // Updates the obscured touchable region for the task surface.
+ mTaskView.setObscuredTouchRect(visible ? mLayerBoundsSupplier.get() : null);
+ }
+
+ @Override
+ public void onUnBubbleConversation(Bubble bubble) {
+ if (mUnBubbleConversationCallback != null) {
+ mUnBubbleConversationCallback.accept(bubble.getKey());
+ }
+ }
+
+ @Override
+ public void onOpenAppSettings(Bubble bubble) {
+ mController.collapseStack();
+ mContext.startActivityAsUser(bubble.getSettingsIntent(mContext), bubble.getUser());
+ }
+
+ @Override
+ public void onDismissBubble(Bubble bubble) {
+ mController.dismissBubble(bubble, Bubbles.DISMISS_USER_REMOVED);
+ }
+ });
+ mHandleView.setOnClickListener(view -> {
+ mMenuViewController.showMenu(true /* animated */);
+ });
+ }
+
+ public BubbleBarHandleView getHandleView() {
+ return mHandleView;
}
// TODO (b/275087636): call this when theme/config changes
- void applyThemeAttrs() {
+ /** Updates the view based on the current theme. */
+ public void applyThemeAttrs() {
boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
mContext.getResources());
- final TypedArray ta = mContext.obtainStyledAttributes(new int[] {
+ final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
android.R.attr.dialogCornerRadius,
android.R.attr.colorBackgroundFloating});
mCornerRadius = supportsRoundedCorners ? ta.getDimensionPixelSize(0, 0) : 0;
@@ -123,14 +191,12 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
ta.recycle();
- mMenuView.setCornerRadius(mCornerRadius);
- mMenuHeight = getResources().getDimensionPixelSize(
- R.dimen.bubblebar_expanded_view_menu_size);
+ mCaptionHeight = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_height);
if (mTaskView != null) {
mTaskView.setCornerRadius(mCornerRadius);
- mTaskView.setElevation(150);
- updateMenuColor();
+ updateHandleColor(true /* animated */);
}
}
@@ -138,35 +204,33 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
-
- // Add corner radius here so that the menu extends behind the rounded corners of TaskView.
- int menuViewHeight = Math.min((int) (mMenuHeight + mCornerRadius), height);
- measureChild(mMenuView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(menuViewHeight,
+ int menuViewHeight = Math.min(mCaptionHeight, height);
+ measureChild(mHandleView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(menuViewHeight,
MeasureSpec.getMode(heightMeasureSpec)));
if (mTaskView != null) {
- int taskViewHeight = height - menuViewHeight;
- measureChild(mTaskView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(taskViewHeight,
+ measureChild(mTaskView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(height,
MeasureSpec.getMode(heightMeasureSpec)));
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
- // Drag handle above
- final int dragHandleBottom = t + mMenuView.getMeasuredHeight();
- mMenuView.layout(l, t, r, dragHandleBottom);
+ super.onLayout(changed, l, t, r, b);
+ final int captionBottom = t + mCaptionHeight;
if (mTaskView != null) {
- // Subtract radius so that the menu extends behind the rounded corners of TaskView.
- mTaskView.layout(l, (int) (dragHandleBottom - mCornerRadius), r,
- dragHandleBottom + mTaskView.getMeasuredHeight());
+ mTaskView.layout(l, t, r,
+ t + mTaskView.getMeasuredHeight());
+ mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
}
+ // Handle draws on top of task view in the caption area.
+ mHandleView.layout(l, t, r, captionBottom);
}
@Override
public void onTaskCreated() {
setContentVisibility(true);
- updateMenuColor();
+ updateHandleColor(false /* animated */);
}
@Override
@@ -187,11 +251,13 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
}
mBubbleTaskViewHelper.cleanUpTaskView();
}
+ mMenuViewController.hideMenu(false /* animated */);
}
- /** Updates the bubble shown in this task view. */
+ /** Updates the bubble shown in the expanded view. */
public void update(Bubble bubble) {
mBubbleTaskViewHelper.update(bubble);
+ mMenuViewController.updateMenu(bubble);
}
/** The task id of the activity shown in the task view, if it exists. */
@@ -199,12 +265,33 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
return mBubbleTaskViewHelper != null ? mBubbleTaskViewHelper.getTaskId() : INVALID_TASK_ID;
}
+ /** Sets layer bounds supplier used for obscured touchable region of task view */
+ void setLayerBoundsSupplier(@Nullable Supplier<Rect> supplier) {
+ mLayerBoundsSupplier = supplier;
+ }
+
+ /** Sets the function to call to un-bubble the given conversation. */
+ public void setUnBubbleConversationCallback(
+ @Nullable Consumer<String> unBubbleConversationCallback) {
+ mUnBubbleConversationCallback = unBubbleConversationCallback;
+ }
+
/**
* Call when the location or size of the view has changed to update TaskView.
*/
public void updateLocation() {
- if (mTaskView == null) return;
- mTaskView.onLocationChanged();
+ if (mTaskView != null) {
+ mTaskView.onLocationChanged();
+ }
+ }
+
+ /** Shows the expanded view for the overflow if it exists. */
+ void maybeShowOverflow() {
+ if (mOverflowView != null) {
+ // post this to the looper so that the view has a chance to be laid out before it can
+ // calculate row and column sizes correctly.
+ post(() -> mOverflowView.show());
+ }
}
/** Sets the alpha of the task view. */
@@ -218,17 +305,21 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
}
}
- /** Updates the menu bar to be the status bar color specified by the app. */
- private void updateMenuColor() {
- if (mTaskView == null) return;
- ActivityManager.RunningTaskInfo info = mTaskView.getTaskInfo();
- final int taskBgColor = info.taskDescription.getStatusBarColor();
- final int color = Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb();
- if (color != -1) {
- mMenuView.setBackgroundColor(color);
- } else {
- mMenuView.setBackgroundColor(mBackgroundColor);
+ /**
+ * Updates the handle color based on the task view status bar or background color; if those
+ * are transparent it defaults to the background color pulled from system theme attributes.
+ */
+ private void updateHandleColor(boolean animated) {
+ if (mTaskView == null || mTaskView.getTaskInfo() == null) return;
+ int color = mBackgroundColor;
+ ActivityManager.TaskDescription taskDescription = mTaskView.getTaskInfo().taskDescription;
+ if (taskDescription.getStatusBarColor() != Color.TRANSPARENT) {
+ color = taskDescription.getStatusBarColor();
+ } else if (taskDescription.getBackgroundColor() != Color.TRANSPARENT) {
+ color = taskDescription.getBackgroundColor();
}
+ final boolean isRegionDark = Color.luminance(color) <= 0.5;
+ mHandleView.updateHandleColor(isRegionDark, animated);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
new file mode 100644
index 000000000000..2b7a0706b4de
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2023 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.bubbles.bar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Outline;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import androidx.annotation.ColorInt;
+import androidx.core.content.ContextCompat;
+
+import com.android.wm.shell.R;
+
+/**
+ * Handle view to show at the top of a bubble bar expanded view.
+ */
+public class BubbleBarHandleView extends View {
+ private static final long COLOR_CHANGE_DURATION = 120;
+
+ // The handle view is currently rendered as 3 evenly spaced dots.
+ private int mDotSize;
+ private int mDotSpacing;
+ // Path used to draw the dots
+ private final Path mPath = new Path();
+
+ private @ColorInt int mHandleLightColor;
+ private @ColorInt int mHandleDarkColor;
+ private @Nullable ObjectAnimator mColorChangeAnim;
+
+ public BubbleBarHandleView(Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public BubbleBarHandleView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0 /* defStyleAttr */);
+ }
+
+ public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
+ }
+
+ public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ mDotSize = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_dot_size);
+ mDotSpacing = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_dot_spacing);
+ mHandleLightColor = ContextCompat.getColor(getContext(),
+ R.color.bubble_bar_expanded_view_handle_light);
+ mHandleDarkColor = ContextCompat.getColor(getContext(),
+ R.color.bubble_bar_expanded_view_handle_dark);
+
+ setClipToOutline(true);
+ setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ final int handleCenterX = view.getWidth() / 2;
+ final int handleCenterY = view.getHeight() / 2;
+ final int handleTotalWidth = mDotSize * 3 + mDotSpacing * 2;
+ final int handleLeft = handleCenterX - handleTotalWidth / 2;
+ final int handleTop = handleCenterY - mDotSize / 2;
+ final int handleBottom = handleTop + mDotSize;
+ RectF dot1 = new RectF(
+ handleLeft, handleTop,
+ handleLeft + mDotSize, handleBottom);
+ RectF dot2 = new RectF(
+ dot1.right + mDotSpacing, handleTop,
+ dot1.right + mDotSpacing + mDotSize, handleBottom
+ );
+ RectF dot3 = new RectF(
+ dot2.right + mDotSpacing, handleTop,
+ dot2.right + mDotSpacing + mDotSize, handleBottom
+ );
+ mPath.reset();
+ mPath.addOval(dot1, Path.Direction.CW);
+ mPath.addOval(dot2, Path.Direction.CW);
+ mPath.addOval(dot3, Path.Direction.CW);
+ outline.setPath(mPath);
+ }
+ });
+ }
+
+ /**
+ * Updates the handle color.
+ *
+ * @param isRegionDark Whether the background behind the handle is dark, and thus the handle
+ * should be light (and vice versa).
+ * @param animated Whether to animate the change, or apply it immediately.
+ */
+ public void updateHandleColor(boolean isRegionDark, boolean animated) {
+ int newColor = isRegionDark ? mHandleLightColor : mHandleDarkColor;
+ if (mColorChangeAnim != null) {
+ mColorChangeAnim.cancel();
+ }
+ if (animated) {
+ mColorChangeAnim = ObjectAnimator.ofArgb(this, "backgroundColor", newColor);
+ mColorChangeAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mColorChangeAnim = null;
+ }
+ });
+ mColorChangeAnim.setDuration(COLOR_CHANGE_DURATION);
+ mColorChangeAnim.start();
+ } else {
+ setBackgroundColor(newColor);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index b1a725b6e5c4..bc04bfc8c18b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -24,14 +24,18 @@ import android.content.Context;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
+import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
+import java.util.function.Consumer;
+
/**
* Similar to {@link com.android.wm.shell.bubbles.BubbleStackView}, this view is added to window
* manager to display bubbles. However, it is only used when bubbles are being displayed in
@@ -53,6 +57,7 @@ public class BubbleBarLayerView extends FrameLayout
@Nullable
private BubbleViewProvider mExpandedBubble;
private BubbleBarExpandedView mExpandedView;
+ private @Nullable Consumer<String> mUnBubbleConversationCallback;
// TODO(b/273310265) - currently the view is always on the right, need to update for RTL.
/** Whether the expanded view is displaying on the left of the screen or not. */
@@ -64,6 +69,10 @@ public class BubbleBarLayerView extends FrameLayout
private final Region mTouchableRegion = new Region();
private final Rect mTempRect = new Rect();
+ // Used to ensure touch target size for the menu shown on a bubble expanded view
+ private TouchDelegate mHandleTouchDelegate;
+ private final Rect mHandleTouchBounds = new Rect();
+
public BubbleBarLayerView(Context context, BubbleController controller) {
super(context);
mBubbleController = controller;
@@ -141,17 +150,42 @@ public class BubbleBarLayerView extends FrameLayout
mExpandedView = null;
}
if (mExpandedView == null) {
+ if (expandedView.getParent() != null) {
+ // Expanded view might be animating collapse and is still attached
+ // Cancel current animations and remove from parent
+ mAnimationHelper.cancelAnimations();
+ removeView(expandedView);
+ }
mExpandedBubble = b;
mExpandedView = expandedView;
- final int width = mPositioner.getExpandedViewWidthForBubbleBar();
- final int height = mPositioner.getExpandedViewHeightForBubbleBar();
+ boolean isOverflowExpanded = b.getKey().equals(BubbleOverflow.KEY);
+ final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
+ final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
mExpandedView.setVisibility(GONE);
+ mExpandedView.setUnBubbleConversationCallback(mUnBubbleConversationCallback);
+ mExpandedView.setLayerBoundsSupplier(() -> new Rect(0, 0, getWidth(), getHeight()));
+ mExpandedView.setUnBubbleConversationCallback(bubbleKey -> {
+ if (mUnBubbleConversationCallback != null) {
+ mUnBubbleConversationCallback.accept(bubbleKey);
+ }
+ });
+ mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
addView(mExpandedView, new FrameLayout.LayoutParams(width, height));
}
mIsExpanded = true;
mBubbleController.getSysuiProxy().onStackExpandChanged(true);
- mAnimationHelper.animateExpansion(mExpandedBubble);
+ mAnimationHelper.animateExpansion(mExpandedBubble, () -> {
+ if (mExpandedView == null) return;
+ // Touch delegate for the menu
+ BubbleBarHandleView view = mExpandedView.getHandleView();
+ view.getBoundsOnScreen(mHandleTouchBounds);
+ mHandleTouchBounds.top -= mPositioner.getBubblePaddingTop();
+ mHandleTouchDelegate = new TouchDelegate(mHandleTouchBounds,
+ mExpandedView.getHandleView());
+ setTouchDelegate(mHandleTouchDelegate);
+ });
+
showScrim(true);
}
@@ -162,15 +196,23 @@ public class BubbleBarLayerView extends FrameLayout
mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
mBubbleController.getSysuiProxy().onStackExpandChanged(false);
mExpandedView = null;
+ setTouchDelegate(null);
showScrim(false);
}
+ /** Sets the function to call to un-bubble the given conversation. */
+ public void setUnBubbleConversationCallback(
+ @Nullable Consumer<String> unBubbleConversationCallback) {
+ mUnBubbleConversationCallback = unBubbleConversationCallback;
+ }
+
/** Updates the expanded view size and position. */
private void updateExpandedView() {
if (mExpandedView == null) return;
+ boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
final int padding = mPositioner.getBubbleBarExpandedViewPadding();
- final int width = mPositioner.getExpandedViewWidthForBubbleBar();
- final int height = mPositioner.getExpandedViewHeightForBubbleBar();
+ final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
+ final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
FrameLayout.LayoutParams lp = (LayoutParams) mExpandedView.getLayoutParams();
lp.width = width;
lp.height = height;
@@ -180,7 +222,7 @@ public class BubbleBarLayerView extends FrameLayout
} else {
mExpandedView.setX(mPositioner.getAvailableRect().width() - width - padding);
}
- mExpandedView.setY(mPositioner.getInsets().top + padding);
+ mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
mExpandedView.updateLocation();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuItemView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuItemView.java
new file mode 100644
index 000000000000..00b977721bea
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuItemView.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 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.bubbles.bar;
+
+import android.annotation.ColorInt;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.wm.shell.R;
+
+/**
+ * Bubble bar expanded view menu item view to display menu action details
+ */
+public class BubbleBarMenuItemView extends LinearLayout {
+ private ImageView mImageView;
+ private TextView mTextView;
+
+ public BubbleBarMenuItemView(Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public BubbleBarMenuItemView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0 /* defStyleAttr */);
+ }
+
+ public BubbleBarMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
+ }
+
+ public BubbleBarMenuItemView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mImageView = findViewById(R.id.bubble_bar_menu_item_icon);
+ mTextView = findViewById(R.id.bubble_bar_menu_item_title);
+ }
+
+ /**
+ * Update menu item with the details and tint color
+ */
+ void update(Icon icon, String title, @ColorInt int tint) {
+ if (tint == Color.TRANSPARENT) {
+ final TypedArray typedArray = getContext().obtainStyledAttributes(
+ new int[]{android.R.attr.textColorPrimary});
+ mTextView.setTextColor(typedArray.getColor(0, Color.BLACK));
+ } else {
+ icon.setTint(tint);
+ mTextView.setTextColor(tint);
+ }
+
+ mImageView.setImageIcon(icon);
+ mTextView.setText(title);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
new file mode 100644
index 000000000000..211fe0d48e43
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2023 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.bubbles.bar;
+
+import android.annotation.ColorInt;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.bubbles.Bubble;
+
+import java.util.ArrayList;
+
+/**
+ * Bubble bar expanded view menu
+ */
+public class BubbleBarMenuView extends LinearLayout {
+ private ViewGroup mBubbleSectionView;
+ private ViewGroup mActionsSectionView;
+ private ImageView mBubbleIconView;
+ private TextView mBubbleTitleView;
+
+ public BubbleBarMenuView(Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public BubbleBarMenuView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0 /* defStyleAttr */);
+ }
+
+ public BubbleBarMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
+ }
+
+ public BubbleBarMenuView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mBubbleSectionView = findViewById(R.id.bubble_bar_manage_menu_bubble_section);
+ mActionsSectionView = findViewById(R.id.bubble_bar_manage_menu_actions_section);
+ mBubbleIconView = findViewById(R.id.bubble_bar_manage_menu_bubble_icon);
+ mBubbleTitleView = findViewById(R.id.bubble_bar_manage_menu_bubble_title);
+ }
+
+ /** Update menu details with bubble info */
+ void updateInfo(Bubble bubble) {
+ if (bubble.getIcon() != null) {
+ mBubbleIconView.setImageIcon(bubble.getIcon());
+ } else {
+ mBubbleIconView.setImageBitmap(bubble.getBubbleIcon());
+ }
+ mBubbleTitleView.setText(bubble.getTitle());
+ }
+
+ /**
+ * Update menu action items views
+ * @param actions used to populate menu item views
+ */
+ void updateActions(ArrayList<MenuAction> actions) {
+ mActionsSectionView.removeAllViews();
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+
+ for (MenuAction action : actions) {
+ BubbleBarMenuItemView itemView = (BubbleBarMenuItemView) inflater.inflate(
+ R.layout.bubble_bar_menu_item, mActionsSectionView, false);
+ itemView.update(action.mIcon, action.mTitle, action.mTint);
+ itemView.setOnClickListener(action.mOnClick);
+ mActionsSectionView.addView(itemView);
+ }
+ }
+
+ /** Sets on close menu listener */
+ void setOnCloseListener(Runnable onClose) {
+ mBubbleSectionView.setOnClickListener(view -> {
+ onClose.run();
+ });
+ }
+
+ /**
+ * Overridden to proxy to section views alpha.
+ * @implNote
+ * If animate alpha on the parent (menu container) view, section view shadows get distorted.
+ * To prevent distortion and artifacts alpha changes applied directly on the section views.
+ */
+ @Override
+ public void setAlpha(float alpha) {
+ mBubbleSectionView.setAlpha(alpha);
+ mActionsSectionView.setAlpha(alpha);
+ }
+
+ /**
+ * Overridden to proxy section view alpha value.
+ * @implNote
+ * The assumption is that both section views have the same alpha value
+ */
+ @Override
+ public float getAlpha() {
+ return mBubbleSectionView.getAlpha();
+ }
+
+ /**
+ * Menu action details used to create menu items
+ */
+ static class MenuAction {
+ private Icon mIcon;
+ private @ColorInt int mTint;
+ private String mTitle;
+ private OnClickListener mOnClick;
+
+ MenuAction(Icon icon, String title, OnClickListener onClick) {
+ this(icon, title, Color.TRANSPARENT, onClick);
+ }
+
+ MenuAction(Icon icon, String title, @ColorInt int tint, OnClickListener onClick) {
+ this.mIcon = icon;
+ this.mTitle = title;
+ this.mTint = tint;
+ this.mOnClick = onClick;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
new file mode 100644
index 000000000000..8be140c16435
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2023 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.bubbles.bar;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.core.content.ContextCompat;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.Bubble;
+
+import java.util.ArrayList;
+
+/**
+ * Manages bubble bar expanded view menu presentation and animations
+ */
+class BubbleBarMenuViewController {
+ private static final float MENU_INITIAL_SCALE = 0.5f;
+ private final Context mContext;
+ private final ViewGroup mRootView;
+ private @Nullable Listener mListener;
+ private @Nullable Bubble mBubble;
+ private @Nullable BubbleBarMenuView mMenuView;
+ /** A transparent view used to intercept touches to collapse menu when presented */
+ private @Nullable View mScrimView;
+ private @Nullable PhysicsAnimator<BubbleBarMenuView> mMenuAnimator;
+ private PhysicsAnimator.SpringConfig mMenuSpringConfig;
+
+ BubbleBarMenuViewController(Context context, ViewGroup rootView) {
+ mContext = context;
+ mRootView = rootView;
+ mMenuSpringConfig = new PhysicsAnimator.SpringConfig(
+ SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
+ }
+
+ /** Sets menu actions listener */
+ void setListener(@Nullable Listener listener) {
+ mListener = listener;
+ }
+
+ /** Update menu with bubble */
+ void updateMenu(@NonNull Bubble bubble) {
+ mBubble = bubble;
+ }
+
+ /**
+ * Show bubble bar expanded view menu
+ * @param animated if should animate transition
+ */
+ void showMenu(boolean animated) {
+ if (mMenuView == null || mScrimView == null) {
+ setupMenu();
+ }
+ cancelAnimations();
+ mMenuView.setVisibility(View.VISIBLE);
+ mScrimView.setVisibility(View.VISIBLE);
+ Runnable endActions = () -> {
+ mMenuView.getChildAt(0).requestAccessibilityFocus();
+ if (mListener != null) {
+ mListener.onMenuVisibilityChanged(true /* isShown */);
+ }
+ };
+ if (animated) {
+ animateTransition(true /* show */, endActions);
+ } else {
+ endActions.run();
+ }
+ }
+
+ /**
+ * Hide bubble bar expanded view menu
+ * @param animated if should animate transition
+ */
+ void hideMenu(boolean animated) {
+ if (mMenuView == null || mScrimView == null) return;
+ cancelAnimations();
+ Runnable endActions = () -> {
+ mMenuView.setVisibility(View.GONE);
+ mScrimView.setVisibility(View.GONE);
+ if (mListener != null) {
+ mListener.onMenuVisibilityChanged(false /* isShown */);
+ }
+ };
+ if (animated) {
+ animateTransition(false /* show */, endActions);
+ } else {
+ endActions.run();
+ }
+ }
+
+ /**
+ * Animate show/hide menu transition
+ * @param show if should show or hide the menu
+ * @param endActions will be called when animation ends
+ */
+ private void animateTransition(boolean show, Runnable endActions) {
+ if (mMenuView == null) return;
+ mMenuAnimator = PhysicsAnimator.getInstance(mMenuView);
+ mMenuAnimator.setDefaultSpringConfig(mMenuSpringConfig);
+ mMenuAnimator
+ .spring(DynamicAnimation.ALPHA, show ? 1f : 0f)
+ .spring(DynamicAnimation.SCALE_Y, show ? 1f : MENU_INITIAL_SCALE)
+ .withEndActions(() -> {
+ mMenuAnimator = null;
+ endActions.run();
+ })
+ .start();
+ }
+
+ /** Cancel running animations */
+ private void cancelAnimations() {
+ if (mMenuAnimator != null) {
+ mMenuAnimator.cancel();
+ mMenuAnimator = null;
+ }
+ }
+
+ /** Sets up and inflate menu views */
+ private void setupMenu() {
+ // Menu view setup
+ mMenuView = (BubbleBarMenuView) LayoutInflater.from(mContext).inflate(
+ R.layout.bubble_bar_menu_view, mRootView, false);
+ mMenuView.setAlpha(0f);
+ mMenuView.setPivotY(0f);
+ mMenuView.setScaleY(MENU_INITIAL_SCALE);
+ mMenuView.setOnCloseListener(() -> hideMenu(true /* animated */));
+ if (mBubble != null) {
+ mMenuView.updateInfo(mBubble);
+ mMenuView.updateActions(createMenuActions(mBubble));
+ }
+ // Scrim view setup
+ mScrimView = new View(mContext);
+ mScrimView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ mScrimView.setOnClickListener(view -> hideMenu(true /* animated */));
+ // Attach to root view
+ mRootView.addView(mScrimView);
+ mRootView.addView(mMenuView);
+ }
+
+ /**
+ * Creates menu actions to populate menu view
+ * @param bubble used to create actions depending on bubble type
+ */
+ private ArrayList<BubbleBarMenuView.MenuAction> createMenuActions(Bubble bubble) {
+ ArrayList<BubbleBarMenuView.MenuAction> menuActions = new ArrayList<>();
+ Resources resources = mContext.getResources();
+
+ if (bubble.isConversation()) {
+ // Don't bubble conversation action
+ menuActions.add(new BubbleBarMenuView.MenuAction(
+ Icon.createWithResource(mContext, R.drawable.bubble_ic_stop_bubble),
+ resources.getString(R.string.bubbles_dont_bubble_conversation),
+ view -> {
+ hideMenu(true /* animated */);
+ if (mListener != null) {
+ mListener.onUnBubbleConversation(bubble);
+ }
+ }
+ ));
+ // Open settings action
+ Icon appIcon = bubble.getRawAppBadge() != null ? Icon.createWithBitmap(
+ bubble.getRawAppBadge()) : null;
+ menuActions.add(new BubbleBarMenuView.MenuAction(
+ appIcon,
+ resources.getString(R.string.bubbles_app_settings, bubble.getAppName()),
+ view -> {
+ hideMenu(true /* animated */);
+ if (mListener != null) {
+ mListener.onOpenAppSettings(bubble);
+ }
+ }
+ ));
+ }
+
+ // Dismiss bubble action
+ menuActions.add(new BubbleBarMenuView.MenuAction(
+ Icon.createWithResource(resources, R.drawable.ic_remove_no_shadow),
+ resources.getString(R.string.bubble_dismiss_text),
+ ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_menu_close),
+ view -> {
+ hideMenu(true /* animated */);
+ if (mListener != null) {
+ mListener.onDismissBubble(bubble);
+ }
+ }
+ ));
+
+ return menuActions;
+ }
+
+ /**
+ * Bubble bar expanded view menu actions listener
+ */
+ interface Listener {
+ /**
+ * Called when manage menu is shown/hidden
+ * If animated will be called when animation ends
+ */
+ void onMenuVisibilityChanged(boolean visible);
+
+ /**
+ * Un-bubbles conversation and removes the bubble from the stack
+ * This conversation will not be bubbled with new messages
+ * @see com.android.wm.shell.bubbles.BubbleController
+ */
+ void onUnBubbleConversation(Bubble bubble);
+
+ /**
+ * Launches app notification bubble settings for the bubble with intent created in:
+ * {@code Bubble.getSettingsIntent}
+ */
+ void onOpenAppSettings(Bubble bubble);
+
+ /**
+ * Dismiss bubble and remove it from the bubble stack
+ */
+ void onDismissBubble(Bubble bubble);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/HandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/HandleView.java
deleted file mode 100644
index 9ee8a9d98aa1..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/HandleView.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2023 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.bubbles.bar;
-
-import android.content.Context;
-import android.view.Gravity;
-import android.widget.LinearLayout;
-
-/**
- * Handle / menu view to show at the top of a bubble bar expanded view.
- */
-public class HandleView extends LinearLayout {
-
- // TODO(b/273307221): implement the manage menu in this view.
- public HandleView(Context context) {
- super(context);
- setOrientation(LinearLayout.HORIZONTAL);
- setGravity(Gravity.CENTER);
- }
-
- /**
- * The menu extends past the top of the TaskView because of the rounded corners. This means
- * to center content in the menu we must subtract the radius (i.e. the amount of space covered
- * by TaskView).
- */
- public void setCornerRadius(float radius) {
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), (int) radius);
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt
index bdfdad59c600..85aaa8ef585c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt
@@ -14,14 +14,19 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.bubble
+package com.android.wm.shell.bubbles.properties
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class ChangeActiveActivityFromBubbleTestCfArm(flicker: FlickerTest) :
- ChangeActiveActivityFromBubbleTest(flicker)
+/**
+ * An interface for exposing bubble properties via flags which can be controlled easily in tests.
+ */
+interface BubbleProperties {
+ /**
+ * Whether bubble bar is enabled.
+ *
+ * When this is `true`, depending on additional factors, such as screen size and taskbar state,
+ * bubbles will be displayed in the bubble bar instead of floating.
+ *
+ * When this is `false`, bubbles will be floating.
+ */
+ val isBubbleBarEnabled: Boolean
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt
index 6c61710d6284..9d8b9a6f3260 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.bubble
+package com.android.wm.shell.bubbles.properties
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
+import android.os.SystemProperties
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class OpenActivityFromBubbleTestCfArm(flicker: FlickerTest) : OpenActivityFromBubbleTest(flicker)
+/** Provides bubble properties in production. */
+object ProdBubbleProperties : BubbleProperties {
+
+ // TODO(b/256873975) Should use proper flag when available to shell/launcher
+ override val isBubbleBarEnabled =
+ SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/FloatingContentCoordinator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/FloatingContentCoordinator.kt
index d5d072a8d449..122dcbb3c2ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/FloatingContentCoordinator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/FloatingContentCoordinator.kt
@@ -94,7 +94,6 @@ class FloatingContentCoordinator constructor() {
* non-overlapping.
* @return The new bounds for this content.
*/
- @JvmDefault
fun calculateNewBoundsOnOverlap(
overlappingContentBounds: Rect,
otherContentBounds: List<Rect>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/LaunchAdjacentController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/LaunchAdjacentController.kt
new file mode 100644
index 000000000000..81592c35e4ac
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/LaunchAdjacentController.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023 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.common
+
+import android.window.WindowContainerToken
+import android.window.WindowContainerTransaction
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG
+import com.android.wm.shell.util.KtProtoLog
+
+/**
+ * Controller to manage behavior of activities launched with
+ * [android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT].
+ */
+class LaunchAdjacentController(private val syncQueue: SyncTransactionQueue) {
+
+ /** Allows to temporarily disable launch adjacent handling */
+ var launchAdjacentEnabled: Boolean = true
+ set(value) {
+ if (field != value) {
+ KtProtoLog.d(WM_SHELL_TASK_ORG, "set launch adjacent flag root enabled=%b", value)
+ field = value
+ container?.let { c ->
+ if (value) {
+ enableContainer(c)
+ } else {
+ disableContainer((c))
+ }
+ }
+ }
+ }
+ private var container: WindowContainerToken? = null
+
+ /**
+ * Set [container] as the new launch adjacent flag root container.
+ *
+ * If launch adjacent handling is disabled through [setLaunchAdjacentEnabled], won't set the
+ * container until after it is enabled again.
+ *
+ * @see WindowContainerTransaction.setLaunchAdjacentFlagRoot
+ */
+ fun setLaunchAdjacentRoot(container: WindowContainerToken) {
+ KtProtoLog.d(WM_SHELL_TASK_ORG, "set new launch adjacent flag root container")
+ this.container = container
+ if (launchAdjacentEnabled) {
+ enableContainer(container)
+ }
+ }
+
+ /**
+ * Clear a container previously set through [setLaunchAdjacentRoot].
+ *
+ * Always clears the container, regardless of [launchAdjacentEnabled] value.
+ *
+ * @see WindowContainerTransaction.clearLaunchAdjacentFlagRoot
+ */
+ fun clearLaunchAdjacentRoot() {
+ KtProtoLog.d(WM_SHELL_TASK_ORG, "clear launch adjacent flag root container")
+ container?.let {
+ disableContainer(it)
+ container = null
+ }
+ }
+
+ private fun enableContainer(container: WindowContainerToken) {
+ KtProtoLog.v(WM_SHELL_TASK_ORG, "enable launch adjacent flag root container")
+ val wct = WindowContainerTransaction()
+ wct.setLaunchAdjacentFlagRoot(container)
+ syncQueue.queue(wct)
+ }
+
+ private fun disableContainer(container: WindowContainerToken) {
+ KtProtoLog.v(WM_SHELL_TASK_ORG, "disable launch adjacent flag root container")
+ val wct = WindowContainerTransaction()
+ wct.clearLaunchAdjacentFlagRoot(container)
+ syncQueue.queue(wct)
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/common/OWNERS
new file mode 100644
index 000000000000..7af038999797
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/OWNERS
@@ -0,0 +1 @@
+madym@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java
index 21355a3efa2e..24608d651d06 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java
@@ -129,6 +129,11 @@ public class BubbleInfo implements Parcelable {
return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION) != 0;
}
+ /** Sets the flags for this bubble. */
+ public void setFlags(int flags) {
+ mFlags = flags;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DismissCircleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissCircleView.java
index e0c782d1675b..7c5bb211a4cc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DismissCircleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissCircleView.java
@@ -14,16 +14,17 @@
* limitations under the License.
*/
-package com.android.wm.shell.common;
+package com.android.wm.shell.common.bubbles;
import android.content.Context;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import com.android.wm.shell.R;
+import androidx.annotation.DimenRes;
+import androidx.annotation.DrawableRes;
+import androidx.core.content.ContextCompat;
/**
* Circular view with a semitransparent, circular background with an 'X' inside it.
@@ -31,33 +32,44 @@ import com.android.wm.shell.R;
* This is used by both Bubbles and PIP as the dismiss target.
*/
public class DismissCircleView extends FrameLayout {
+ @DrawableRes int mBackgroundResId;
+ @DimenRes int mIconSizeResId;
private final ImageView mIconView = new ImageView(getContext());
public DismissCircleView(Context context) {
super(context);
- final Resources res = getResources();
-
- setBackground(res.getDrawable(R.drawable.dismiss_circle_background));
-
- mIconView.setImageDrawable(res.getDrawable(R.drawable.pip_ic_close_white));
addView(mIconView);
-
- setViewSizes();
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- final Resources res = getResources();
- setBackground(res.getDrawable(R.drawable.dismiss_circle_background));
+ setBackground(ContextCompat.getDrawable(getContext(), mBackgroundResId));
+ setViewSizes();
+ }
+
+ /**
+ * Sets up view with the provided resource ids.
+ * Decouples resource dependency in order to be used externally (e.g. Launcher)
+ *
+ * @param backgroundResId drawable resource id of the circle background
+ * @param iconResId drawable resource id of the icon for the dismiss view
+ * @param iconSizeResId dimen resource id of the icon size
+ */
+ public void setup(@DrawableRes int backgroundResId, @DrawableRes int iconResId,
+ @DimenRes int iconSizeResId) {
+ mBackgroundResId = backgroundResId;
+ mIconSizeResId = iconSizeResId;
+
+ setBackground(ContextCompat.getDrawable(getContext(), backgroundResId));
+ mIconView.setImageDrawable(ContextCompat.getDrawable(getContext(), iconResId));
setViewSizes();
}
/** Retrieves the current dimensions for the icon and circle and applies them. */
private void setViewSizes() {
- final Resources res = getResources();
- final int iconSize = res.getDimensionPixelSize(R.dimen.dismiss_target_x_size);
+ final int iconSize = getResources().getDimensionPixelSize(mIconSizeResId);
mIconView.setLayoutParams(
new FrameLayout.LayoutParams(iconSize, iconSize, Gravity.CENTER));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissView.kt
index 67ecb915e098..d275a0be8e93 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissView.kt
@@ -14,41 +14,73 @@
* limitations under the License.
*/
-package com.android.wm.shell.bubbles
+package com.android.wm.shell.common.bubbles
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.util.IntProperty
+import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManager
import android.widget.FrameLayout
+import androidx.annotation.ColorRes
+import androidx.annotation.DimenRes
+import androidx.annotation.DrawableRes
+import androidx.core.content.ContextCompat
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW
-import com.android.wm.shell.R
import com.android.wm.shell.animation.PhysicsAnimator
-import com.android.wm.shell.common.DismissCircleView
-/*
+/**
* View that handles interactions between DismissCircleView and BubbleStackView.
+ *
+ * @note [setup] method should be called after initialisation
*/
class DismissView(context: Context) : FrameLayout(context) {
+ /**
+ * The configuration is used to provide module specific resource ids
+ *
+ * @see [setup] method
+ */
+ data class Config(
+ /** dimen resource id of the dismiss target circle view size */
+ @DimenRes val targetSizeResId: Int,
+ /** dimen resource id of the icon size in the dismiss target */
+ @DimenRes val iconSizeResId: Int,
+ /** dimen resource id of the bottom margin for the dismiss target */
+ @DimenRes var bottomMarginResId: Int,
+ /** dimen resource id of the height for dismiss area gradient */
+ @DimenRes val floatingGradientHeightResId: Int,
+ /** color resource id of the dismiss area gradient color */
+ @ColorRes val floatingGradientColorResId: Int,
+ /** drawable resource id of the dismiss target background */
+ @DrawableRes val backgroundResId: Int,
+ /** drawable resource id of the icon for the dismiss target */
+ @DrawableRes val iconResId: Int
+ )
+
+ companion object {
+ private const val SHOULD_SETUP =
+ "The view isn't ready. Should be called after `setup`"
+ private val TAG = DismissView::class.simpleName
+ }
var circle = DismissCircleView(context)
var isShowing = false
- var targetSizeResId: Int
+ var config: Config? = null
private val animator = PhysicsAnimator.getInstance(circle)
private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
private val DISMISS_SCRIM_FADE_MS = 200L
private var wm: WindowManager =
context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
- private var gradientDrawable = createGradient()
+ private var gradientDrawable: GradientDrawable? = null
private val GRADIENT_ALPHA: IntProperty<GradientDrawable> =
object : IntProperty<GradientDrawable>("alpha") {
@@ -61,23 +93,41 @@ class DismissView(context: Context) : FrameLayout(context) {
}
init {
- setLayoutParams(LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- resources.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height),
- Gravity.BOTTOM))
- updatePadding()
setClipToPadding(false)
setClipChildren(false)
setVisibility(View.INVISIBLE)
+ addView(circle)
+ }
+
+ /**
+ * Sets up view with the provided resource ids.
+ *
+ * Decouples resource dependency in order to be used externally (e.g. Launcher). Usually called
+ * with default params in module specific extension:
+ * @see [DismissView.setup] in DismissViewExt.kt
+ */
+ fun setup(config: Config) {
+ this.config = config
+
+ // Setup layout
+ layoutParams = LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ resources.getDimensionPixelSize(config.floatingGradientHeightResId),
+ Gravity.BOTTOM)
+ updatePadding()
+
+ // Setup gradient
+ gradientDrawable = createGradient(color = config.floatingGradientColorResId)
setBackgroundDrawable(gradientDrawable)
- targetSizeResId = R.dimen.dismiss_circle_size
- val targetSize: Int = resources.getDimensionPixelSize(targetSizeResId)
- addView(circle, LayoutParams(targetSize, targetSize,
- Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL))
- // start with circle offscreen so it's animated up
- circle.setTranslationY(resources.getDimensionPixelSize(
- R.dimen.floating_dismiss_gradient_height).toFloat())
+ // Setup DismissCircleView
+ circle.setup(config.backgroundResId, config.iconResId, config.iconSizeResId)
+ val targetSize: Int = resources.getDimensionPixelSize(config.targetSizeResId)
+ circle.layoutParams = LayoutParams(targetSize, targetSize,
+ Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
+ // Initial position with circle offscreen so it's animated up
+ circle.translationY = resources.getDimensionPixelSize(config.floatingGradientHeightResId)
+ .toFloat()
}
/**
@@ -85,6 +135,7 @@ class DismissView(context: Context) : FrameLayout(context) {
*/
fun show() {
if (isShowing) return
+ val gradientDrawable = checkExists(gradientDrawable) ?: return
isShowing = true
setVisibility(View.VISIBLE)
val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
@@ -104,6 +155,7 @@ class DismissView(context: Context) : FrameLayout(context) {
*/
fun hide() {
if (!isShowing) return
+ val gradientDrawable = checkExists(gradientDrawable) ?: return
isShowing = false
val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
gradientDrawable.alpha, 0)
@@ -124,18 +176,17 @@ class DismissView(context: Context) : FrameLayout(context) {
}
fun updateResources() {
+ val config = checkExists(config) ?: return
updatePadding()
- layoutParams.height = resources.getDimensionPixelSize(
- R.dimen.floating_dismiss_gradient_height)
-
- val targetSize = resources.getDimensionPixelSize(targetSizeResId)
+ layoutParams.height = resources.getDimensionPixelSize(config.floatingGradientHeightResId)
+ val targetSize = resources.getDimensionPixelSize(config.targetSizeResId)
circle.layoutParams.width = targetSize
circle.layoutParams.height = targetSize
circle.requestLayout()
}
- private fun createGradient(): GradientDrawable {
- val gradientColor = context.resources.getColor(android.R.color.system_neutral1_900)
+ private fun createGradient(@ColorRes color: Int): GradientDrawable {
+ val gradientColor = ContextCompat.getColor(context, color)
val alpha = 0.7f * 255
val gradientColorWithAlpha = Color.argb(alpha.toInt(),
Color.red(gradientColor),
@@ -150,10 +201,22 @@ class DismissView(context: Context) : FrameLayout(context) {
}
private fun updatePadding() {
+ val config = checkExists(config) ?: return
val insets: WindowInsets = wm.getCurrentWindowMetrics().getWindowInsets()
val navInset = insets.getInsetsIgnoringVisibility(
WindowInsets.Type.navigationBars())
setPadding(0, 0, 0, navInset.bottom +
- resources.getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin))
+ resources.getDimensionPixelSize(config.bottomMarginResId))
+ }
+
+ /**
+ * Checks if the value is set up and exists, if not logs an exception.
+ * Used for convenient logging in case `setup` wasn't called before
+ *
+ * @return value provided as argument
+ */
+ private fun <T>checkExists(value: T?): T? {
+ if (value == null) Log.e(TAG, SHOULD_SETUP)
+ return value
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt
index ea9d065d5f53..cc37bd3a4589 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.bubbles
+package com.android.wm.shell.common.bubbles
import android.graphics.PointF
import android.view.MotionEvent
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
index c76937de6669..ec2680085fb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
@@ -76,6 +76,9 @@ public class DividerHandleView extends View {
private int mCurrentHeight;
private AnimatorSet mAnimator;
private boolean mTouching;
+ private boolean mHovering;
+ private final int mHoveringWidth;
+ private final int mHoveringHeight;
public DividerHandleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -87,6 +90,8 @@ public class DividerHandleView extends View {
mCurrentHeight = mHeight;
mTouchingWidth = mWidth > mHeight ? mWidth / 2 : mWidth;
mTouchingHeight = mHeight > mWidth ? mHeight / 2 : mHeight;
+ mHoveringWidth = mWidth > mHeight ? ((int) (mWidth * 1.5f)) : mWidth;
+ mHoveringHeight = mHeight > mWidth ? ((int) (mHeight * 1.5f)) : mHeight;
}
/** Sets touching state for this handle view. */
@@ -94,24 +99,32 @@ public class DividerHandleView extends View {
if (touching == mTouching) {
return;
}
+ setInputState(touching, animate, mTouchingWidth, mTouchingHeight);
+ mTouching = touching;
+ }
+
+ /** Sets hovering state for this handle view. */
+ public void setHovering(boolean hovering, boolean animate) {
+ if (hovering == mHovering) {
+ return;
+ }
+ setInputState(hovering, animate, mHoveringWidth, mHoveringHeight);
+ mHovering = hovering;
+ }
+
+ private void setInputState(boolean stateOn, boolean animate, int stateWidth, int stateHeight) {
if (mAnimator != null) {
mAnimator.cancel();
mAnimator = null;
}
if (!animate) {
- if (touching) {
- mCurrentWidth = mTouchingWidth;
- mCurrentHeight = mTouchingHeight;
- } else {
- mCurrentWidth = mWidth;
- mCurrentHeight = mHeight;
- }
+ mCurrentWidth = stateOn ? stateWidth : mWidth;
+ mCurrentHeight = stateOn ? stateHeight : mHeight;
invalidate();
} else {
- animateToTarget(touching ? mTouchingWidth : mWidth,
- touching ? mTouchingHeight : mHeight, touching);
+ animateToTarget(stateOn ? stateWidth : mWidth,
+ stateOn ? stateHeight : mHeight, stateOn);
}
- mTouching = touching;
}
private void animateToTarget(int targetWidth, int targetHeight, boolean touching) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 69f0bad4fb45..2dbc4445d606 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -17,14 +17,19 @@
package com.android.wm.shell.common.split;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
+import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CURSOR_HOVER_STATES_ENABLED;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
+import android.provider.DeviceConfig;
import android.util.AttributeSet;
import android.util.Property;
import android.view.GestureDetector;
@@ -32,6 +37,7 @@ import android.view.InsetsController;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.SurfaceControlViewHost;
import android.view.VelocityTracker;
import android.view.View;
@@ -46,6 +52,7 @@ import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
@@ -222,7 +229,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
for (int i = insetsState.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = insetsState.sourceAt(i);
if (source.getType() == WindowInsets.Type.navigationBars()
- && source.insetsRoundedCornerFrame()) {
+ && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
mTempRect.inset(source.calculateVisibleInsets(mTempRect));
}
}
@@ -270,6 +277,12 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
}
@Override
+ public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
+ return PointerIcon.getSystemIcon(getContext(),
+ isLandscape() ? TYPE_HORIZONTAL_DOUBLE_ARROW : TYPE_VERTICAL_DOUBLE_ARROW);
+ }
+
+ @Override
public boolean onTouch(View v, MotionEvent event) {
if (mSplitLayout == null || !mInteractive) {
return false;
@@ -371,6 +384,43 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
mViewHost.relayout(lp);
}
+ @Override
+ public boolean onHoverEvent(MotionEvent event) {
+ if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, CURSOR_HOVER_STATES_ENABLED,
+ /* defaultValue = */ false)) {
+ return false;
+ }
+
+ if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
+ setHovering();
+ return true;
+ } else if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
+ releaseHovering();
+ return true;
+ }
+ return false;
+ }
+
+ @VisibleForTesting
+ void setHovering() {
+ mHandle.setHovering(true, true);
+ mHandle.animate()
+ .setInterpolator(Interpolators.TOUCH_RESPONSE)
+ .setDuration(TOUCH_ANIMATION_DURATION)
+ .translationZ(mTouchElevation)
+ .start();
+ }
+
+ @VisibleForTesting
+ void releaseHovering() {
+ mHandle.setHovering(false, true);
+ mHandle.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
+ .translationZ(0)
+ .start();
+ }
+
/**
* Set divider should interactive to user or not.
*
@@ -384,7 +434,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
"Set divider bar %s from %s", interactive ? "interactive" : "non-interactive",
from);
mInteractive = interactive;
- if (!mInteractive && mMoving) {
+ if (!mInteractive && hideHandle && mMoving) {
final int position = mSplitLayout.getDividePosition();
mSplitLayout.flingDividePosition(
mLastDraggingPosition,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index a9ccdf6a156f..2b1037711249 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -323,7 +323,11 @@ public class SplitDecorManager extends WindowlessWindowManager {
}
}
if (mShown) {
- fadeOutDecor(()-> animFinishedCallback.accept(true));
+ fadeOutDecor(()-> {
+ if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
+ animFinishedCallback.accept(true);
+ }
+ });
} else {
// Decor surface is hidden so release it directly.
releaseDecor(t);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index f70d3aec9ec8..d3fada37a685 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -593,9 +593,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
void flingDividePosition(int from, int to, int duration,
@Nullable Runnable flingFinishedCallback) {
if (from == to) {
- // No animation run, still callback to stop resizing.
- mSplitLayoutHandler.onLayoutSizeChanged(this);
-
if (flingFinishedCallback != null) {
flingFinishedCallback.run();
}
@@ -725,10 +722,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return bounds.width() > bounds.height();
}
- public boolean isDensityChanged(int densityDpi) {
- return mDensity != densityDpi;
- }
-
/**
* Return if this layout is landscape.
*/
@@ -773,15 +766,13 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
boolean boundsChanged = false;
if (!mBounds1.equals(mWinBounds1) || !task1.token.equals(mWinToken1)) {
- wct.setBounds(task1.token, mBounds1);
- wct.setSmallestScreenWidthDp(task1.token, getSmallestWidthDp(mBounds1));
+ setTaskBounds(wct, task1, mBounds1);
mWinBounds1.set(mBounds1);
mWinToken1 = task1.token;
boundsChanged = true;
}
if (!mBounds2.equals(mWinBounds2) || !task2.token.equals(mWinToken2)) {
- wct.setBounds(task2.token, mBounds2);
- wct.setSmallestScreenWidthDp(task2.token, getSmallestWidthDp(mBounds2));
+ setTaskBounds(wct, task2, mBounds2);
mWinBounds2.set(mBounds2);
mWinToken2 = task2.token;
boundsChanged = true;
@@ -789,6 +780,13 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return boundsChanged;
}
+ /** Set bounds to the {@link WindowContainerTransaction} for single task. */
+ public void setTaskBounds(WindowContainerTransaction wct,
+ ActivityManager.RunningTaskInfo task, Rect bounds) {
+ wct.setBounds(task.token, bounds);
+ wct.setSmallestScreenWidthDp(task.token, getSmallestWidthDp(bounds));
+ }
+
private int getSmallestWidthDp(Rect bounds) {
mTempRect.set(bounds);
mTempRect.inset(getDisplayStableInsets(mContext));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
index 0289da916937..d7ea1c0c620d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
@@ -89,4 +89,9 @@ public class SplitScreenUtils {
int userId1, int userId2) {
return (packageName1 != null && packageName1.equals(packageName2)) && (userId1 == userId2);
}
+
+ /** Generates a common log message for split screen failures */
+ public static String splitFailureMessage(String caller, String reason) {
+ return "(" + caller + ") Splitscreen aborted: " + reason;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
index 12d51f54a09c..9facbd542e6c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
@@ -25,11 +25,13 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.dagger.pip.TvPipModule;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -86,13 +88,14 @@ public class TvWMShellModule {
TransactionPool transactionPool,
IconProvider iconProvider,
Optional<RecentTasksController> recentTasks,
+ LaunchAdjacentController launchAdjacentController,
@ShellMainThread ShellExecutor mainExecutor,
Handler mainHandler,
SystemWindows systemWindows) {
return new TvSplitScreenController(context, shellInit, shellCommandHandler, shellController,
shellTaskOrganizer, syncQueue, rootTDAOrganizer, displayController,
displayImeController, displayInsetsController, dragAndDropController, transitions,
- transactionPool, iconProvider, recentTasks, mainExecutor, mainHandler,
- systemWindows);
+ transactionPool, iconProvider, recentTasks, launchAdjacentController, mainExecutor,
+ mainHandler, systemWindows);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index c491fed5d896..422e3b0216c8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -20,7 +20,6 @@ import static com.android.wm.shell.onehanded.OneHandedController.SUPPORT_ONE_HAN
import android.app.ActivityTaskManager;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.SystemProperties;
import android.view.IWindowManager;
@@ -45,7 +44,7 @@ import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.DockStateReader;
-import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
@@ -75,10 +74,6 @@ import com.android.wm.shell.keyguard.KeyguardTransitions;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipMediaController;
-import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipUiEventLogger;
-import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasks;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.recents.RecentsTransitionHandler;
@@ -102,13 +97,13 @@ import com.android.wm.shell.unfold.UnfoldAnimationController;
import com.android.wm.shell.unfold.UnfoldTransitionHandler;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
-import java.util.Optional;
-
import dagger.BindsOptionalOf;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
+import java.util.Optional;
+
/**
* Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only
* accessible from components within the WM subcomponent (can be explicitly exposed to the
@@ -275,6 +270,13 @@ public abstract class WMShellBaseModule {
return new WindowManagerShellWrapper(mainExecutor);
}
+ @WMSingleton
+ @Provides
+ static LaunchAdjacentController provideLaunchAdjacentController(
+ SyncTransactionQueue syncQueue) {
+ return new LaunchAdjacentController(syncQueue);
+ }
+
//
// Back animation
//
@@ -462,40 +464,6 @@ public abstract class WMShellBaseModule {
}
//
- // Pip (optional feature)
- //
-
- @WMSingleton
- @Provides
- static FloatingContentCoordinator provideFloatingContentCoordinator() {
- return new FloatingContentCoordinator();
- }
-
- // Needs handler for registering broadcast receivers
- @WMSingleton
- @Provides
- static PipMediaController providePipMediaController(Context context,
- @ShellMainThread Handler mainHandler) {
- return new PipMediaController(context, mainHandler);
- }
-
- @WMSingleton
- @Provides
- static PipSurfaceTransactionHelper providePipSurfaceTransactionHelper(Context context) {
- return new PipSurfaceTransactionHelper(context);
- }
-
- @WMSingleton
- @Provides
- static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
- PackageManager packageManager) {
- return new PipUiEventLogger(uiEventLogger, packageManager);
- }
-
- @BindsOptionalOf
- abstract PipTouchHandler optionalPipTouchHandler();
-
- //
// Recent tasks
//
@@ -830,7 +798,6 @@ public abstract class WMShellBaseModule {
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
- Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Optional<UnfoldAnimationController> unfoldAnimationController,
Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index cff317259f1e..881c8f5552b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.dagger;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.os.Handler;
@@ -36,25 +37,29 @@ import com.android.wm.shell.bubbles.BubbleData;
import com.android.wm.shell.bubbles.BubbleDataRepository;
import com.android.wm.shell.bubbles.BubbleLogger;
import com.android.wm.shell.bubbles.BubblePositioner;
+import com.android.wm.shell.bubbles.properties.ProdBubbleProperties;
+import com.android.wm.shell.bubbles.storage.BubblePersistentRepository;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TabletopModeController;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.dagger.pip.PipModule;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler;
import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler;
+import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.freeform.FreeformTaskListener;
@@ -62,27 +67,7 @@ import com.android.wm.shell.freeform.FreeformTaskTransitionHandler;
import com.android.wm.shell.freeform.FreeformTaskTransitionObserver;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.onehanded.OneHandedController;
-import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipAnimationController;
-import com.android.wm.shell.pip.PipAppOpsListener;
-import com.android.wm.shell.pip.PipBoundsAlgorithm;
-import com.android.wm.shell.pip.PipBoundsState;
-import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.PipMediaController;
-import com.android.wm.shell.pip.PipParamsChangedForwarder;
-import com.android.wm.shell.pip.PipSnapAlgorithm;
-import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipTaskOrganizer;
-import com.android.wm.shell.pip.PipTransition;
import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
-import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
-import com.android.wm.shell.pip.phone.PhonePipMenuController;
-import com.android.wm.shell.pip.phone.PipController;
-import com.android.wm.shell.pip.phone.PipMotionHelper;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
-import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.recents.RecentsTransitionHandler;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -122,7 +107,10 @@ import java.util.Optional;
* This module only defines Shell dependencies for handheld SystemUI implementation. Common
* dependencies should go into {@link WMShellBaseModule}.
*/
-@Module(includes = WMShellBaseModule.class)
+@Module(includes = {
+ WMShellBaseModule.class,
+ PipModule.class
+})
public abstract class WMShellModule {
//
@@ -180,11 +168,12 @@ public abstract class WMShellModule {
IWindowManager wmService) {
return new BubbleController(context, shellInit, shellCommandHandler, shellController, data,
null /* synchronizer */, floatingContentCoordinator,
- new BubbleDataRepository(context, launcherApps, mainExecutor),
+ new BubbleDataRepository(launcherApps, mainExecutor,
+ new BubblePersistentRepository(context)),
statusBarService, windowManager, windowManagerShellWrapper, userManager,
launcherApps, logger, taskStackListener, organizer, positioner, displayController,
oneHandedOptional, dragAndDropController, mainExecutor, mainHandler, bgExecutor,
- taskViewTransitions, syncQueue, wmService);
+ taskViewTransitions, syncQueue, wmService, ProdBubbleProperties.INSTANCE);
}
//
@@ -197,33 +186,35 @@ public abstract class WMShellModule {
Context context,
@ShellMainThread Handler mainHandler,
@ShellMainThread Choreographer mainChoreographer,
+ ShellInit shellInit,
ShellTaskOrganizer taskOrganizer,
DisplayController displayController,
+ ShellController shellController,
SyncTransactionQueue syncQueue,
Transitions transitions,
Optional<DesktopModeController> desktopModeController,
- Optional<DesktopTasksController> desktopTasksController,
- Optional<SplitScreenController> splitScreenController) {
+ Optional<DesktopTasksController> desktopTasksController) {
if (DesktopModeStatus.isAnyEnabled()) {
return new DesktopModeWindowDecorViewModel(
context,
mainHandler,
mainChoreographer,
+ shellInit,
taskOrganizer,
displayController,
+ shellController,
syncQueue,
transitions,
desktopModeController,
- desktopTasksController,
- splitScreenController);
+ desktopTasksController);
}
return new CaptionWindowDecorViewModel(
- context,
- mainHandler,
- mainChoreographer,
- taskOrganizer,
- displayController,
- syncQueue);
+ context,
+ mainHandler,
+ mainChoreographer,
+ taskOrganizer,
+ displayController,
+ syncQueue);
}
//
@@ -263,8 +254,13 @@ public abstract class WMShellModule {
static FreeformTaskTransitionHandler provideFreeformTaskTransitionHandler(
ShellInit shellInit,
Transitions transitions,
- WindowDecorViewModel windowDecorViewModel) {
- return new FreeformTaskTransitionHandler(shellInit, transitions, windowDecorViewModel);
+ Context context,
+ WindowDecorViewModel windowDecorViewModel,
+ DisplayController displayController,
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellAnimationThread ShellExecutor animExecutor) {
+ return new FreeformTaskTransitionHandler(shellInit, transitions, context,
+ windowDecorViewModel, displayController, mainExecutor, animExecutor);
}
@WMSingleton
@@ -327,200 +323,14 @@ public abstract class WMShellModule {
TransactionPool transactionPool,
IconProvider iconProvider,
Optional<RecentTasksController> recentTasks,
+ LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel,
@ShellMainThread ShellExecutor mainExecutor) {
return new SplitScreenController(context, shellInit, shellCommandHandler, shellController,
shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, displayController,
displayImeController, displayInsetsController, dragAndDropController, transitions,
- transactionPool, iconProvider, recentTasks, mainExecutor);
- }
-
- //
- // Pip
- //
-
- @WMSingleton
- @Provides
- static Optional<Pip> providePip(Context context,
- ShellInit shellInit,
- ShellCommandHandler shellCommandHandler,
- ShellController shellController,
- DisplayController displayController,
- PipAnimationController pipAnimationController,
- PipAppOpsListener pipAppOpsListener,
- PipBoundsAlgorithm pipBoundsAlgorithm,
- PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
- PipBoundsState pipBoundsState,
- PipSizeSpecHandler pipSizeSpecHandler,
- PipDisplayLayoutState pipDisplayLayoutState,
- PipMotionHelper pipMotionHelper,
- PipMediaController pipMediaController,
- PhonePipMenuController phonePipMenuController,
- PipTaskOrganizer pipTaskOrganizer,
- PipTransitionState pipTransitionState,
- PipTouchHandler pipTouchHandler,
- PipTransitionController pipTransitionController,
- WindowManagerShellWrapper windowManagerShellWrapper,
- TaskStackListenerImpl taskStackListener,
- PipParamsChangedForwarder pipParamsChangedForwarder,
- DisplayInsetsController displayInsetsController,
- TabletopModeController pipTabletopController,
- Optional<OneHandedController> oneHandedController,
- @ShellMainThread ShellExecutor mainExecutor) {
- return Optional.ofNullable(PipController.create(
- context, shellInit, shellCommandHandler, shellController,
- displayController, pipAnimationController, pipAppOpsListener, pipBoundsAlgorithm,
- pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler, pipDisplayLayoutState,
- pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer,
- pipTransitionState, pipTouchHandler, pipTransitionController,
- windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
- displayInsetsController, pipTabletopController, oneHandedController, mainExecutor));
- }
-
- @WMSingleton
- @Provides
- static PipBoundsState providePipBoundsState(Context context,
- PipSizeSpecHandler pipSizeSpecHandler, PipDisplayLayoutState pipDisplayLayoutState) {
- return new PipBoundsState(context, pipSizeSpecHandler, pipDisplayLayoutState);
- }
-
- @WMSingleton
- @Provides
- static PipSnapAlgorithm providePipSnapAlgorithm() {
- return new PipSnapAlgorithm();
- }
-
- @WMSingleton
- @Provides
- static PhonePipKeepClearAlgorithm providePhonePipKeepClearAlgorithm(Context context) {
- return new PhonePipKeepClearAlgorithm(context);
- }
-
- @WMSingleton
- @Provides
- static PipSizeSpecHandler providePipSizeSpecHelper(Context context,
- PipDisplayLayoutState pipDisplayLayoutState) {
- return new PipSizeSpecHandler(context, pipDisplayLayoutState);
- }
-
- @WMSingleton
- @Provides
- static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
- PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
- PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
- PipSizeSpecHandler pipSizeSpecHandler) {
- return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm,
- pipKeepClearAlgorithm, pipSizeSpecHandler);
- }
-
- // Handler is used by Icon.loadDrawableAsync
- @WMSingleton
- @Provides
- static PhonePipMenuController providesPipPhoneMenuController(Context context,
- PipBoundsState pipBoundsState, PipMediaController pipMediaController,
- SystemWindows systemWindows,
- Optional<SplitScreenController> splitScreenOptional,
- PipUiEventLogger pipUiEventLogger,
- @ShellMainThread ShellExecutor mainExecutor,
- @ShellMainThread Handler mainHandler) {
- return new PhonePipMenuController(context, pipBoundsState, pipMediaController,
- systemWindows, splitScreenOptional, pipUiEventLogger, mainExecutor, mainHandler);
- }
-
- @WMSingleton
- @Provides
- static PipTouchHandler providePipTouchHandler(Context context,
- ShellInit shellInit,
- PhonePipMenuController menuPhoneController,
- PipBoundsAlgorithm pipBoundsAlgorithm,
- PipBoundsState pipBoundsState,
- PipSizeSpecHandler pipSizeSpecHandler,
- PipTaskOrganizer pipTaskOrganizer,
- PipMotionHelper pipMotionHelper,
- FloatingContentCoordinator floatingContentCoordinator,
- PipUiEventLogger pipUiEventLogger,
- @ShellMainThread ShellExecutor mainExecutor) {
- return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
- pipBoundsState, pipSizeSpecHandler, pipTaskOrganizer, pipMotionHelper,
- floatingContentCoordinator, pipUiEventLogger, mainExecutor);
- }
-
- @WMSingleton
- @Provides
- static PipTransitionState providePipTransitionState() {
- return new PipTransitionState();
- }
-
- @WMSingleton
- @Provides
- static PipTaskOrganizer providePipTaskOrganizer(Context context,
- SyncTransactionQueue syncTransactionQueue,
- PipTransitionState pipTransitionState,
- PipBoundsState pipBoundsState,
- PipDisplayLayoutState pipDisplayLayoutState,
- PipBoundsAlgorithm pipBoundsAlgorithm,
- PhonePipMenuController menuPhoneController,
- PipAnimationController pipAnimationController,
- PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
- PipTransitionController pipTransitionController,
- PipParamsChangedForwarder pipParamsChangedForwarder,
- Optional<SplitScreenController> splitScreenControllerOptional,
- DisplayController displayController,
- PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
- @ShellMainThread ShellExecutor mainExecutor) {
- return new PipTaskOrganizer(context,
- syncTransactionQueue, pipTransitionState, pipBoundsState, pipDisplayLayoutState,
- pipBoundsAlgorithm, menuPhoneController, pipAnimationController,
- pipSurfaceTransactionHelper, pipTransitionController, pipParamsChangedForwarder,
- splitScreenControllerOptional, displayController, pipUiEventLogger,
- shellTaskOrganizer, mainExecutor);
- }
-
- @WMSingleton
- @Provides
- static PipAnimationController providePipAnimationController(PipSurfaceTransactionHelper
- pipSurfaceTransactionHelper) {
- return new PipAnimationController(pipSurfaceTransactionHelper);
- }
-
- @WMSingleton
- @Provides
- static PipTransitionController providePipTransitionController(Context context,
- ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, Transitions transitions,
- PipAnimationController pipAnimationController, PipBoundsAlgorithm pipBoundsAlgorithm,
- PipBoundsState pipBoundsState, PipDisplayLayoutState pipDisplayLayoutState,
- PipTransitionState pipTransitionState, PhonePipMenuController pipMenuController,
- PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
- Optional<SplitScreenController> splitScreenOptional) {
- return new PipTransition(context, shellInit, shellTaskOrganizer, transitions,
- pipBoundsState, pipDisplayLayoutState, pipTransitionState, pipMenuController,
- pipBoundsAlgorithm, pipAnimationController, pipSurfaceTransactionHelper,
- splitScreenOptional);
- }
-
- @WMSingleton
- @Provides
- static PipAppOpsListener providePipAppOpsListener(Context context,
- PipTouchHandler pipTouchHandler,
- @ShellMainThread ShellExecutor mainExecutor) {
- return new PipAppOpsListener(context, pipTouchHandler.getMotionHelper(), mainExecutor);
- }
-
- @WMSingleton
- @Provides
- static PipMotionHelper providePipMotionHelper(Context context,
- PipBoundsState pipBoundsState, PipTaskOrganizer pipTaskOrganizer,
- PhonePipMenuController menuController, PipSnapAlgorithm pipSnapAlgorithm,
- PipTransitionController pipTransitionController,
- FloatingContentCoordinator floatingContentCoordinator) {
- return new PipMotionHelper(context, pipBoundsState, pipTaskOrganizer,
- menuController, pipSnapAlgorithm, pipTransitionController,
- floatingContentCoordinator);
- }
-
- @WMSingleton
- @Provides
- static PipParamsChangedForwarder providePipParamsChangedForwarder() {
- return new PipParamsChangedForwarder();
+ transactionPool, iconProvider, recentTasks, launchAdjacentController,
+ windowDecorViewModel, mainExecutor);
}
//
@@ -532,13 +342,16 @@ public abstract class WMShellModule {
static DefaultMixedHandler provideDefaultMixedHandler(
ShellInit shellInit,
Optional<SplitScreenController> splitScreenOptional,
- Optional<PipTouchHandler> pipTouchHandlerOptional,
+ @Nullable PipTransitionController pipTransitionController,
Optional<RecentsTransitionHandler> recentsTransitionHandler,
KeyguardTransitionHandler keyguardTransitionHandler,
+ Optional<DesktopModeController> desktopModeController,
+ Optional<DesktopTasksController> desktopTasksController,
Optional<UnfoldTransitionHandler> unfoldHandler,
Transitions transitions) {
return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
- pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler,
+ pipTransitionController, recentsTransitionHandler,
+ keyguardTransitionHandler, desktopModeController, desktopTasksController,
unfoldHandler);
}
@@ -573,13 +386,13 @@ public abstract class WMShellModule {
animators.add(fullscreenAnimator);
return new UnfoldAnimationController(
- shellInit,
- transactionPool,
- progressProvider.get(),
- animators,
- unfoldTransitionHandler,
- mainExecutor
- );
+ shellInit,
+ transactionPool,
+ progressProvider.get(),
+ animators,
+ unfoldTransitionHandler,
+ mainExecutor
+ );
}
@Provides
@@ -671,6 +484,7 @@ public abstract class WMShellModule {
static DesktopTasksController provideDesktopTasksController(
Context context,
ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
ShellController shellController,
DisplayController displayController,
ShellTaskOrganizer shellTaskOrganizer,
@@ -679,13 +493,16 @@ public abstract class WMShellModule {
Transitions transitions,
EnterDesktopTaskTransitionHandler enterDesktopTransitionHandler,
ExitDesktopTaskTransitionHandler exitDesktopTransitionHandler,
+ ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
@DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
+ LaunchAdjacentController launchAdjacentController,
@ShellMainThread ShellExecutor mainExecutor
) {
- return new DesktopTasksController(context, shellInit, shellController, displayController,
- shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, transitions,
- enterDesktopTransitionHandler, exitDesktopTransitionHandler,
- desktopModeTaskRepository, mainExecutor);
+ return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController,
+ displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,
+ transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler,
+ toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository,
+ launchAdjacentController, mainExecutor);
}
@WMSingleton
@@ -697,6 +514,13 @@ public abstract class WMShellModule {
@WMSingleton
@Provides
+ static ToggleResizeDesktopTaskTransitionHandler provideToggleResizeDesktopTaskTransitionHandler(
+ Transitions transitions) {
+ return new ToggleResizeDesktopTaskTransitionHandler(transitions);
+ }
+
+ @WMSingleton
+ @Provides
static ExitDesktopTaskTransitionHandler provideExitDesktopTaskTransitionHandler(
Transitions transitions,
Context context
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
new file mode 100644
index 000000000000..16c39601e0bf
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2023 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.dagger.pip;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TabletopModeController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.dagger.WMShellBaseModule;
+import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.onehanded.OneHandedController;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipAnimationController;
+import com.android.wm.shell.pip.PipAppOpsListener;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipDisplayLayoutState;
+import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.pip.PipParamsChangedForwarder;
+import com.android.wm.shell.pip.PipSnapAlgorithm;
+import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipTransition;
+import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.PipTransitionState;
+import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.PipUtils;
+import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
+import com.android.wm.shell.pip.phone.PhonePipMenuController;
+import com.android.wm.shell.pip.phone.PipController;
+import com.android.wm.shell.pip.phone.PipMotionHelper;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
+import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.sysui.ShellCommandHandler;
+import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.Transitions;
+
+import dagger.Module;
+import dagger.Provides;
+
+import java.util.Optional;
+
+/**
+ * Provides dependencies from {@link com.android.wm.shell.pip}, this implementation is meant to be
+ * replaced by the sibling {@link Pip2Module}.
+ */
+@Module(includes = {
+ Pip1SharedModule.class,
+ WMShellBaseModule.class
+})
+public abstract class Pip1Module {
+ @WMSingleton
+ @Provides
+ static Optional<Pip> providePip1(Context context,
+ ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
+ ShellController shellController,
+ DisplayController displayController,
+ PipAnimationController pipAnimationController,
+ PipAppOpsListener pipAppOpsListener,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
+ PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
+ PipBoundsState pipBoundsState,
+ PipSizeSpecHandler pipSizeSpecHandler,
+ PipDisplayLayoutState pipDisplayLayoutState,
+ PipMotionHelper pipMotionHelper,
+ PipMediaController pipMediaController,
+ PhonePipMenuController phonePipMenuController,
+ PipTaskOrganizer pipTaskOrganizer,
+ PipTransitionState pipTransitionState,
+ PipTouchHandler pipTouchHandler,
+ PipTransitionController pipTransitionController,
+ WindowManagerShellWrapper windowManagerShellWrapper,
+ TaskStackListenerImpl taskStackListener,
+ PipParamsChangedForwarder pipParamsChangedForwarder,
+ DisplayInsetsController displayInsetsController,
+ TabletopModeController pipTabletopController,
+ Optional<OneHandedController> oneHandedController,
+ @ShellMainThread ShellExecutor mainExecutor) {
+ if (PipUtils.isPip2ExperimentEnabled()) {
+ return Optional.empty();
+ } else {
+ return Optional.ofNullable(PipController.create(
+ context, shellInit, shellCommandHandler, shellController,
+ displayController, pipAnimationController, pipAppOpsListener,
+ pipBoundsAlgorithm,
+ pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler,
+ pipDisplayLayoutState,
+ pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer,
+ pipTransitionState, pipTouchHandler, pipTransitionController,
+ windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
+ displayInsetsController, pipTabletopController, oneHandedController,
+ mainExecutor));
+ }
+ }
+
+ @WMSingleton
+ @Provides
+ static PipBoundsState providePipBoundsState(Context context,
+ PipSizeSpecHandler pipSizeSpecHandler, PipDisplayLayoutState pipDisplayLayoutState) {
+ return new PipBoundsState(context, pipSizeSpecHandler, pipDisplayLayoutState);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipSnapAlgorithm providePipSnapAlgorithm() {
+ return new PipSnapAlgorithm();
+ }
+
+ @WMSingleton
+ @Provides
+ static PhonePipKeepClearAlgorithm providePhonePipKeepClearAlgorithm(Context context) {
+ return new PhonePipKeepClearAlgorithm(context);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipSizeSpecHandler providePipSizeSpecHelper(Context context,
+ PipDisplayLayoutState pipDisplayLayoutState) {
+ return new PipSizeSpecHandler(context, pipDisplayLayoutState);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
+ PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
+ PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
+ PipSizeSpecHandler pipSizeSpecHandler) {
+ return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm,
+ pipKeepClearAlgorithm, pipSizeSpecHandler);
+ }
+
+ // Handler is used by Icon.loadDrawableAsync
+ @WMSingleton
+ @Provides
+ static PhonePipMenuController providesPipPhoneMenuController(Context context,
+ PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+ SystemWindows systemWindows,
+ Optional<SplitScreenController> splitScreenOptional,
+ PipUiEventLogger pipUiEventLogger,
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler) {
+ return new PhonePipMenuController(context, pipBoundsState, pipMediaController,
+ systemWindows, splitScreenOptional, pipUiEventLogger, mainExecutor, mainHandler);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipTouchHandler providePipTouchHandler(Context context,
+ ShellInit shellInit,
+ PhonePipMenuController menuPhoneController,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipBoundsState pipBoundsState,
+ PipSizeSpecHandler pipSizeSpecHandler,
+ PipTaskOrganizer pipTaskOrganizer,
+ PipMotionHelper pipMotionHelper,
+ FloatingContentCoordinator floatingContentCoordinator,
+ PipUiEventLogger pipUiEventLogger,
+ @ShellMainThread ShellExecutor mainExecutor) {
+ return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
+ pipBoundsState, pipSizeSpecHandler, pipTaskOrganizer, pipMotionHelper,
+ floatingContentCoordinator, pipUiEventLogger, mainExecutor);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipTransitionState providePipTransitionState() {
+ return new PipTransitionState();
+ }
+
+ @WMSingleton
+ @Provides
+ static PipTaskOrganizer providePipTaskOrganizer(Context context,
+ SyncTransactionQueue syncTransactionQueue,
+ PipTransitionState pipTransitionState,
+ PipBoundsState pipBoundsState,
+ PipDisplayLayoutState pipDisplayLayoutState,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
+ PhonePipMenuController menuPhoneController,
+ PipAnimationController pipAnimationController,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTransitionController pipTransitionController,
+ PipParamsChangedForwarder pipParamsChangedForwarder,
+ Optional<SplitScreenController> splitScreenControllerOptional,
+ DisplayController displayController,
+ PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
+ @ShellMainThread ShellExecutor mainExecutor) {
+ return new PipTaskOrganizer(context,
+ syncTransactionQueue, pipTransitionState, pipBoundsState, pipDisplayLayoutState,
+ pipBoundsAlgorithm, menuPhoneController, pipAnimationController,
+ pipSurfaceTransactionHelper, pipTransitionController, pipParamsChangedForwarder,
+ splitScreenControllerOptional, displayController, pipUiEventLogger,
+ shellTaskOrganizer, mainExecutor);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipAnimationController providePipAnimationController(PipSurfaceTransactionHelper
+ pipSurfaceTransactionHelper) {
+ return new PipAnimationController(pipSurfaceTransactionHelper);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipTransition providePipTransition(Context context,
+ ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, Transitions transitions,
+ PipAnimationController pipAnimationController, PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipBoundsState pipBoundsState, PipDisplayLayoutState pipDisplayLayoutState,
+ PipTransitionState pipTransitionState, PhonePipMenuController pipMenuController,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ Optional<SplitScreenController> splitScreenOptional) {
+ return new PipTransition(context, shellInit, shellTaskOrganizer, transitions,
+ pipBoundsState, pipDisplayLayoutState, pipTransitionState, pipMenuController,
+ pipBoundsAlgorithm, pipAnimationController, pipSurfaceTransactionHelper,
+ splitScreenOptional);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipAppOpsListener providePipAppOpsListener(Context context,
+ PipTouchHandler pipTouchHandler,
+ @ShellMainThread ShellExecutor mainExecutor) {
+ return new PipAppOpsListener(context, pipTouchHandler.getMotionHelper(), mainExecutor);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipMotionHelper providePipMotionHelper(Context context,
+ PipBoundsState pipBoundsState, PipTaskOrganizer pipTaskOrganizer,
+ PhonePipMenuController menuController, PipSnapAlgorithm pipSnapAlgorithm,
+ PipTransitionController pipTransitionController,
+ FloatingContentCoordinator floatingContentCoordinator) {
+ return new PipMotionHelper(context, pipBoundsState, pipTaskOrganizer,
+ menuController, pipSnapAlgorithm, pipTransitionController,
+ floatingContentCoordinator);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipParamsChangedForwarder providePipParamsChangedForwarder() {
+ return new PipParamsChangedForwarder();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
new file mode 100644
index 000000000000..f29b3a35128d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 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.dagger.pip;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip.PipUiEventLogger;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Provides shared dependencies from {@link com.android.wm.shell.pip}, this implementation is
+ * shared with {@link TvPipModule} and possibly other form factors.
+ */
+@Module
+public abstract class Pip1SharedModule {
+ @WMSingleton
+ @Provides
+ static FloatingContentCoordinator provideFloatingContentCoordinator() {
+ return new FloatingContentCoordinator();
+ }
+
+ // Needs handler for registering broadcast receivers
+ @WMSingleton
+ @Provides
+ static PipMediaController providePipMediaController(Context context,
+ @ShellMainThread Handler mainHandler) {
+ return new PipMediaController(context, mainHandler);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipSurfaceTransactionHelper providePipSurfaceTransactionHelper(Context context) {
+ return new PipSurfaceTransactionHelper(context);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
+ PackageManager packageManager) {
+ return new PipUiEventLogger(uiEventLogger, packageManager);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
new file mode 100644
index 000000000000..c7c6e8a14278
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 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.dagger.pip;
+
+import android.annotation.Nullable;
+
+import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.pip2.PipTransition;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Provides dependencies from {@link com.android.wm.shell.pip2}, this implementation is meant to be
+ * the successor of its sibling {@link Pip1SharedModule}.
+ */
+@Module
+public abstract class Pip2Module {
+ @WMSingleton
+ @Provides
+ @Nullable
+ static PipTransition providePipTransition() {
+ return null;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
new file mode 100644
index 000000000000..04032bb17fec
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 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.dagger.pip;
+
+import android.annotation.Nullable;
+
+import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.PipUtils;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Provides dependencies for external components / modules reference PiP and extracts away the
+ * selection of legacy and new PiP implementation.
+ */
+@Module(includes = {
+ Pip1Module.class,
+ Pip2Module.class
+})
+public abstract class PipModule {
+ @WMSingleton
+ @Provides
+ static PipTransitionController providePipTransitionController(
+ com.android.wm.shell.pip.PipTransition legacyPipTransition,
+ @Nullable com.android.wm.shell.pip2.PipTransition newPipTransition) {
+ if (PipUtils.isPip2ExperimentEnabled() && newPipTransition != null) {
+ return newPipTransition;
+ } else {
+ return legacyPipTransition;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
index 14daae03e6b5..360bf8b70fca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.dagger;
+package com.android.wm.shell.dagger.pip;
import android.content.Context;
import android.os.Handler;
@@ -28,6 +28,8 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.dagger.WMShellBaseModule;
+import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipAppOpsListener;
@@ -62,7 +64,9 @@ import java.util.Optional;
/**
* Provides TV specific dependencies for Pip.
*/
-@Module(includes = {WMShellBaseModule.class})
+@Module(includes = {
+ WMShellBaseModule.class,
+ Pip1SharedModule.class})
public abstract class TvPipModule {
@WMSingleton
@Provides
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index b9d2be280efb..db6c258e84c2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -33,6 +33,7 @@ import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DE
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
import android.content.Context;
+import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Region;
import android.net.Uri;
@@ -414,6 +415,25 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
}
/**
+ * Applies the proper surface states (rounded corners) to tasks when desktop mode is active.
+ * This is intended to be used when desktop mode is part of another animation but isn't, itself,
+ * animating.
+ */
+ public void syncSurfaceState(@NonNull TransitionInfo info,
+ SurfaceControl.Transaction finishTransaction) {
+ // Add rounded corners to freeform windows
+ final TypedArray ta = mContext.obtainStyledAttributes(
+ new int[]{android.R.attr.dialogCornerRadius});
+ final int cornerRadius = ta.getDimensionPixelSize(0, 0);
+ ta.recycle();
+ for (TransitionInfo.Change change: info.getChanges()) {
+ if (change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ finishTransaction.setCornerRadius(change.getLeash(), cornerRadius);
+ }
+ }
+ }
+
+ /**
* A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
*/
private final class SettingsObserver extends ContentObserver {
@@ -500,6 +520,11 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
}
@Override
+ public void showDesktopApp(int taskId) throws RemoteException {
+ // TODO
+ }
+
+ @Override
public int getVisibleTaskCount(int displayId) throws RemoteException {
int[] result = new int[1];
executeRemoteCallWithTaskPermission(mController, "getVisibleTaskCount",
@@ -508,5 +533,20 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
);
return result[0];
}
+
+ @Override
+ public void stashDesktopApps(int displayId) throws RemoteException {
+ // Stashing of desktop apps not needed. Apps always launch on desktop
+ }
+
+ @Override
+ public void hideStashedDesktopApps(int displayId) throws RemoteException {
+ // Stashing of desktop apps not needed. Apps always launch on desktop
+ }
+
+ @Override
+ public void setTaskListener(IDesktopTaskListener listener) throws RemoteException {
+ // TODO(b/261234402): move visibility from sysui state to listener
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
index 76ca68bbfa75..517f9f2aba27 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
@@ -54,6 +54,15 @@ public class DesktopModeStatus {
public static final boolean IS_DISPLAY_CHANGE_ENABLED = SystemProperties.getBoolean(
"persist.wm.debug.desktop_change_display", false);
+
+ /**
+ * Flag to indicate that desktop stashing is enabled.
+ * When enabled, swiping home from desktop stashes the open apps. Next app that launches,
+ * will be added to the desktop.
+ */
+ private static final boolean IS_STASHING_ENABLED = SystemProperties.getBoolean(
+ "persist.wm.debug.desktop_stashing", false);
+
/**
* Return {@code true} if desktop mode support is enabled
*/
@@ -84,6 +93,13 @@ public class DesktopModeStatus {
}
/**
+ * Return {@code true} if desktop task stashing is enabled when going home.
+ * Allows users to use home screen to add tasks to desktop.
+ */
+ public static boolean isStashingEnabled() {
+ return IS_STASHING_ENABLED;
+ }
+ /**
* Check if desktop mode is active
*
* @return {@code true} if active
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index 3ab175d3b68a..c05af73e6765 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -25,6 +25,7 @@ import androidx.core.util.keyIterator
import androidx.core.util.valueIterator
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.util.KtProtoLog
+import java.io.PrintWriter
import java.util.concurrent.Executor
import java.util.function.Consumer
@@ -43,6 +44,7 @@ class DesktopModeTaskRepository {
*/
val activeTasks: ArraySet<Int> = ArraySet(),
val visibleTasks: ArraySet<Int> = ArraySet(),
+ var stashed: Boolean = false
)
// Tasks currently in freeform mode, ordered from top to bottom (top is at index 0).
@@ -85,8 +87,10 @@ class DesktopModeTaskRepository {
visibleTasksListeners[visibleTasksListener] = executor
displayData.keyIterator().forEach { displayId ->
val visibleTasks = getVisibleTaskCount(displayId)
+ val stashed = isStashed(displayId)
executor.execute {
visibleTasksListener.onVisibilityChanged(displayId, visibleTasks > 0)
+ visibleTasksListener.onStashedChanged(displayId, stashed)
}
}
}
@@ -312,13 +316,58 @@ class DesktopModeTaskRepository {
}
/**
+ * Update stashed status on display with id [displayId]
+ */
+ fun setStashed(displayId: Int, stashed: Boolean) {
+ val data = displayData.getOrCreate(displayId)
+ val oldValue = data.stashed
+ data.stashed = stashed
+ if (oldValue != stashed) {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: mark stashed=%b displayId=%d",
+ stashed,
+ displayId
+ )
+ visibleTasksListeners.forEach { (listener, executor) ->
+ executor.execute { listener.onStashedChanged(displayId, stashed) }
+ }
+ }
+ }
+
+ /**
+ * Check if display with id [displayId] has desktop tasks stashed
+ */
+ fun isStashed(displayId: Int): Boolean {
+ return displayData[displayId]?.stashed ?: false
+ }
+
+ internal fun dump(pw: PrintWriter, prefix: String) {
+ val innerPrefix = "$prefix "
+ pw.println("${prefix}DesktopModeTaskRepository")
+ dumpDisplayData(pw, innerPrefix)
+ pw.println("${innerPrefix}freeformTasksInZOrder=${freeformTasksInZOrder.toDumpString()}")
+ pw.println("${innerPrefix}activeTasksListeners=${activeTasksListeners.size}")
+ pw.println("${innerPrefix}visibleTasksListeners=${visibleTasksListeners.size}")
+ }
+
+ private fun dumpDisplayData(pw: PrintWriter, prefix: String) {
+ val innerPrefix = "$prefix "
+ displayData.forEach { displayId, data ->
+ pw.println("${prefix}Display $displayId:")
+ pw.println("${innerPrefix}activeTasks=${data.activeTasks.toDumpString()}")
+ pw.println("${innerPrefix}visibleTasks=${data.visibleTasks.toDumpString()}")
+ pw.println("${innerPrefix}stashed=${data.stashed}")
+ }
+ }
+
+ /**
* Defines interface for classes that can listen to changes for active tasks in desktop mode.
*/
interface ActiveTasksListener {
/**
* Called when the active tasks change in desktop mode.
*/
- @JvmDefault
fun onActiveTasksChanged(displayId: Int) {}
}
@@ -329,7 +378,15 @@ class DesktopModeTaskRepository {
/**
* Called when the desktop starts or stops showing freeform tasks.
*/
- @JvmDefault
fun onVisibilityChanged(displayId: Int, hasVisibleFreeformTasks: Boolean) {}
+
+ /**
+ * Called when the desktop stashed status changes.
+ */
+ fun onStashedChanged(displayId: Int, stashed: Boolean) {}
}
}
+
+private fun <T> Iterable<T>.toDumpString(): String {
+ return joinToString(separator = ", ", prefix = "[", postfix = "]")
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 91bb155d9d01..b15fd912e32d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.desktopmode
+import android.R
import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
@@ -24,19 +25,21 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.app.WindowConfiguration.WindowingMode
import android.content.Context
+import android.content.res.TypedArray
import android.graphics.Point
import android.graphics.Rect
import android.graphics.Region
import android.os.IBinder
import android.os.SystemProperties
+import android.util.DisplayMetrics.DENSITY_DEFAULT
import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
import android.window.TransitionRequestInfo
-import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import androidx.annotation.BinderThread
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
@@ -44,18 +47,24 @@ import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.ExecutorUtils
import com.android.wm.shell.common.ExternalInterfaceBinder
+import com.android.wm.shell.common.LaunchAdjacentController
import com.android.wm.shell.common.RemoteCallable
import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.common.SingleInstanceRemoteListener
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.common.annotations.ExternalThread
import com.android.wm.shell.common.annotations.ShellMainThread
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.sysui.ShellSharedConstants
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.util.KtProtoLog
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
+import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
+import java.io.PrintWriter
import java.util.concurrent.Executor
import java.util.function.Consumer
@@ -63,6 +72,7 @@ import java.util.function.Consumer
class DesktopTasksController(
private val context: Context,
shellInit: ShellInit,
+ private val shellCommandHandler: ShellCommandHandler,
private val shellController: ShellController,
private val displayController: DisplayController,
private val shellTaskOrganizer: ShellTaskOrganizer,
@@ -71,7 +81,10 @@ class DesktopTasksController(
private val transitions: Transitions,
private val enterDesktopTaskTransitionHandler: EnterDesktopTaskTransitionHandler,
private val exitDesktopTaskTransitionHandler: ExitDesktopTaskTransitionHandler,
+ private val toggleResizeDesktopTaskTransitionHandler:
+ ToggleResizeDesktopTaskTransitionHandler,
private val desktopModeTaskRepository: DesktopModeTaskRepository,
+ private val launchAdjacentController: LaunchAdjacentController,
@ShellMainThread private val mainExecutor: ShellExecutor
) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler {
@@ -82,6 +95,15 @@ class DesktopTasksController(
visualIndicator?.releaseVisualIndicator(t)
visualIndicator = null
}
+ private val taskVisibilityListener = object : VisibleTasksListener {
+ override fun onVisibilityChanged(displayId: Int, hasVisibleFreeformTasks: Boolean) {
+ launchAdjacentController.launchAdjacentEnabled = !hasVisibleFreeformTasks
+ }
+ }
+
+ private val transitionAreaHeight
+ get() = context.resources.getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.desktop_mode_transition_area_height)
init {
desktopMode = DesktopModeImpl()
@@ -92,12 +114,14 @@ class DesktopTasksController(
private fun onInit() {
KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopTasksController")
+ shellCommandHandler.addDumpCallback(this::dump, this)
shellController.addExternalInterface(
ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE,
{ createExternalInterface() },
this
)
transitions.addHandler(this)
+ desktopModeTaskRepository.addVisibleTasksListener(taskVisibilityListener, mainExecutor)
}
/** Show all tasks, that are part of the desktop, on top of launcher */
@@ -118,72 +142,120 @@ class DesktopTasksController(
}
}
+ /**
+ * Stash desktop tasks on display with id [displayId].
+ *
+ * When desktop tasks are stashed, launcher home screen icons are fully visible. New apps
+ * launched in this state will be added to the desktop. Existing desktop tasks will be brought
+ * back to front during the launch.
+ */
+ fun stashDesktopApps(displayId: Int) {
+ if (DesktopModeStatus.isStashingEnabled()) {
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: stashDesktopApps")
+ desktopModeTaskRepository.setStashed(displayId, true)
+ }
+ }
+
+ /**
+ * Clear the stashed state for the given display
+ */
+ fun hideStashedDesktopApps(displayId: Int) {
+ if (DesktopModeStatus.isStashingEnabled()) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: hideStashedApps displayId=%d",
+ displayId
+ )
+ desktopModeTaskRepository.setStashed(displayId, false)
+ }
+ }
+
/** Get number of tasks that are marked as visible */
fun getVisibleTaskCount(displayId: Int): Int {
return desktopModeTaskRepository.getVisibleTaskCount(displayId)
}
/** Move a task with given `taskId` to desktop */
- fun moveToDesktop(taskId: Int) {
- shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToDesktop(task) }
+ fun moveToDesktop(
+ decor: DesktopModeWindowDecoration,
+ taskId: Int,
+ wct: WindowContainerTransaction = WindowContainerTransaction()
+ ) {
+ shellTaskOrganizer.getRunningTaskInfo(taskId)?.let {
+ task -> moveToDesktop(decor, task, wct)
+ }
}
- /** Move a task to desktop */
- fun moveToDesktop(task: RunningTaskInfo) {
+ /**
+ * Move a task to desktop
+ */
+ fun moveToDesktop(
+ decor: DesktopModeWindowDecoration,
+ task: RunningTaskInfo,
+ wct: WindowContainerTransaction = WindowContainerTransaction()
+ ) {
KtProtoLog.v(
WM_SHELL_DESKTOP_MODE,
"DesktopTasksController: moveToDesktop taskId=%d",
task.taskId
)
- val wct = WindowContainerTransaction()
// Bring other apps to front first
bringDesktopAppsToFront(task.displayId, wct)
- addMoveToDesktopChanges(wct, task.token)
+ addMoveToDesktopChanges(wct, task)
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
+ enterDesktopTaskTransitionHandler.moveToDesktop(wct, decor)
} else {
shellTaskOrganizer.applyTransaction(wct)
}
}
/**
- * Moves a single task to freeform and sets the taskBounds to the passed in bounds,
- * startBounds
+ * The first part of the animated move to desktop transition. Applies the changes to move task
+ * to desktop mode and sets the taskBounds to the passed in bounds, startBounds. This is
+ * followed with a call to {@link finishMoveToDesktop} or {@link cancelMoveToDesktop}.
*/
- fun moveToFreeform(taskInfo: RunningTaskInfo, startBounds: Rect) {
+ fun startMoveToDesktop(
+ taskInfo: RunningTaskInfo,
+ startBounds: Rect,
+ dragToDesktopValueAnimator: MoveToDesktopAnimator
+ ) {
KtProtoLog.v(
WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: moveToFreeform with bounds taskId=%d",
+ "DesktopTasksController: startMoveToDesktop taskId=%d",
taskInfo.taskId
)
val wct = WindowContainerTransaction()
moveHomeTaskToFront(wct)
- addMoveToDesktopChanges(wct, taskInfo.getToken())
+ addMoveToDesktopChanges(wct, taskInfo)
wct.setBounds(taskInfo.token, startBounds)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_ENTER_FREEFORM, wct, mOnAnimationFinishedCallback)
+ enterDesktopTaskTransitionHandler.startMoveToDesktop(wct, dragToDesktopValueAnimator,
+ mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
}
}
- /** Brings apps to front and sets freeform task bounds */
- private fun moveToDesktopWithAnimation(taskInfo: RunningTaskInfo, freeformBounds: Rect) {
+ /**
+ * The second part of the animated move to desktop transition, called after
+ * {@link startMoveToDesktop}. Brings apps to front and sets freeform task bounds.
+ */
+ private fun finalizeMoveToDesktop(taskInfo: RunningTaskInfo, freeformBounds: Rect) {
KtProtoLog.v(
WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: moveToDesktop with animation taskId=%d",
+ "DesktopTasksController: finalizeMoveToDesktop taskId=%d",
taskInfo.taskId
)
val wct = WindowContainerTransaction()
bringDesktopAppsToFront(taskInfo.displayId, wct)
- addMoveToDesktopChanges(wct, taskInfo.getToken())
+ addMoveToDesktopChanges(wct, taskInfo)
wct.setBounds(taskInfo.token, freeformBounds)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct, mOnAnimationFinishedCallback)
+ enterDesktopTaskTransitionHandler.finalizeMoveToDesktop(wct,
+ mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
releaseVisualIndicator()
@@ -204,7 +276,7 @@ class DesktopTasksController(
)
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task.token)
+ addMoveToFullscreenChanges(wct, task)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
} else {
@@ -213,21 +285,30 @@ class DesktopTasksController(
}
/**
- * Move a task to fullscreen after being dragged from fullscreen and released back into
- * status bar area
+ * The second part of the animated move to desktop transition, called after
+ * {@link startMoveToDesktop}. Move a task to fullscreen after being dragged from fullscreen
+ * and released back into status bar area.
*/
- fun cancelMoveToFreeform(task: RunningTaskInfo, position: Point) {
+ fun cancelMoveToDesktop(task: RunningTaskInfo, moveToDesktopAnimator: MoveToDesktopAnimator) {
KtProtoLog.v(
- WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: cancelMoveToFreeform taskId=%d",
- task.taskId
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: cancelMoveToDesktop taskId=%d",
+ task.taskId
)
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task.token)
+ wct.setBounds(task.token, null)
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, position,
- mOnAnimationFinishedCallback)
+ enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct,
+ moveToDesktopAnimator) { t ->
+ val callbackWCT = WindowContainerTransaction()
+ visualIndicator?.releaseVisualIndicator(t)
+ visualIndicator = null
+ addMoveToFullscreenChanges(callbackWCT, task)
+ transitions.startTransition(TRANSIT_CHANGE, callbackWCT, null /* handler */)
+ }
} else {
+ addMoveToFullscreenChanges(wct, task)
shellTaskOrganizer.applyTransaction(wct)
releaseVisualIndicator()
}
@@ -240,7 +321,7 @@ class DesktopTasksController(
task.taskId
)
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task.token)
+ addMoveToFullscreenChanges(wct, task)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
exitDesktopTaskTransitionHandler.startTransition(
@@ -252,6 +333,11 @@ class DesktopTasksController(
}
/** Move a task to the front */
+ fun moveTaskToFront(taskId: Int) {
+ shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveTaskToFront(task) }
+ }
+
+ /** Move a task to the front */
fun moveTaskToFront(taskInfo: RunningTaskInfo) {
KtProtoLog.v(
WM_SHELL_DESKTOP_MODE,
@@ -331,6 +417,49 @@ class DesktopTasksController(
}
}
+ /** Quick-resizes a desktop task, toggling between the stable bounds and the default bounds. */
+ fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo, windowDecor: DesktopModeWindowDecoration) {
+ val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
+
+ val stableBounds = Rect()
+ displayLayout.getStableBounds(stableBounds)
+ val destinationBounds = Rect()
+ if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) {
+ // The desktop task is currently occupying the whole stable bounds, toggle to the
+ // default bounds.
+ getDefaultDesktopTaskBounds(
+ density = taskInfo.configuration.densityDpi.toFloat() / DENSITY_DEFAULT,
+ stableBounds = stableBounds,
+ outBounds = destinationBounds
+ )
+ } else {
+ // Toggle to the stable bounds.
+ destinationBounds.set(stableBounds)
+ }
+
+ val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ toggleResizeDesktopTaskTransitionHandler.startTransition(
+ wct,
+ taskInfo.taskId,
+ windowDecor
+ )
+ } else {
+ shellTaskOrganizer.applyTransaction(wct)
+ }
+ }
+
+ private fun getDefaultDesktopTaskBounds(density: Float, stableBounds: Rect, outBounds: Rect) {
+ val width = (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f).toInt()
+ val height = (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f).toInt()
+ outBounds.set(0, 0, width, height)
+ // Center the task in stable bounds
+ outBounds.offset(
+ stableBounds.centerX() - outBounds.centerX(),
+ stableBounds.centerY() - outBounds.centerY()
+ )
+ }
+
/**
* Get windowing move for a given `taskId`
*
@@ -397,83 +526,169 @@ class DesktopTasksController(
transition: IBinder,
request: TransitionRequestInfo
): WindowContainerTransaction? {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: handleRequest request=%s",
+ request
+ )
// Check if we should skip handling this transition
+ var reason = ""
val shouldHandleRequest =
when {
// Only handle open or to front transitions
- request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> false
+ request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> {
+ reason = "transition type not handled (${request.type})"
+ false
+ }
// Only handle when it is a task transition
- request.triggerTask == null -> false
+ request.triggerTask == null -> {
+ reason = "triggerTask is null"
+ false
+ }
// Only handle standard type tasks
- request.triggerTask.activityType != ACTIVITY_TYPE_STANDARD -> false
+ request.triggerTask.activityType != ACTIVITY_TYPE_STANDARD -> {
+ reason = "activityType not handled (${request.triggerTask.activityType})"
+ false
+ }
// Only handle fullscreen or freeform tasks
request.triggerTask.windowingMode != WINDOWING_MODE_FULLSCREEN &&
- request.triggerTask.windowingMode != WINDOWING_MODE_FREEFORM -> false
+ request.triggerTask.windowingMode != WINDOWING_MODE_FREEFORM -> {
+ reason = "windowingMode not handled (${request.triggerTask.windowingMode})"
+ false
+ }
// Otherwise process it
else -> true
}
if (!shouldHandleRequest) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: skipping handleRequest reason=%s",
+ reason
+ )
return null
}
val task: RunningTaskInfo = request.triggerTask
- val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)
- // Check if we should switch a fullscreen task to freeform
- if (task.windowingMode == WINDOWING_MODE_FULLSCREEN) {
- // If there are any visible desktop tasks, switch the task to freeform
- if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) {
- KtProtoLog.d(
+ val result = when {
+ // If display has tasks stashed, handle as stashed launch
+ desktopModeTaskRepository.isStashed(task.displayId) -> handleStashedTaskLaunch(task)
+ // Check if fullscreen task should be updated
+ task.windowingMode == WINDOWING_MODE_FULLSCREEN -> handleFullscreenTaskLaunch(task)
+ // Check if freeform task should be updated
+ task.windowingMode == WINDOWING_MODE_FREEFORM -> handleFreeformTaskLaunch(task)
+ else -> {
+ null
+ }
+ }
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: handleRequest result=%s",
+ result ?: "null"
+ )
+ return result
+ }
+
+ /**
+ * Applies the proper surface states (rounded corners) to tasks when desktop mode is active.
+ * This is intended to be used when desktop mode is part of another animation but isn't, itself,
+ * animating.
+ */
+ fun syncSurfaceState(
+ info: TransitionInfo,
+ finishTransaction: SurfaceControl.Transaction
+ ) {
+ // Add rounded corners to freeform windows
+ val ta: TypedArray = context.obtainStyledAttributes(
+ intArrayOf(R.attr.dialogCornerRadius))
+ val cornerRadius = ta.getDimensionPixelSize(0, 0).toFloat()
+ ta.recycle()
+ info.changes
+ .filter { it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM }
+ .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) }
+ }
+
+ private fun handleFreeformTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? {
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFreeformTaskLaunch")
+ val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)
+ if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) {
+ KtProtoLog.d(
WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: switch fullscreen task to freeform on transition" +
- " taskId=%d",
+ "DesktopTasksController: switch freeform task to fullscreen oon transition" +
+ " taskId=%d",
task.taskId
- )
- return WindowContainerTransaction().also { wct ->
- addMoveToDesktopChanges(wct, task.token)
- }
+ )
+ return WindowContainerTransaction().also { wct ->
+ addMoveToFullscreenChanges(wct, task)
}
}
+ return null
+ }
- // CHeck if we should switch a freeform task to fullscreen
- if (task.windowingMode == WINDOWING_MODE_FREEFORM) {
- // If no visible desktop tasks, switch this task to freeform as the transition came
- // outside of this controller
- if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) {
- KtProtoLog.d(
+ private fun handleFullscreenTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? {
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFullscreenTaskLaunch")
+ val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)
+ if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) {
+ KtProtoLog.d(
WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: switch freeform task to fullscreen oon transition" +
- " taskId=%d",
+ "DesktopTasksController: switch fullscreen task to freeform on transition" +
+ " taskId=%d",
task.taskId
- )
- return WindowContainerTransaction().also { wct ->
- addMoveToFullscreenChanges(wct, task.token)
- }
+ )
+ return WindowContainerTransaction().also { wct ->
+ addMoveToDesktopChanges(wct, task)
}
}
return null
}
+ private fun handleStashedTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: launch apps with stashed on transition taskId=%d",
+ task.taskId
+ )
+ val wct = WindowContainerTransaction()
+ bringDesktopAppsToFront(task.displayId, wct)
+ addMoveToDesktopChanges(wct, task)
+ desktopModeTaskRepository.setStashed(task.displayId, false)
+ return wct
+ }
+
private fun addMoveToDesktopChanges(
wct: WindowContainerTransaction,
- token: WindowContainerToken
+ taskInfo: RunningTaskInfo
) {
- wct.setWindowingMode(token, WINDOWING_MODE_FREEFORM)
- wct.reorder(token, true /* onTop */)
+ val displayWindowingMode = taskInfo.configuration.windowConfiguration.displayWindowingMode
+ val targetWindowingMode = if (displayWindowingMode == WINDOWING_MODE_FREEFORM) {
+ // Display windowing is freeform, set to undefined and inherit it
+ WINDOWING_MODE_UNDEFINED
+ } else {
+ WINDOWING_MODE_FREEFORM
+ }
+ wct.setWindowingMode(taskInfo.token, targetWindowingMode)
+ wct.reorder(taskInfo.token, true /* onTop */)
if (isDesktopDensityOverrideSet()) {
- wct.setDensityDpi(token, getDesktopDensityDpi())
+ wct.setDensityDpi(taskInfo.token, getDesktopDensityDpi())
}
}
private fun addMoveToFullscreenChanges(
wct: WindowContainerTransaction,
- token: WindowContainerToken
+ taskInfo: RunningTaskInfo
) {
- wct.setWindowingMode(token, WINDOWING_MODE_FULLSCREEN)
- wct.setBounds(token, null)
+ val displayWindowingMode = taskInfo.configuration.windowConfiguration.displayWindowingMode
+ val targetWindowingMode = if (displayWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // Display windowing is fullscreen, set to undefined and inherit it
+ WINDOWING_MODE_UNDEFINED
+ } else {
+ WINDOWING_MODE_FULLSCREEN
+ }
+ wct.setWindowingMode(taskInfo.token, targetWindowingMode)
+ wct.setBounds(taskInfo.token, null)
if (isDesktopDensityOverrideSet()) {
- wct.setDensityDpi(token, getFullscreenDensityDpi())
+ wct.setDensityDpi(taskInfo.token, getFullscreenDensityDpi())
}
}
@@ -508,13 +723,12 @@ class DesktopTasksController(
y: Float
) {
if (taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
- val statusBarHeight = getStatusBarHeight(taskInfo)
- if (y <= statusBarHeight && visualIndicator == null) {
+ if (y <= transitionAreaHeight && visualIndicator == null) {
visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo,
displayController, context, taskSurface, shellTaskOrganizer,
rootTaskDisplayAreaOrganizer)
visualIndicator?.createFullscreenIndicatorWithAnimatedBounds()
- } else if (y > statusBarHeight && visualIndicator != null) {
+ } else if (y > transitionAreaHeight && visualIndicator != null) {
releaseVisualIndicator()
}
}
@@ -524,14 +738,18 @@ class DesktopTasksController(
* Perform checks required on drag end. Move to fullscreen if drag ends in status bar area.
*
* @param taskInfo the task being dragged.
- * @param position position of surface when drag ends
+ * @param position position of surface when drag ends.
+ * @param y the Y position of the top edge of the task
+ * @param windowDecor the window decoration for the task being dragged
*/
fun onDragPositioningEnd(
taskInfo: RunningTaskInfo,
- position: Point
+ position: Point,
+ y: Float,
+ windowDecor: DesktopModeWindowDecoration
) {
- val statusBarHeight = getStatusBarHeight(taskInfo)
- if (position.y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+ if (y <= transitionAreaHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+ windowDecor.incrementRelayoutBlock()
moveToFullscreenWithAnimation(taskInfo, position)
}
}
@@ -549,9 +767,9 @@ class DesktopTasksController(
taskSurface: SurfaceControl,
y: Float
) {
- // If the motion event is above the status bar, return since we do not need to show the
- // visual indicator at this point.
- if (y < getStatusBarHeight(taskInfo)) {
+ // If the motion event is above the status bar and the visual indicator is not yet visible,
+ // return since we do not need to show the visual indicator at this point.
+ if (y < getStatusBarHeight(taskInfo) && visualIndicator == null) {
return
}
if (visualIndicator == null) {
@@ -580,7 +798,7 @@ class DesktopTasksController(
taskInfo: RunningTaskInfo,
freeformBounds: Rect
) {
- moveToDesktopWithAnimation(taskInfo, freeformBounds)
+ finalizeMoveToDesktop(taskInfo, freeformBounds)
}
private fun getStatusBarHeight(taskInfo: RunningTaskInfo): Int {
@@ -632,6 +850,12 @@ class DesktopTasksController(
desktopModeTaskRepository.setTaskCornerListener(listener, callbackExecutor)
}
+ private fun dump(pw: PrintWriter, prefix: String) {
+ val innerPrefix = "$prefix "
+ pw.println("${prefix}DesktopTasksController")
+ desktopModeTaskRepository.dump(pw, innerPrefix)
+ }
+
/** The interface for calls from outside the shell, within the host process. */
@ExternalThread
private inner class DesktopModeImpl : DesktopMode {
@@ -658,8 +882,51 @@ class DesktopTasksController(
@BinderThread
private class IDesktopModeImpl(private var controller: DesktopTasksController?) :
IDesktopMode.Stub(), ExternalInterfaceBinder {
+
+ private lateinit var remoteListener:
+ SingleInstanceRemoteListener<DesktopTasksController, IDesktopTaskListener>
+
+ private val listener: VisibleTasksListener = object : VisibleTasksListener {
+ override fun onVisibilityChanged(displayId: Int, visible: Boolean) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "IDesktopModeImpl: onVisibilityChanged display=%d visible=%b",
+ displayId,
+ visible
+ )
+ remoteListener.call { l -> l.onVisibilityChanged(displayId, visible) }
+ }
+
+ override fun onStashedChanged(displayId: Int, stashed: Boolean) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "IDesktopModeImpl: onStashedChanged display=%d stashed=%b",
+ displayId,
+ stashed
+ )
+ remoteListener.call { l -> l.onStashedChanged(displayId, stashed) }
+ }
+ }
+
+ init {
+ remoteListener =
+ SingleInstanceRemoteListener<DesktopTasksController, IDesktopTaskListener>(
+ controller,
+ { c ->
+ c.desktopModeTaskRepository.addVisibleTasksListener(
+ listener,
+ c.mainExecutor
+ )
+ },
+ { c ->
+ c.desktopModeTaskRepository.removeVisibleTasksListener(listener)
+ }
+ )
+ }
+
/** Invalidates this instance, preventing future calls from updating the controller. */
override fun invalidate() {
+ remoteListener.unregister()
controller = null
}
@@ -670,6 +937,27 @@ class DesktopTasksController(
) { c -> c.showDesktopApps(displayId) }
}
+ override fun stashDesktopApps(displayId: Int) {
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "stashDesktopApps"
+ ) { c -> c.stashDesktopApps(displayId) }
+ }
+
+ override fun hideStashedDesktopApps(displayId: Int) {
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "hideStashedDesktopApps"
+ ) { c -> c.hideStashedDesktopApps(displayId) }
+ }
+
+ override fun showDesktopApp(taskId: Int) {
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "showDesktopApp"
+ ) { c -> c.moveTaskToFront(taskId) }
+ }
+
override fun getVisibleTaskCount(displayId: Int): Int {
val result = IntArray(1)
ExecutorUtils.executeRemoteCallWithTaskPermission(
@@ -680,13 +968,33 @@ class DesktopTasksController(
)
return result[0]
}
+
+ override fun setTaskListener(listener: IDesktopTaskListener?) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "IDesktopModeImpl: set task listener=%s",
+ listener ?: "null"
+ )
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "setTaskListener"
+ ) { _ -> listener?.let { remoteListener.register(it) } ?: remoteListener.unregister() }
+ }
}
companion object {
private val DESKTOP_DENSITY_OVERRIDE =
- SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 0)
+ SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 284)
private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000)
+ // Override default freeform task width when desktop mode is enabled. In dips.
+ private val DESKTOP_MODE_DEFAULT_WIDTH_DP =
+ SystemProperties.getInt("persist.wm.debug.desktop_mode.default_width", 840)
+
+ // Override default freeform task height when desktop mode is enabled. In dips.
+ private val DESKTOP_MODE_DEFAULT_HEIGHT_DP =
+ SystemProperties.getInt("persist.wm.debug.desktop_mode.default_height", 630)
+
/**
* Check if desktop density override is enabled
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 3733b919e366..024465b281b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -17,15 +17,16 @@
package com.android.wm.shell.desktopmode;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
-import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.os.IBinder;
+import android.util.Slog;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -36,6 +37,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration;
+import com.android.wm.shell.windowdecor.MoveToDesktopAnimator;
import java.util.ArrayList;
import java.util.List;
@@ -48,18 +51,18 @@ import java.util.function.Supplier;
*/
public class EnterDesktopTaskTransitionHandler implements Transitions.TransitionHandler {
+ private static final String TAG = "EnterDesktopTaskTransitionHandler";
private final Transitions mTransitions;
private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
- // The size of the screen during drag relative to the fullscreen size
- public static final float DRAG_FREEFORM_SCALE = 0.4f;
// The size of the screen after drag relative to the fullscreen size
public static final float FINAL_FREEFORM_SCALE = 0.6f;
public static final int FREEFORM_ANIMATION_DURATION = 336;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
- private Point mPosition;
private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
+ private MoveToDesktopAnimator mMoveToDesktopAnimator;
+ private DesktopModeWindowDecoration mDesktopModeWindowDecoration;
public EnterDesktopTaskTransitionHandler(
Transitions transitions) {
@@ -79,7 +82,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
* @param wct WindowContainerTransaction for transition
* @param onAnimationEndCallback to be called after animation
*/
- public void startTransition(@WindowManager.TransitionType int type,
+ private void startTransition(@WindowManager.TransitionType int type,
@NonNull WindowContainerTransaction wct,
Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
mOnAnimationFinishedCallback = onAnimationEndCallback;
@@ -88,19 +91,58 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
}
/**
+ * Starts Transition of type TRANSIT_START_DRAG_TO_DESKTOP_MODE
+ * @param wct WindowContainerTransaction for transition
+ * @param moveToDesktopAnimator Animator that shrinks and positions task during two part move
+ * to desktop animation
+ * @param onAnimationEndCallback to be called after animation
+ */
+ public void startMoveToDesktop(@NonNull WindowContainerTransaction wct,
+ @NonNull MoveToDesktopAnimator moveToDesktopAnimator,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mMoveToDesktopAnimator = moveToDesktopAnimator;
+ startTransition(Transitions.TRANSIT_START_DRAG_TO_DESKTOP_MODE, wct,
+ onAnimationEndCallback);
+ }
+
+ /**
+ * Starts Transition of type TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE
+ * @param wct WindowContainerTransaction for transition
+ * @param onAnimationEndCallback to be called after animation
+ */
+ public void finalizeMoveToDesktop(@NonNull WindowContainerTransaction wct,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ startTransition(Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE, wct,
+ onAnimationEndCallback);
+ }
+
+ /**
* Starts Transition of type TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
* @param wct WindowContainerTransaction for transition
- * @param position Position of task when transition is triggered
+ * @param moveToDesktopAnimator Animator that shrinks and positions task during two part move
+ * to desktop animation
* @param onAnimationEndCallback to be called after animation
*/
public void startCancelMoveToDesktopMode(@NonNull WindowContainerTransaction wct,
- Point position,
+ MoveToDesktopAnimator moveToDesktopAnimator,
Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
- mPosition = position;
- startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct,
+ mMoveToDesktopAnimator = moveToDesktopAnimator;
+ startTransition(Transitions.TRANSIT_CANCEL_DRAG_TO_DESKTOP_MODE, wct,
onAnimationEndCallback);
}
+ /**
+ * Starts Transition of type TRANSIT_MOVE_TO_DESKTOP
+ * @param wct WindowContainerTransaction for transition
+ * @param decor {@link DesktopModeWindowDecoration} of task being animated
+ */
+ public void moveToDesktop(@NonNull WindowContainerTransaction wct,
+ DesktopModeWindowDecoration decor) {
+ mDesktopModeWindowDecoration = decor;
+ startTransition(Transitions.TRANSIT_MOVE_TO_DESKTOP, wct,
+ null /* onAnimationEndCallback */);
+ }
+
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startT,
@@ -140,103 +182,206 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
}
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (type == Transitions.TRANSIT_ENTER_FREEFORM
+ if (type == Transitions.TRANSIT_MOVE_TO_DESKTOP
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
- // Transitioning to freeform but keeping fullscreen bounds, so the crop is set
- // to null and we don't require an animation
- final SurfaceControl sc = change.getLeash();
- startT.setWindowCrop(sc, null);
- startT.apply();
- mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
- return true;
+ return animateMoveToDesktop(change, startT, finishCallback);
}
- Rect endBounds = change.getEndAbsBounds();
- if (type == Transitions.TRANSIT_ENTER_DESKTOP_MODE
+ if (type == Transitions.TRANSIT_START_DRAG_TO_DESKTOP_MODE
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ return animateStartDragToDesktopMode(change, startT, finishT, finishCallback);
+ }
+
+ final Rect endBounds = change.getEndAbsBounds();
+ if (type == Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
&& !endBounds.isEmpty()) {
- // This Transition animates a task to freeform bounds after being dragged into freeform
- // mode and brings the remaining freeform tasks to front
- final SurfaceControl sc = change.getLeash();
- startT.setWindowCrop(sc, endBounds.width(),
- endBounds.height());
- startT.apply();
-
- // We want to find the scale of the current bounds relative to the end bounds. The
- // task is currently scaled to DRAG_FREEFORM_SCALE and the final bounds will be
- // scaled to FINAL_FREEFORM_SCALE. So, it is scaled to
- // DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE relative to the freeform bounds
- final ValueAnimator animator =
- ValueAnimator.ofFloat(DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE, 1f);
- animator.setDuration(FREEFORM_ANIMATION_DURATION);
- final SurfaceControl.Transaction t = mTransactionSupplier.get();
- animator.addUpdateListener(animation -> {
- final float animationValue = (float) animation.getAnimatedValue();
- t.setScale(sc, animationValue, animationValue);
-
- final float animationWidth = endBounds.width() * animationValue;
- final float animationHeight = endBounds.height() * animationValue;
- final int animationX = endBounds.centerX() - (int) (animationWidth / 2);
- final int animationY = endBounds.centerY() - (int) (animationHeight / 2);
-
- t.setPosition(sc, animationX, animationY);
- t.apply();
- });
-
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mOnAnimationFinishedCallback != null) {
- mOnAnimationFinishedCallback.accept(finishT);
- }
- mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
- }
- });
+ return animateFinalizeDragToDesktopMode(change, startT, finishT, finishCallback,
+ endBounds);
+ }
- animator.start();
- return true;
+ if (type == Transitions.TRANSIT_CANCEL_DRAG_TO_DESKTOP_MODE
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ return animateCancelDragToDesktopMode(change, startT, finishT, finishCallback,
+ endBounds);
}
- if (type == Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
- && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- && mPosition != null) {
- // This Transition animates a task to fullscreen after being dragged from the status
- // bar and then released back into the status bar area
- final SurfaceControl sc = change.getLeash();
- // Hide the first (fullscreen) frame because the animation will start from the smaller
- // scale size.
- startT.hide(sc)
- .setWindowCrop(sc, endBounds.width(), endBounds.height())
- .apply();
+ return false;
+ }
- final ValueAnimator animator = new ValueAnimator();
- animator.setFloatValues(DRAG_FREEFORM_SCALE, 1f);
- animator.setDuration(FREEFORM_ANIMATION_DURATION);
- final SurfaceControl.Transaction t = mTransactionSupplier.get();
- animator.addUpdateListener(animation -> {
- final float scale = (float) animation.getAnimatedValue();
- t.setPosition(sc, mPosition.x * (1 - scale), mPosition.y * (1 - scale))
- .setScale(sc, scale, scale)
- .show(sc)
- .apply();
- });
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mOnAnimationFinishedCallback != null) {
- mOnAnimationFinishedCallback.accept(finishT);
- }
- mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ private boolean animateMoveToDesktop(
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ if (mDesktopModeWindowDecoration == null) {
+ Slog.e(TAG, "Window Decoration is not available for this transition");
+ return false;
+ }
+
+ final SurfaceControl leash = change.getLeash();
+ final Rect startBounds = change.getStartAbsBounds();
+ startT.setPosition(leash, startBounds.left, startBounds.right)
+ .setWindowCrop(leash, startBounds.width(), startBounds.height())
+ .show(leash);
+ mDesktopModeWindowDecoration.showResizeVeil(startT, startBounds);
+
+ final ValueAnimator animator = ValueAnimator.ofObject(new RectEvaluator(),
+ change.getStartAbsBounds(), change.getEndAbsBounds());
+ animator.setDuration(FREEFORM_ANIMATION_DURATION);
+ SurfaceControl.Transaction t = mTransactionSupplier.get();
+ animator.addUpdateListener(animation -> {
+ final Rect animationValue = (Rect) animator.getAnimatedValue();
+ t.setPosition(leash, animationValue.left, animationValue.right)
+ .setWindowCrop(leash, animationValue.width(), animationValue.height())
+ .show(leash);
+ mDesktopModeWindowDecoration.updateResizeVeil(t, animationValue);
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDesktopModeWindowDecoration.hideResizeVeil();
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null));
+ }
+ });
+ animator.start();
+ return true;
+ }
+
+ private boolean animateStartDragToDesktopMode(
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ // Transitioning to freeform but keeping fullscreen bounds, so the crop is set
+ // to null and we don't require an animation
+ final SurfaceControl sc = change.getLeash();
+ startT.setWindowCrop(sc, null);
+
+ if (mMoveToDesktopAnimator == null
+ || mMoveToDesktopAnimator.getTaskId() != change.getTaskInfo().taskId) {
+ Slog.e(TAG, "No animator available for this transition");
+ return false;
+ }
+
+ // Calculate and set position of the task
+ final PointF position = mMoveToDesktopAnimator.getPosition();
+ startT.setPosition(sc, position.x, position.y);
+ finishT.setPosition(sc, position.x, position.y);
+
+ startT.apply();
+
+ mTransitions.getMainExecutor().execute(() -> finishCallback.onTransitionFinished(null));
+
+ return true;
+ }
+
+ private boolean animateFinalizeDragToDesktopMode(
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback,
+ @NonNull Rect endBounds) {
+ // This Transition animates a task to freeform bounds after being dragged into freeform
+ // mode and brings the remaining freeform tasks to front
+ final SurfaceControl sc = change.getLeash();
+ startT.setWindowCrop(sc, endBounds.width(),
+ endBounds.height());
+ startT.apply();
+
+ // End the animation that shrinks the window when task is first dragged from fullscreen
+ if (mMoveToDesktopAnimator != null) {
+ mMoveToDesktopAnimator.endAnimator();
+ }
+
+ // We want to find the scale of the current bounds relative to the end bounds. The
+ // task is currently scaled to DRAG_FREEFORM_SCALE and the final bounds will be
+ // scaled to FINAL_FREEFORM_SCALE. So, it is scaled to
+ // DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE relative to the freeform bounds
+ final ValueAnimator animator =
+ ValueAnimator.ofFloat(
+ MoveToDesktopAnimator.DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE, 1f);
+ animator.setDuration(FREEFORM_ANIMATION_DURATION);
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+ animator.addUpdateListener(animation -> {
+ final float animationValue = (float) animation.getAnimatedValue();
+ t.setScale(sc, animationValue, animationValue);
+
+ final float animationWidth = endBounds.width() * animationValue;
+ final float animationHeight = endBounds.height() * animationValue;
+ final int animationX = endBounds.centerX() - (int) (animationWidth / 2);
+ final int animationY = endBounds.centerY() - (int) (animationHeight / 2);
+
+ t.setPosition(sc, animationX, animationY);
+ t.apply();
+ });
+
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
}
- });
- animator.start();
- return true;
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null));
+ }
+ });
+
+ animator.start();
+ return true;
+ }
+ private boolean animateCancelDragToDesktopMode(
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback,
+ @NonNull Rect endBounds) {
+ // This Transition animates a task to fullscreen after being dragged from the status
+ // bar and then released back into the status bar area
+ final SurfaceControl sc = change.getLeash();
+ // Hide the first (fullscreen) frame because the animation will start from the smaller
+ // scale size.
+ startT.hide(sc)
+ .setWindowCrop(sc, endBounds.width(), endBounds.height())
+ .apply();
+
+ if (mMoveToDesktopAnimator == null
+ || mMoveToDesktopAnimator.getTaskId() != change.getTaskInfo().taskId) {
+ Slog.e(TAG, "No animator available for this transition");
+ return false;
}
- return false;
+ // End the animation that shrinks the window when task is first dragged from fullscreen
+ mMoveToDesktopAnimator.endAnimator();
+
+ final ValueAnimator animator = new ValueAnimator();
+ animator.setFloatValues(MoveToDesktopAnimator.DRAG_FREEFORM_SCALE, 1f);
+ animator.setDuration(FREEFORM_ANIMATION_DURATION);
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+
+ // Get position of the task
+ final float x = mMoveToDesktopAnimator.getPosition().x;
+ final float y = mMoveToDesktopAnimator.getPosition().y;
+
+ animator.addUpdateListener(animation -> {
+ final float scale = (float) animation.getAnimatedValue();
+ t.setPosition(sc, x * (1 - scale), y * (1 - scale))
+ .setScale(sc, scale, scale)
+ .show(sc)
+ .apply();
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null));
+ }
+ });
+ animator.start();
+ return true;
}
@Nullable
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index 3ad5edf0e604..7342bd1ae5de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -168,7 +168,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
mOnAnimationFinishedCallback.accept(finishT);
}
mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ () -> finishCallback.onTransitionFinished(null));
}
});
animator.start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index 899d67267e69..ee3a080e7318 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -16,6 +16,8 @@
package com.android.wm.shell.desktopmode;
+import com.android.wm.shell.desktopmode.IDesktopTaskListener;
+
/**
* Interface that is exposed to remote callers to manipulate desktop mode features.
*/
@@ -24,6 +26,18 @@ interface IDesktopMode {
/** Show apps on the desktop on the given display */
void showDesktopApps(int displayId);
+ /** Stash apps on the desktop to allow launching another app from home screen */
+ void stashDesktopApps(int displayId);
+
+ /** Hide apps that may be stashed */
+ void hideStashedDesktopApps(int displayId);
+
+ /** Bring task with the given id to front */
+ oneway void showDesktopApp(int taskId);
+
/** Get count of visible desktop tasks on the given display */
int getVisibleTaskCount(int displayId);
+
+ /** Set listener that will receive callbacks about updates to desktop tasks */
+ oneway void setTaskListener(IDesktopTaskListener listener);
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl
index 62fa7b4516c7..39128a863ec9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl
@@ -14,14 +14,17 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.bubble
+package com.android.wm.shell.desktopmode;
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
+/**
+ * Allows external processes to register a listener in WMShell to get updates about desktop task
+ * state.
+ */
+interface IDesktopTaskListener {
+
+ /** Desktop task visibility has change. Visible if at least 1 task is visible. */
+ oneway void onVisibilityChanged(int displayId, boolean visible);
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class DragToDismissBubbleScreenTestCfArm(flicker: FlickerTest) :
- DragToDismissBubbleScreenTest(flicker)
+ /** Desktop task stashed status has changed. */
+ oneway void onStashedChanged(int displayId, boolean stashed);
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
new file mode 100644
index 000000000000..b9cb5c75aaf0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 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.desktopmode
+
+import android.animation.Animator
+import android.animation.RectEvaluator
+import android.animation.ValueAnimator
+import android.graphics.Rect
+import android.os.IBinder
+import android.util.SparseArray
+import android.view.SurfaceControl
+import android.view.WindowManager.TRANSIT_CHANGE
+import android.window.TransitionInfo
+import android.window.TransitionRequestInfo
+import android.window.WindowContainerTransaction
+import androidx.core.animation.addListener
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
+import java.util.function.Supplier
+
+/** Handles the animation of quick resizing of desktop tasks. */
+class ToggleResizeDesktopTaskTransitionHandler(
+ private val transitions: Transitions,
+ private val transactionSupplier: Supplier<SurfaceControl.Transaction>
+) : Transitions.TransitionHandler {
+
+ private val rectEvaluator = RectEvaluator(Rect())
+ private val taskToDecorationMap = SparseArray<DesktopModeWindowDecoration>()
+
+ private var boundsAnimator: Animator? = null
+
+ constructor(
+ transitions: Transitions
+ ) : this(transitions, Supplier { SurfaceControl.Transaction() })
+
+ /** Starts a quick resize transition. */
+ fun startTransition(
+ wct: WindowContainerTransaction,
+ taskId: Int,
+ windowDecoration: DesktopModeWindowDecoration
+ ) {
+ // Pause relayout until the transition animation finishes.
+ windowDecoration.incrementRelayoutBlock()
+ transitions.startTransition(TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE, wct, this)
+ taskToDecorationMap.put(taskId, windowDecoration)
+ }
+
+ override fun startAnimation(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction,
+ finishCallback: Transitions.TransitionFinishCallback
+ ): Boolean {
+ val change = findRelevantChange(info)
+ val leash = change.leash
+ val taskId = change.taskInfo.taskId
+ val startBounds = change.startAbsBounds
+ val endBounds = change.endAbsBounds
+ val windowDecor =
+ taskToDecorationMap.removeReturnOld(taskId)
+ ?: throw IllegalStateException("Window decoration not found for task $taskId")
+
+ val tx = transactionSupplier.get()
+ boundsAnimator?.cancel()
+ boundsAnimator =
+ ValueAnimator.ofObject(rectEvaluator, startBounds, endBounds)
+ .setDuration(RESIZE_DURATION_MS)
+ .apply {
+ addListener(
+ onStart = {
+ startTransaction
+ .setPosition(
+ leash,
+ startBounds.left.toFloat(),
+ startBounds.top.toFloat()
+ )
+ .setWindowCrop(leash, startBounds.width(), startBounds.height())
+ .show(leash)
+ windowDecor.showResizeVeil(startTransaction, startBounds)
+ },
+ onEnd = {
+ finishTransaction
+ .setPosition(
+ leash,
+ endBounds.left.toFloat(),
+ endBounds.top.toFloat()
+ )
+ .setWindowCrop(leash, endBounds.width(), endBounds.height())
+ .show(leash)
+ windowDecor.hideResizeVeil()
+ finishCallback.onTransitionFinished(null)
+ boundsAnimator = null
+ }
+ )
+ addUpdateListener { anim ->
+ val rect = anim.animatedValue as Rect
+ tx.setPosition(leash, rect.left.toFloat(), rect.top.toFloat())
+ .setWindowCrop(leash, rect.width(), rect.height())
+ .show(leash)
+ windowDecor.updateResizeVeil(tx, rect)
+ }
+ start()
+ }
+ return true
+ }
+
+ override fun handleRequest(
+ transition: IBinder,
+ request: TransitionRequestInfo
+ ): WindowContainerTransaction? {
+ return null
+ }
+
+ private fun findRelevantChange(info: TransitionInfo): TransitionInfo.Change {
+ val matchingChanges =
+ info.changes.filter { c ->
+ !isWallpaper(c) && isValidTaskChange(c) && c.mode == TRANSIT_CHANGE
+ }
+ if (matchingChanges.size != 1) {
+ throw IllegalStateException(
+ "Expected 1 relevant change but found: ${matchingChanges.size}"
+ )
+ }
+ return matchingChanges.first()
+ }
+
+ private fun isWallpaper(change: TransitionInfo.Change): Boolean {
+ return (change.flags and TransitionInfo.FLAG_IS_WALLPAPER) != 0
+ }
+
+ private fun isValidTaskChange(change: TransitionInfo.Change): Boolean {
+ return change.taskInfo != null && change.taskInfo?.taskId != -1
+ }
+
+ companion object {
+ private const val RESIZE_DURATION_MS = 300L
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
index 99922fbc2d95..f9ea1d4e2a07 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
@@ -21,11 +21,17 @@ This code itself will not compile by itself, but the `protologtool` will preproc
building to check the log state (is enabled) before printing the print format style log.
**Notes**
-- ProtoLogs currently only work from soong builds (ie. via make/mp). We need to reimplement the
- tool for use with SysUI-studio
+- ProtoLogs are only fully supported from soong builds (ie. via make/mp). In SysUI-studio it falls
+ back to log via Logcat
- Non-text ProtoLogs are not currently supported with the Shell library (you can't view them with
traces in Winscope)
+### Kotlin
+
+Protolog tool does not yet have support for Kotlin code (see [b/168581922](https://b.corp.google.com/issues/168581922)).
+For logging in Kotlin, use the [KtProtoLog](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt)
+class which has a similar API to the Java ProtoLog class.
+
### Enabling ProtoLog command line logging
Run these commands to enable protologs for both WM Core and WM Shell to print to logcat.
```shell
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index be2489da3628..0bf8ec32c6c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -16,9 +16,6 @@
package com.android.wm.shell.draganddrop;
-import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
-import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
-import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DragEvent.ACTION_DRAG_ENDED;
import static android.view.DragEvent.ACTION_DRAG_ENTERED;
@@ -38,6 +35,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
+import android.app.ActivityTaskManager;
import android.content.ClipDescription;
import android.content.ComponentCallbacks2;
import android.content.Context;
@@ -205,8 +203,6 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
final Context context = mDisplayController.getDisplayContext(displayId)
.createWindowContext(TYPE_APPLICATION_OVERLAY, null);
final WindowManager wm = context.getSystemService(WindowManager.class);
-
- // TODO(b/169894807): Figure out the right layer for this, needs to be below the task bar
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
TYPE_APPLICATION_OVERLAY,
@@ -279,15 +275,11 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
}
if (event.getAction() == ACTION_DRAG_STARTED) {
- final boolean hasValidClipData = event.getClipData().getItemCount() > 0
- && (description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
- || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
- || description.hasMimeType(MIMETYPE_APPLICATION_TASK));
- pd.isHandlingDrag = hasValidClipData;
+ pd.isHandlingDrag = DragUtils.canHandleDrag(event);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
"Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s",
pd.isHandlingDrag, event.getClipData().getItemCount(),
- getMimeTypes(description));
+ DragUtils.getMimeTypesConcatenated(description));
}
if (!pd.isHandlingDrag) {
@@ -300,10 +292,13 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
Slog.w(TAG, "Unexpected drag start during an active drag");
return false;
}
+ // TODO(b/290391688): Also update the session data with task stack changes
InstanceId loggerSessionId = mLogger.logStart(event);
pd.activeDragCount++;
- pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
- event.getClipData(), loggerSessionId);
+ pd.dragSession = new DragSession(mContext, ActivityTaskManager.getInstance(),
+ mDisplayController.getDisplayLayout(displayId), event.getClipData());
+ pd.dragSession.update();
+ pd.dragLayout.prepare(pd.dragSession, loggerSessionId);
setDropTargetWindowVisibility(pd, View.VISIBLE);
notifyDragStarted();
break;
@@ -324,7 +319,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
break;
}
case ACTION_DRAG_ENDED:
- // TODO(b/169894807): Ensure sure it's not possible to get ENDED without DROP
+ // TODO(b/290391688): Ensure sure it's not possible to get ENDED without DROP
// or EXITED
if (pd.dragLayout.hasDropped()) {
mLogger.logDrop();
@@ -362,17 +357,6 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
pd.setWindowVisibility(visibility);
}
- private String getMimeTypes(ClipDescription description) {
- String mimeTypes = "";
- for (int i = 0; i < description.getMimeTypeCount(); i++) {
- if (i > 0) {
- mimeTypes += ", ";
- }
- mimeTypes += description.getMimeType(i);
- }
- return mimeTypes;
- }
-
/**
* Returns if any displays are currently ready to handle a drag/drop.
*/
@@ -462,6 +446,8 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
// A count of the number of active drags in progress to ensure that we only hide the window
// when all the drag animations have completed
int activeDragCount;
+ // The active drag session
+ DragSession dragSession;
PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayout dl) {
displayId = dispId;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index fb08c878837a..e70768b6b752 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -21,7 +21,6 @@ import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVIT
import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
@@ -41,16 +40,13 @@ import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPL
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
-import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
-import android.app.WindowConfiguration;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -67,14 +63,12 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.wm.shell.R;
-import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.List;
/**
* The policy for handling drag and drop operations to shell.
@@ -84,7 +78,6 @@ public class DragAndDropPolicy {
private static final String TAG = DragAndDropPolicy.class.getSimpleName();
private final Context mContext;
- private final ActivityTaskManager mActivityTaskManager;
private final Starter mStarter;
private final SplitScreenController mSplitScreen;
private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
@@ -94,14 +87,12 @@ public class DragAndDropPolicy {
private DragSession mSession;
public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
- this(context, ActivityTaskManager.getInstance(), splitScreen, new DefaultStarter(context));
+ this(context, splitScreen, new DefaultStarter(context));
}
@VisibleForTesting
- DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager,
- SplitScreenController splitScreen, Starter starter) {
+ DragAndDropPolicy(Context context, SplitScreenController splitScreen, Starter starter) {
mContext = context;
- mActivityTaskManager = activityTaskManager;
mSplitScreen = splitScreen;
mStarter = mSplitScreen != null ? mSplitScreen : starter;
}
@@ -109,11 +100,9 @@ public class DragAndDropPolicy {
/**
* Starts a new drag session with the given initial drag data.
*/
- void start(DisplayLayout displayLayout, ClipData data, InstanceId loggerSessionId) {
+ void start(DragSession session, InstanceId loggerSessionId) {
mLoggerSessionId = loggerSessionId;
- mSession = new DragSession(mActivityTaskManager, displayLayout, data);
- // TODO(b/169894807): Also update the session data with task stack changes
- mSession.update();
+ mSession = session;
RectF disallowHitRegion = (RectF) mSession.dragData.getExtra(EXTRA_DISALLOW_HIT_REGION);
if (disallowHitRegion == null) {
mDisallowHitRegion.setEmpty();
@@ -123,13 +112,6 @@ public class DragAndDropPolicy {
}
/**
- * Returns the last running task.
- */
- ActivityManager.RunningTaskInfo getLatestRunningTask() {
- return mSession.runningTaskInfo;
- }
-
- /**
* Returns the number of targets.
*/
int getNumTargets() {
@@ -286,49 +268,6 @@ public class DragAndDropPolicy {
}
/**
- * Per-drag session data.
- */
- private static class DragSession {
- private final ActivityTaskManager mActivityTaskManager;
- private final ClipData mInitialDragData;
-
- final DisplayLayout displayLayout;
- Intent dragData;
- ActivityManager.RunningTaskInfo runningTaskInfo;
- @WindowConfiguration.WindowingMode
- int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
- @WindowConfiguration.ActivityType
- int runningTaskActType = ACTIVITY_TYPE_STANDARD;
- boolean dragItemSupportsSplitscreen;
-
- DragSession(ActivityTaskManager activityTaskManager,
- DisplayLayout dispLayout, ClipData data) {
- mActivityTaskManager = activityTaskManager;
- mInitialDragData = data;
- displayLayout = dispLayout;
- }
-
- /**
- * Updates the session data based on the current state of the system.
- */
- void update() {
- List<ActivityManager.RunningTaskInfo> tasks =
- mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
- if (!tasks.isEmpty()) {
- final ActivityManager.RunningTaskInfo task = tasks.get(0);
- runningTaskInfo = task;
- runningTaskWinMode = task.getWindowingMode();
- runningTaskActType = task.getActivityType();
- }
-
- final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
- dragItemSupportsSplitscreen = info == null
- || ActivityInfo.isResizeableMode(info.resizeMode);
- dragData = mInitialDragData.getItemAt(0).getIntent();
- }
- }
-
- /**
* Interface for actually committing the task launches.
*/
public interface Starter {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index fe42822ab6a1..205a455200bd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -35,7 +35,6 @@ import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.StatusBarManager;
-import android.content.ClipData;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Color;
@@ -53,14 +52,13 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
-import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.ArrayList;
/**
- * Coordinates the visible drop targets for the current drag.
+ * Coordinates the visible drop targets for the current drag within a single display.
*/
public class DragLayout extends LinearLayout {
@@ -86,6 +84,7 @@ public class DragLayout extends LinearLayout {
private boolean mIsShowing;
private boolean mHasDropped;
+ private DragSession mSession;
@SuppressLint("WrongConstant")
public DragLayout(Context context, SplitScreenController splitScreenController,
@@ -182,16 +181,19 @@ public class DragLayout extends LinearLayout {
return mHasDropped;
}
- public void prepare(DisplayLayout displayLayout, ClipData initialData,
- InstanceId loggerSessionId) {
- mPolicy.start(displayLayout, initialData, loggerSessionId);
+ /**
+ * Called when a new drag is started.
+ */
+ public void prepare(DragSession session, InstanceId loggerSessionId) {
+ mPolicy.start(session, loggerSessionId);
+ mSession = session;
mHasDropped = false;
mCurrentTarget = null;
boolean alreadyInSplit = mSplitScreenController != null
&& mSplitScreenController.isSplitScreenVisible();
if (!alreadyInSplit) {
- ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask();
+ ActivityManager.RunningTaskInfo taskInfo1 = mSession.runningTaskInfo;
if (taskInfo1 != null) {
final int activityType = taskInfo1.getActivityType();
if (activityType == ACTIVITY_TYPE_STANDARD) {
@@ -356,7 +358,16 @@ public class DragLayout extends LinearLayout {
*/
public void hide(DragEvent event, Runnable hideCompleteCallback) {
mIsShowing = false;
- animateSplitContainers(false, hideCompleteCallback);
+ animateSplitContainers(false, () -> {
+ if (hideCompleteCallback != null) {
+ hideCompleteCallback.run();
+ }
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DROP:
+ case DragEvent.ACTION_DRAG_ENDED:
+ mSession = null;
+ }
+ });
// Reset the state if we previously force-ignore the bottom margin
mDropZoneView1.setForceIgnoreBottomMargin(false);
mDropZoneView2.setForceIgnoreBottomMargin(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
new file mode 100644
index 000000000000..478b6a9d95f6
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 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.draganddrop;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static android.content.Intent.EXTRA_USER;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
+import android.app.WindowConfiguration;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.net.Uri;
+import android.os.UserHandle;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.common.DisplayLayout;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * Per-drag session data.
+ */
+public class DragSession {
+ private final ActivityTaskManager mActivityTaskManager;
+ private final ClipData mInitialDragData;
+
+ final DisplayLayout displayLayout;
+ Intent dragData;
+ ActivityManager.RunningTaskInfo runningTaskInfo;
+ @WindowConfiguration.WindowingMode
+ int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
+ @WindowConfiguration.ActivityType
+ int runningTaskActType = ACTIVITY_TYPE_STANDARD;
+ boolean dragItemSupportsSplitscreen;
+
+ DragSession(Context context, ActivityTaskManager activityTaskManager,
+ DisplayLayout dispLayout, ClipData data) {
+ mActivityTaskManager = activityTaskManager;
+ mInitialDragData = data;
+ displayLayout = dispLayout;
+ }
+
+ /**
+ * Updates the session data based on the current state of the system.
+ */
+ void update() {
+ List<ActivityManager.RunningTaskInfo> tasks =
+ mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
+ if (!tasks.isEmpty()) {
+ final ActivityManager.RunningTaskInfo task = tasks.get(0);
+ runningTaskInfo = task;
+ runningTaskWinMode = task.getWindowingMode();
+ runningTaskActType = task.getActivityType();
+ }
+
+ final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
+ dragItemSupportsSplitscreen = info == null
+ || ActivityInfo.isResizeableMode(info.resizeMode);
+ dragData = mInitialDragData.getItemAt(0).getIntent();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
new file mode 100644
index 000000000000..7c0883d2538f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.draganddrop;
+
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+
+import android.content.ClipDescription;
+import android.view.DragEvent;
+
+/** Collection of utility classes for handling drag and drop. */
+public class DragUtils {
+ private static final String TAG = "DragUtils";
+
+ /**
+ * Returns whether we can handle this particular drag.
+ */
+ public static boolean canHandleDrag(DragEvent event) {
+ return event.getClipData().getItemCount() > 0
+ && (isAppDrag(event.getClipDescription()));
+ }
+
+ /**
+ * Returns whether this clip data description represents an app drag.
+ */
+ public static boolean isAppDrag(ClipDescription description) {
+ return description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
+ || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
+ || description.hasMimeType(MIMETYPE_APPLICATION_TASK);
+ }
+
+ /**
+ * Returns a list of the mime types provided in the clip description.
+ */
+ public static String getMimeTypesConcatenated(ClipDescription description) {
+ String mimeTypes = "";
+ for (int i = 0; i < description.getMimeTypeCount(); i++) {
+ if (i > 0) {
+ mimeTypes += ", ";
+ }
+ mimeTypes += description.getMimeType(i);
+ }
+ return mimeTypes;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
deleted file mode 100644
index 73deea54e52f..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2020 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.draganddrop;
-
-import android.animation.ObjectAnimator;
-import android.animation.RectEvaluator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.IntProperty;
-import android.util.Property;
-import android.view.animation.Interpolator;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.graphics.ColorUtils;
-import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.R;
-
-/**
- * Drawable to draw the region that the target will have once it is dropped.
- */
-public class DropOutlineDrawable extends Drawable {
-
- private static final int BOUNDS_DURATION = 200;
- private static final int ALPHA_DURATION = 135;
-
- private final IntProperty<DropOutlineDrawable> ALPHA =
- new IntProperty<DropOutlineDrawable>("alpha") {
- @Override
- public void setValue(DropOutlineDrawable d, int alpha) {
- d.setAlpha(alpha);
- }
-
- @Override
- public Integer get(DropOutlineDrawable d) {
- return d.getAlpha();
- }
- };
-
- private final Property<DropOutlineDrawable, Rect> BOUNDS =
- new Property<DropOutlineDrawable, Rect>(Rect.class, "bounds") {
- @Override
- public void set(DropOutlineDrawable d, Rect bounds) {
- d.setRegionBounds(bounds);
- }
-
- @Override
- public Rect get(DropOutlineDrawable d) {
- return d.getRegionBounds();
- }
- };
-
- private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
- private ObjectAnimator mBoundsAnimator;
- private ObjectAnimator mAlphaAnimator;
-
- private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- private final Rect mBounds = new Rect();
- private final float mCornerRadius;
- private final int mMaxAlpha;
- private int mColor;
-
- public DropOutlineDrawable(Context context) {
- super();
- // TODO(b/169894807): Use corner specific radii and maybe lower radius for non-edge corners
- mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
- mColor = context.getColor(R.color.drop_outline_background);
- mMaxAlpha = Color.alpha(mColor);
- // Initialize as hidden
- ALPHA.set(this, 0);
- }
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
- // Do nothing
- }
-
- @Override
- public void setAlpha(int alpha) {
- mColor = ColorUtils.setAlphaComponent(mColor, alpha);
- mPaint.setColor(mColor);
- invalidateSelf();
- }
-
- @Override
- public int getAlpha() {
- return Color.alpha(mColor);
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- protected void onBoundsChange(Rect bounds) {
- invalidateSelf();
- }
-
- @Override
- public void draw(@NonNull Canvas canvas) {
- canvas.drawRoundRect(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom,
- mCornerRadius, mCornerRadius, mPaint);
- }
-
- public void setRegionBounds(Rect bounds) {
- mBounds.set(bounds);
- invalidateSelf();
- }
-
- public Rect getRegionBounds() {
- return mBounds;
- }
-
- ObjectAnimator startBoundsAnimation(Rect toBounds, Interpolator interpolator) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Animate bounds: from=%s to=%s",
- mBounds, toBounds);
- if (mBoundsAnimator != null) {
- mBoundsAnimator.cancel();
- }
- mBoundsAnimator = ObjectAnimator.ofObject(this, BOUNDS, mRectEvaluator,
- mBounds, toBounds);
- mBoundsAnimator.setDuration(BOUNDS_DURATION);
- mBoundsAnimator.setInterpolator(interpolator);
- mBoundsAnimator.start();
- return mBoundsAnimator;
- }
-
- ObjectAnimator startVisibilityAnimation(boolean visible, Interpolator interpolator) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Animate alpha: from=%d to=%d",
- Color.alpha(mColor), visible ? mMaxAlpha : 0);
- if (mAlphaAnimator != null) {
- mAlphaAnimator.cancel();
- }
- mAlphaAnimator = ObjectAnimator.ofInt(this, ALPHA, Color.alpha(mColor),
- visible ? mMaxAlpha : 0);
- mAlphaAnimator.setDuration(ALPHA_DURATION);
- mAlphaAnimator.setInterpolator(interpolator);
- mAlphaAnimator.start();
- return mAlphaAnimator;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
index 04fc79acadbd..84027753435b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
@@ -19,9 +19,15 @@ package com.android.wm.shell.freeform;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
+import android.content.Context;
+import android.graphics.Rect;
import android.os.IBinder;
+import android.util.ArrayMap;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -31,6 +37,8 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
@@ -39,23 +47,37 @@ import java.util.ArrayList;
import java.util.List;
/**
- * The {@link Transitions.TransitionHandler} that handles freeform task maximizing and restoring
- * transitions.
+ * The {@link Transitions.TransitionHandler} that handles freeform task maximizing, closing, and
+ * restoring transitions.
*/
public class FreeformTaskTransitionHandler
implements Transitions.TransitionHandler, FreeformTaskTransitionStarter {
-
+ private static final int CLOSE_ANIM_DURATION = 400;
+ private final Context mContext;
private final Transitions mTransitions;
private final WindowDecorViewModel mWindowDecorViewModel;
+ private final DisplayController mDisplayController;
+ private final ShellExecutor mMainExecutor;
+ private final ShellExecutor mAnimExecutor;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
+ private final ArrayMap<IBinder, ArrayList<Animator>> mAnimations = new ArrayMap<>();
+
public FreeformTaskTransitionHandler(
ShellInit shellInit,
Transitions transitions,
- WindowDecorViewModel windowDecorViewModel) {
+ Context context,
+ WindowDecorViewModel windowDecorViewModel,
+ DisplayController displayController,
+ ShellExecutor mainExecutor,
+ ShellExecutor animExecutor) {
mTransitions = transitions;
+ mContext = context;
mWindowDecorViewModel = windowDecorViewModel;
+ mDisplayController = displayController;
+ mMainExecutor = mainExecutor;
+ mAnimExecutor = animExecutor;
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
shellInit.addInitCallback(this::onInit, this);
}
@@ -103,6 +125,14 @@ public class FreeformTaskTransitionHandler
@NonNull SurfaceControl.Transaction finishT,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
boolean transitionHandled = false;
+ final ArrayList<Animator> animations = new ArrayList<>();
+ final Runnable onAnimFinish = () -> {
+ if (!animations.isEmpty()) return;
+ mMainExecutor.execute(() -> {
+ mAnimations.remove(transition);
+ finishCallback.onTransitionFinished(null /* wct */);
+ });
+ };
for (TransitionInfo.Change change : info.getChanges()) {
if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
continue;
@@ -121,21 +151,45 @@ public class FreeformTaskTransitionHandler
case WindowManager.TRANSIT_TO_BACK:
transitionHandled |= startMinimizeTransition(transition);
break;
+ case WindowManager.TRANSIT_CLOSE:
+ if (change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ transitionHandled |= startCloseTransition(transition, change,
+ finishT, animations, onAnimFinish);
+ }
+ break;
}
}
-
- mPendingTransitionTokens.remove(transition);
-
if (!transitionHandled) {
return false;
}
-
+ mAnimations.put(transition, animations);
+ // startT must be applied before animations start.
startT.apply();
- mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ mAnimExecutor.execute(() -> {
+ for (Animator anim : animations) {
+ anim.start();
+ }
+ });
+ // Run this here in case no animators are created.
+ onAnimFinish.run();
+ mPendingTransitionTokens.remove(transition);
return true;
}
+ @Override
+ public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ ArrayList<Animator> animations = mAnimations.get(mergeTarget);
+ if (animations == null) return;
+ mAnimExecutor.execute(() -> {
+ for (Animator anim : animations) {
+ anim.end();
+ }
+ });
+
+ }
+
private boolean startChangeTransition(
IBinder transition,
int type,
@@ -165,6 +219,36 @@ public class FreeformTaskTransitionHandler
return mPendingTransitionTokens.contains(transition);
}
+ private boolean startCloseTransition(IBinder transition, TransitionInfo.Change change,
+ SurfaceControl.Transaction finishT, ArrayList<Animator> animations,
+ Runnable onAnimFinish) {
+ if (!mPendingTransitionTokens.contains(transition)) return false;
+ int screenHeight = mDisplayController
+ .getDisplayLayout(change.getTaskInfo().displayId).height();
+ ValueAnimator animator = new ValueAnimator();
+ animator.setDuration(CLOSE_ANIM_DURATION)
+ .setFloatValues(0f, 1f);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ SurfaceControl sc = change.getLeash();
+ finishT.hide(sc);
+ Rect startBounds = new Rect(change.getTaskInfo().configuration.windowConfiguration
+ .getBounds());
+ animator.addUpdateListener(animation -> {
+ t.setPosition(sc, startBounds.left,
+ startBounds.top + (animation.getAnimatedFraction() * screenHeight));
+ t.apply();
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ animations.remove(animator);
+ onAnimFinish.run();
+ }
+ });
+ animations.add(animator);
+ return true;
+ }
+
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index 56bd188a0d7d..2ef92adb90f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -19,7 +19,6 @@ package com.android.wm.shell.keyguard;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_OCCLUDING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
import static android.view.WindowManager.TRANSIT_SLEEP;
@@ -169,7 +168,7 @@ public class KeyguardTransitionHandler implements Transitions.TransitionHandler
// Post our finish callback to let startAnimation finish first.
mMainExecutor.executeDelayed(() -> {
mStartedTransitions.remove(transition);
- finishCallback.onTransitionFinished(wct, null);
+ finishCallback.onTransitionFinished(wct);
}, 0);
}
});
@@ -206,7 +205,7 @@ public class KeyguardTransitionHandler implements Transitions.TransitionHandler
// implementing an AIDL interface.
Log.wtf(TAG, "RemoteException thrown from KeyguardService transition", e);
}
- nextFinishCallback.onTransitionFinished(null, null);
+ nextFinishCallback.onTransitionFinished(null);
} else if (nextInfo.getType() == TRANSIT_SLEEP) {
// An empty SLEEP transition comes in as a signal to abort transitions whenever a sleep
// token is held. In cases where keyguard is showing, we are running the animation for
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index f34d2a827e69..a9aa6badcfe2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -67,4 +67,11 @@ public interface Pip {
* view hierarchy or destroyed.
*/
default void removePipExclusionBoundsChangeListener(Consumer<Rect> listener) { }
+
+ /**
+ * @return {@link PipTransitionController} instance.
+ */
+ default PipTransitionController getPipTransitionController() {
+ return null;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
index 2590cab9ff2e..ddffb5bdacde 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
@@ -150,13 +150,15 @@ public class PipMediaController {
mContext = context;
mMainHandler = mainHandler;
mHandlerExecutor = new HandlerExecutor(mMainHandler);
- IntentFilter mediaControlFilter = new IntentFilter();
- mediaControlFilter.addAction(ACTION_PLAY);
- mediaControlFilter.addAction(ACTION_PAUSE);
- mediaControlFilter.addAction(ACTION_NEXT);
- mediaControlFilter.addAction(ACTION_PREV);
- mContext.registerReceiverForAllUsers(mMediaActionReceiver, mediaControlFilter,
- SYSTEMUI_PERMISSION, mainHandler, Context.RECEIVER_EXPORTED);
+ if (!PipUtils.isPip2ExperimentEnabled()) {
+ IntentFilter mediaControlFilter = new IntentFilter();
+ mediaControlFilter.addAction(ACTION_PLAY);
+ mediaControlFilter.addAction(ACTION_PAUSE);
+ mediaControlFilter.addAction(ACTION_NEXT);
+ mediaControlFilter.addAction(ACTION_PREV);
+ mContext.registerReceiverForAllUsers(mMediaActionReceiver, mediaControlFilter,
+ SYSTEMUI_PERMISSION, mainHandler, Context.RECEIVER_EXPORTED);
+ }
// Creates the standard media buttons that we may show.
mPauseAction = getDefaultRemoteAction(R.string.pip_pause,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 08da4857a0b0..0d55018ba580 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -364,13 +364,15 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mMainExecutor = mainExecutor;
// TODO: Can be removed once wm components are created on the shell-main thread
- mMainExecutor.execute(() -> {
- mTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_PIP);
- });
- mTaskOrganizer.addFocusListener(this);
- mPipTransitionController.setPipOrganizer(this);
- displayController.addDisplayWindowListener(this);
- pipTransitionController.registerPipTransitionCallback(mPipTransitionCallback);
+ if (!PipUtils.isPip2ExperimentEnabled()) {
+ mMainExecutor.execute(() -> {
+ mTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_PIP);
+ });
+ mTaskOrganizer.addFocusListener(this);
+ mPipTransitionController.setPipOrganizer(this);
+ displayController.addDisplayWindowListener(this);
+ pipTransitionController.registerPipTransitionCallback(mPipTransitionCallback);
+ }
}
public PipTransitionController getTransitionController() {
@@ -590,7 +592,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
SplitScreenController split = mSplitScreenOptional.get();
if (split.isTaskInSplitScreen(mTaskInfo.lastParentTaskIdBeforePip)) {
split.prepareExitSplitScreen(wct, split.getStageOfTask(
- mTaskInfo.lastParentTaskIdBeforePip));
+ mTaskInfo.lastParentTaskIdBeforePip),
+ SplitScreenController.EXIT_REASON_APP_FINISHED);
}
}
mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, destinationBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index e3d53fc415db..2563d984b793 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -447,7 +447,7 @@ public class PipTransition extends PipTransitionController {
// handler if there is a pending PiP animation.
final Transitions.TransitionFinishCallback finishCallback = mFinishCallback;
mFinishCallback = null;
- finishCallback.onTransitionFinished(wct, null /* callback */);
+ finishCallback.onTransitionFinished(wct);
}
@Override
@@ -456,7 +456,7 @@ public class PipTransition extends PipTransitionController {
// for example, when app crashes while in PiP and exit transition has not started
mCurrentPipTaskToken = null;
if (mFinishCallback == null) return;
- mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
+ mFinishCallback.onTransitionFinished(null /* wct */);
mFinishCallback = null;
mFinishTransaction = null;
}
@@ -586,7 +586,7 @@ public class PipTransition extends PipTransitionController {
final boolean useLocalLeash = activitySc != null;
final boolean toFullscreen = pipChange.getEndAbsBounds().equals(
mPipBoundsState.getDisplayBounds());
- mFinishCallback = (wct, wctCB) -> {
+ mFinishCallback = (wct) -> {
mPipOrganizer.onExitPipFinished(taskInfo);
// TODO(b/286346098): remove the OPEN app flicker completely
@@ -610,7 +610,7 @@ public class PipTransition extends PipTransitionController {
mPipAnimationController.resetAnimatorState();
finishTransaction.remove(pipLeash);
}
- finishCallback.onTransitionFinished(wct, wctCB);
+ finishCallback.onTransitionFinished(wct);
};
mFinishTransaction = finishTransaction;
@@ -750,7 +750,7 @@ public class PipTransition extends PipTransitionController {
finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
mPipDisplayLayoutState.getDisplayBounds());
mPipOrganizer.onExitPipFinished(taskInfo);
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
}
/** Whether we should handle the given {@link TransitionInfo} animation as entering PIP. */
@@ -1045,7 +1045,7 @@ public class PipTransition extends PipTransitionController {
startTransaction.apply();
mPipOrganizer.onExitPipFinished(taskInfo);
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
}
private void resetPrevPip(@NonNull TransitionInfo.Change prevPipTaskChange,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 63627938ec87..0f74f9e323a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -142,8 +142,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipAnimationController = pipAnimationController;
mTransitions = transitions;
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- shellInit.addInitCallback(this::onInit, this);
+ if (!PipUtils.isPip2ExperimentEnabled()) {
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ shellInit.addInitCallback(this::onInit, this);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java
index 8b98790d3499..3cd9848d5686 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java
@@ -27,6 +27,7 @@ import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.Context;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
@@ -46,6 +47,9 @@ public class PipUtils {
// Minimum difference between two floats (e.g. aspect ratios) to consider them not equal.
private static final double EPSILON = 1e-7;
+ private static final String ENABLE_PIP2_IMPLEMENTATION =
+ "persist.wm.debug.enable_pip2_implementation";
+
/**
* @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack.
* The component name may be null if no such activity exists.
@@ -134,4 +138,8 @@ public class PipUtils {
return null;
}
}
+
+ public static boolean isPip2ExperimentEnabled() {
+ return SystemProperties.getBoolean(ENABLE_PIP2_IMPLEMENTATION, false);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
index 4a06d84ce90d..8c2879e0d816 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
@@ -383,6 +383,9 @@ public class PipAccessibilityInteractionConnection {
}
@Override
- public void attachAccessibilityOverlayToWindow(SurfaceControl sc) {}
+ public void attachAccessibilityOverlayToWindow(
+ SurfaceControl sc,
+ int interactionId,
+ IAccessibilityInteractionConnectionCallback callback) {}
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 65727b6145e4..26b7b684e1d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -352,6 +352,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mMainExecutor.executeDelayed(
mMovePipInResponseToKeepClearAreasChangeCallback,
PIP_KEEP_CLEAR_AREAS_DELAY);
+
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onKeepClearAreasChanged: restricted=%s, unrestricted=%s",
+ restricted, unrestricted);
}
}
}
@@ -461,8 +465,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
Optional<OneHandedController> oneHandedController,
ShellExecutor mainExecutor
) {
-
-
mContext = context;
mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
@@ -493,7 +495,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mDisplayInsetsController = displayInsetsController;
mTabletopModeController = tabletopModeController;
- shellInit.addInitCallback(this::onInit, this);
+ if (!PipUtils.isPip2ExperimentEnabled()) {
+ shellInit.addInitCallback(this::onInit, this);
+ }
}
private void onInit() {
@@ -795,6 +799,14 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
private void onDisplayChangedUncheck(DisplayLayout layout, boolean saveRestoreSnapFraction) {
+ if (mPipTransitionState.getInSwipePipToHomeTransition()) {
+ // If orientation is changed when performing swipe-pip animation, DisplayLayout has
+ // been updated in startSwipePipToHome. So it is unnecessary to update again when
+ // receiving onDisplayConfigurationChanged. This also avoids TouchHandler.userResizeTo
+ // update surface position in different orientation by the intermediate state. The
+ // desired resize will be done by the end of transition.
+ return;
+ }
Runnable updateDisplayLayout = () -> {
final boolean fromRotation = Transitions.ENABLE_SHELL_TRANSITIONS
&& mPipDisplayLayoutState.getDisplayLayout().rotation() != layout.rotation();
@@ -939,12 +951,19 @@ public class PipController implements PipTransitionController.PipTransitionCallb
* Sets both shelf visibility and its height.
*/
private void setShelfHeight(boolean visible, int height) {
+ if (mEnablePipKeepClearAlgorithm) {
+ // turn this into Launcher keep clear area registration instead
+ setLauncherKeepClearAreaHeight(visible, height);
+ return;
+ }
if (!mIsKeyguardShowingOrAnimating) {
setShelfHeightLocked(visible, height);
}
}
private void setLauncherKeepClearAreaHeight(boolean visible, int height) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "setLauncherKeepClearAreaHeight: visible=%b, height=%d", visible, height);
if (visible) {
Rect rect = new Rect(
0, mPipBoundsState.getDisplayBounds().bottom - height,
@@ -1002,9 +1021,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb
int launcherRotation, Rect hotseatKeepClearArea) {
if (mEnablePipKeepClearAlgorithm) {
- // pre-emptively add the keep clear area for Hotseat, so that it is taken into account
+ // preemptively add the keep clear area for Hotseat, so that it is taken into account
// when calculating the entry destination bounds of PiP window
- mPipBoundsState.getRestrictedKeepClearAreas().add(hotseatKeepClearArea);
+ mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG,
+ hotseatKeepClearArea);
} else {
int shelfHeight = hotseatKeepClearArea.height();
setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
@@ -1253,6 +1273,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb
PipController.this.showPictureInPictureMenu();
});
}
+
+ @Override
+ public PipTransitionController getPipTransitionController() {
+ return mPipTransitionController;
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 9729a4007bac..da455f85d908 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -33,9 +33,10 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import com.android.wm.shell.R;
-import com.android.wm.shell.bubbles.DismissView;
-import com.android.wm.shell.common.DismissCircleView;
+import com.android.wm.shell.bubbles.DismissViewUtils;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.bubbles.DismissCircleView;
+import com.android.wm.shell.common.bubbles.DismissView;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.android.wm.shell.pip.PipUiEventLogger;
@@ -106,6 +107,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
}
mTargetViewContainer = new DismissView(mContext);
+ DismissViewUtils.setup(mTargetViewContainer);
mTargetView = mTargetViewContainer.getCircle();
mTargetViewContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> {
if (!windowInsets.equals(mWindowInsets)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
index 7971c049ff3b..c6e5cf25f844 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
@@ -123,18 +123,19 @@ public class PipSizeSpecHandler {
final int totalVerticalPadding = getInsetBounds().top
+ (getDisplayBounds().height() - getInsetBounds().bottom);
- final int shorterLength = (int) (1f * Math.min(
- getDisplayBounds().width() - totalHorizontalPadding,
- getDisplayBounds().height() - totalVerticalPadding));
+ final int shorterLength = Math.min(getDisplayBounds().width() - totalHorizontalPadding,
+ getDisplayBounds().height() - totalVerticalPadding);
int maxWidth, maxHeight;
// use the optimized max sizing logic only within a certain aspect ratio range
if (aspectRatio >= mOptimizedAspectRatio && aspectRatio <= 1 / mOptimizedAspectRatio) {
// this formula and its derivation is explained in b/198643358#comment16
- maxWidth = (int) (mOptimizedAspectRatio * shorterLength
+ maxWidth = Math.round(mOptimizedAspectRatio * shorterLength
+ shorterLength * (aspectRatio - mOptimizedAspectRatio) / (1
+ aspectRatio));
+ // make sure the max width doesn't go beyond shorter screen length after rounding
+ maxWidth = Math.min(maxWidth, shorterLength);
maxHeight = Math.round(maxWidth / aspectRatio);
} else {
if (aspectRatio > 1f) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 2c4f76b1f34b..372ade333218 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -57,6 +57,7 @@ import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ShellInit;
@@ -228,7 +229,9 @@ public class PipTouchHandler {
// TODO(b/181599115): This should really be initializes as part of the pip controller, but
// until all PIP implementations derive from the controller, just initialize the touch handler
// if it is needed
- shellInit.addInitCallback(this::onInit, this);
+ if (!PipUtils.isPip2ExperimentEnabled()) {
+ shellInit.addInitCallback(this::onInit, this);
+ }
}
/**
@@ -591,6 +594,13 @@ public class PipTouchHandler {
return true;
}
+ // Ignore the motion event When the entry animation is waiting to be started
+ if (!mTouchState.isUserInteracting() && mPipTaskOrganizer.isEntryScheduled()) {
+ ProtoLog.wtf(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Waiting to start the entry animation, skip the motion event.", TAG);
+ return true;
+ }
+
// Update the touch state
mTouchState.onTouchEvent(ev);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
index 5f6b3fe1e250..fc0b876e1bde 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
@@ -77,6 +77,19 @@ abstract class TvPipAction {
return mActionType;
}
+ static String getActionTypeString(@ActionType int actionType) {
+ switch (actionType) {
+ case ACTION_FULLSCREEN: return "ACTION_FULLSCREEN";
+ case ACTION_CLOSE: return "ACTION_CLOSE";
+ case ACTION_MOVE: return "ACTION_MOVE";
+ case ACTION_EXPAND_COLLAPSE: return "ACTION_EXPAND_COLLAPSE";
+ case ACTION_CUSTOM: return "ACTION_CUSTOM";
+ case ACTION_CUSTOM_CLOSE: return "ACTION_CUSTOM_CLOSE";
+ default:
+ return "UNDEFINED";
+ }
+ }
+
abstract void populateButton(@NonNull TvWindowMenuActionButton button, Handler mainHandler);
abstract PendingIntent getPendingIntent();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
index 3b44f10ebe62..11c2665c9665 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
@@ -56,8 +56,10 @@ public class TvPipActionsProvider implements TvPipAction.SystemActionsHandler {
private final List<Listener> mListeners = new ArrayList<>();
private final TvPipAction.SystemActionsHandler mSystemActionsHandler;
- private final List<TvPipAction> mActionsList;
+ private final List<TvPipAction> mActionsList = new ArrayList<>();
+ private final TvPipSystemAction mFullscreenAction;
private final TvPipSystemAction mDefaultCloseAction;
+ private final TvPipSystemAction mMoveAction;
private final TvPipSystemAction mExpandCollapseAction;
private final List<RemoteAction> mMediaActions = new ArrayList<>();
@@ -67,26 +69,27 @@ public class TvPipActionsProvider implements TvPipAction.SystemActionsHandler {
TvPipAction.SystemActionsHandler systemActionsHandler) {
mSystemActionsHandler = systemActionsHandler;
- mActionsList = new ArrayList<>();
- mActionsList.add(new TvPipSystemAction(ACTION_FULLSCREEN, R.string.pip_fullscreen,
+ mFullscreenAction = new TvPipSystemAction(ACTION_FULLSCREEN, R.string.pip_fullscreen,
R.drawable.pip_ic_fullscreen_white, ACTION_TO_FULLSCREEN, context,
- mSystemActionsHandler));
-
+ mSystemActionsHandler);
mDefaultCloseAction = new TvPipSystemAction(ACTION_CLOSE, R.string.pip_close,
R.drawable.pip_ic_close_white, ACTION_CLOSE_PIP, context, mSystemActionsHandler);
- mActionsList.add(mDefaultCloseAction);
-
- mActionsList.add(new TvPipSystemAction(ACTION_MOVE, R.string.pip_move,
- R.drawable.pip_ic_move_white, ACTION_MOVE_PIP, context, mSystemActionsHandler));
-
+ mMoveAction = new TvPipSystemAction(ACTION_MOVE, R.string.pip_move,
+ R.drawable.pip_ic_move_white, ACTION_MOVE_PIP, context, mSystemActionsHandler);
mExpandCollapseAction = new TvPipSystemAction(ACTION_EXPAND_COLLAPSE, R.string.pip_collapse,
R.drawable.pip_ic_collapse, ACTION_TOGGLE_EXPANDED_PIP, context,
mSystemActionsHandler);
- mActionsList.add(mExpandCollapseAction);
+ initActions();
pipMediaController.addActionListener(this::onMediaActionsChanged);
}
+ private void initActions() {
+ mActionsList.add(mFullscreenAction);
+ mActionsList.add(mDefaultCloseAction);
+ mActionsList.add(mMoveAction);
+ }
+
@Override
public void executeAction(@TvPipAction.ActionType int actionType) {
if (mSystemActionsHandler != null) {
@@ -199,6 +202,14 @@ public class TvPipActionsProvider implements TvPipAction.SystemActionsHandler {
}
}
+ void reset() {
+ mActionsList.clear();
+ mMediaActions.clear();
+ mAppActions.clear();
+
+ initActions();
+ }
+
List<TvPipAction> getActionsList() {
return mActionsList;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
index e1737eccc6e1..3f3951a2d4f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
@@ -81,6 +81,7 @@ public class TvPipBoundsState extends PipBoundsState {
super(context, pipSizeSpecHandler, pipDisplayLayoutState);
mContext = context;
updateDefaultGravity();
+ mTvPipGravity = mDefaultGravity;
mPreviousCollapsedGravity = mDefaultGravity;
mIsTvExpandedPipSupported = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 02eeb2ac4fd5..2482acf60267 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -478,6 +478,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
mActionBroadcastReceiver.unregister();
mTvPipMenuController.closeMenu();
+ mTvPipActionsProvider.reset();
mTvPipBoundsState.resetTvPipState();
mTvPipBoundsController.reset();
setState(STATE_NO_PIP);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipTransition.java
new file mode 100644
index 000000000000..8ab85d0829df
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipTransition.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 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.pip2;
+
+import android.annotation.NonNull;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.pip.PipAnimationController;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipMenuController;
+import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.Transitions;
+
+/** Placeholder, for demonstrate purpose only. */
+public abstract class PipTransition extends PipTransitionController {
+ public PipTransition(
+ @NonNull ShellInit shellInit,
+ @NonNull ShellTaskOrganizer shellTaskOrganizer,
+ @NonNull Transitions transitions,
+ PipBoundsState pipBoundsState,
+ PipMenuController pipMenuController,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipAnimationController pipAnimationController) {
+ super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController,
+ pipBoundsAlgorithm, pipAnimationController);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/README.md b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/README.md
new file mode 100644
index 000000000000..415ea8f959cc
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/README.md
@@ -0,0 +1,3 @@
+# PLACEHOLDER
+
+This is meant to be the doc for the pip2 package. \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 2a61445b27ba..3af1b75f33b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -35,7 +35,7 @@ public enum ShellProtoLogGroup implements IProtoLogGroup {
WM_SHELL_RECENTS_TRANSITION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
"ShellRecents"),
WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
- Consts.TAG_WM_SHELL),
+ "ShellDragAndDrop"),
WM_SHELL_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_STARTING_WINDOW),
WM_SHELL_BACK_PREVIEW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
@@ -49,7 +49,7 @@ public enum ShellProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM_SPLIT_SCREEN),
WM_SHELL_SYSUI_EVENTS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
- WM_SHELL_DESKTOP_MODE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ WM_SHELL_DESKTOP_MODE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
WM_SHELL_FLOATING_APPS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 843e5af67af9..a11d9528a170 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -567,15 +567,18 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
&& taskInfo.configuration.windowConfiguration.isAlwaysOnTop()) {
// Tasks that are always on top (e.g. bubbles), will handle their own transition
// as they are on top of everything else. So cancel the merge here.
- cancel("task #" + taskInfo.taskId + " is always_on_top");
+ cancel(false /* toHome */, false /* withScreenshots */,
+ "task #" + taskInfo.taskId + " is always_on_top");
return;
}
final boolean isRootTask = taskInfo != null
&& TransitionInfo.isIndependent(change, info);
+ final boolean isRecentsTask = mRecentsTask != null
+ && mRecentsTask.equals(change.getContainer());
hasTaskChange = hasTaskChange || isRootTask;
final boolean isLeafTask = leafTaskFilter.test(change);
if (TransitionUtil.isOpeningType(change.getMode())) {
- if (mRecentsTask != null && mRecentsTask.equals(change.getContainer())) {
+ if (isRecentsTask) {
recentsOpening = change;
} else if (isRootTask || isLeafTask) {
if (isLeafTask && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
@@ -590,7 +593,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
openingTaskIsLeafs.add(isLeafTask ? 1 : 0);
}
} else if (TransitionUtil.isClosingType(change.getMode())) {
- if (mRecentsTask != null && mRecentsTask.equals(change.getContainer())) {
+ if (isRecentsTask) {
foundRecentsClosing = true;
} else if (isRootTask || isLeafTask) {
if (closingTasks == null) {
@@ -601,7 +604,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
} else if (change.getMode() == TRANSIT_CHANGE) {
// Finish recents animation if the display is changed, so the default
// transition handler can play the animation such as rotation effect.
- if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) {
+ if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)
+ && info.getType() == TRANSIT_CHANGE) {
// This call to cancel will use the screenshots taken preemptively in
// handleMidTransitionRequest() prior to the display changing
cancel(mWillFinishToHome, true /* withScreenshots */, "display change");
@@ -611,7 +615,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
if (!TransitionUtil.isOrderOnly(change) && isLeafTask) {
hasChangingApp = true;
} else if (isLeafTask && taskInfo.topActivityType == ACTIVITY_TYPE_HOME
- && !mRecentsTask.equals(change.getContainer())) {
+ && !isRecentsTask ) {
// Unless it is a 3p launcher. This means that the 3p launcher was already
// visible (eg. the "pausing" task is translucent over the 3p launcher).
// Treat it as if we are "re-opening" the 3p launcher.
@@ -767,7 +771,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
Slog.e(TAG, "Error sending appeared tasks to recents animation", e);
}
}
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
}
/** For now, just set-up a jump-cut to the new activity. */
@@ -933,7 +937,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
}
}
cleanUp();
- finishCB.onTransitionFinished(wct.isEmpty() ? null : wct, null /* wctCB */);
+ finishCB.onTransitionFinished(wct.isEmpty() ? null : wct);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index 89538cb394d4..e52235fda80f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -24,6 +24,9 @@ import android.window.WindowContainerTransaction;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
+
+import java.util.Optional;
/**
* Main stage for split-screen mode. When split-screen is active all standard activity types launch
@@ -35,9 +38,10 @@ class MainStage extends StageTaskListener {
MainStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession, IconProvider iconProvider) {
+ SurfaceSession surfaceSession, IconProvider iconProvider,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
super(context, taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
- iconProvider);
+ iconProvider, windowDecorViewModel);
}
boolean isActive() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 8639b36faf4c..9903113c5453 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -25,6 +25,9 @@ import android.window.WindowContainerTransaction;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
+
+import java.util.Optional;
/**
* Side stage for split-screen mode. Only tasks that are explicitly pinned to this stage show up
@@ -37,9 +40,10 @@ class SideStage extends StageTaskListener {
SideStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession, IconProvider iconProvider) {
+ SurfaceSession surfaceSession, IconProvider iconProvider,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
super(context, taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
- iconProvider);
+ iconProvider, windowDecorViewModel);
}
boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index e7a367f1992d..5fa26542ee07 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -31,6 +31,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.common.split.SplitScreenUtils.isValidToSplit;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.samePackage;
+import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -50,6 +51,7 @@ import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Slog;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -76,6 +78,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
@@ -94,6 +97,7 @@ import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -171,6 +175,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
private final TransactionPool mTransactionPool;
private final IconProvider mIconProvider;
private final Optional<RecentTasksController> mRecentTasksOptional;
+ private final LaunchAdjacentController mLaunchAdjacentController;
+ private final Optional<WindowDecorViewModel> mWindowDecorViewModel;
private final SplitScreenShellCommandHandler mSplitScreenShellCommandHandler;
private final String[] mAppsSupportMultiInstances;
@@ -197,6 +203,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
TransactionPool transactionPool,
IconProvider iconProvider,
Optional<RecentTasksController> recentTasks,
+ LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel,
ShellExecutor mainExecutor) {
mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
@@ -213,6 +221,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mTransactionPool = transactionPool;
mIconProvider = iconProvider;
mRecentTasksOptional = recentTasks;
+ mLaunchAdjacentController = launchAdjacentController;
+ mWindowDecorViewModel = windowDecorViewModel;
mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
// TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
// override for this controller from the base module
@@ -242,6 +252,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
TransactionPool transactionPool,
IconProvider iconProvider,
RecentTasksController recentTasks,
+ LaunchAdjacentController launchAdjacentController,
+ WindowDecorViewModel windowDecorViewModel,
ShellExecutor mainExecutor,
StageCoordinator stageCoordinator) {
mShellCommandHandler = shellCommandHandler;
@@ -259,6 +271,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mTransactionPool = transactionPool;
mIconProvider = iconProvider;
mRecentTasksOptional = Optional.of(recentTasks);
+ mLaunchAdjacentController = launchAdjacentController;
+ mWindowDecorViewModel = Optional.of(windowDecorViewModel);
mStageCoordinator = stageCoordinator;
mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
shellInit.addInitCallback(this::onInit, this);
@@ -291,13 +305,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator = createStageCoordinator();
}
mDragAndDropController.ifPresent(controller -> controller.setSplitScreenController(this));
+ mWindowDecorViewModel.ifPresent(viewModel -> viewModel.setSplitScreenController(this));
}
protected StageCoordinator createStageCoordinator() {
return new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mTaskOrganizer, mDisplayController, mDisplayImeController,
- mDisplayInsetsController, mTransitions, mTransactionPool,
- mIconProvider, mMainExecutor, mRecentTasksOptional);
+ mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider,
+ mMainExecutor, mRecentTasksOptional, mLaunchAdjacentController,
+ mWindowDecorViewModel);
}
@Override
@@ -407,8 +423,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
* transition.
*/
public void prepareExitSplitScreen(WindowContainerTransaction wct,
- @StageType int stageToTop) {
+ @StageType int stageToTop, @ExitReason int reason) {
mStageCoordinator.prepareExitSplitScreen(stageToTop, wct);
+ mStageCoordinator.clearSplitPairedInRecents(reason);
}
public void enterSplitScreen(int taskId, boolean leftOrTop) {
@@ -537,6 +554,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
} else {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startShortcut",
+ "app package " + packageName + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
return;
@@ -566,6 +585,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startShortcutAndTaskWithLegacyTransition",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -598,12 +619,14 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startShortcutAndTask",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
}
- mStageCoordinator.startShortcutAndTask(shortcutInfo, options1, taskId, options2,
- splitPosition, splitRatio, remoteTransition, instanceId);
+ mStageCoordinator.startShortcutAndTask(shortcutInfo, activityOptions.toBundle(), taskId,
+ options2, splitPosition, splitRatio, remoteTransition, instanceId);
}
/**
@@ -633,6 +656,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntentAndTaskWithLegacyTransition",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -663,6 +688,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntentAndTask",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -691,6 +718,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
pendingIntent2 = null;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntentsWithLegacyTransition",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -709,24 +738,38 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
Intent fillInIntent2 = null;
final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent1);
final String packageName2 = SplitScreenUtils.getPackageName(pendingIntent2);
+ final ActivityOptions activityOptions1 = options1 != null
+ ? ActivityOptions.fromBundle(options1) : ActivityOptions.makeBasic();
+ final ActivityOptions activityOptions2 = options2 != null
+ ? ActivityOptions.fromBundle(options2) : ActivityOptions.makeBasic();
if (samePackage(packageName1, packageName2, userId1, userId2)) {
if (supportMultiInstancesSplit(packageName1)) {
fillInIntent1 = new Intent();
fillInIntent1.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
fillInIntent2 = new Intent();
fillInIntent2.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+
+ if (shortcutInfo1 != null) {
+ activityOptions1.setApplyMultipleTaskFlagForShortcut(true);
+ }
+ if (shortcutInfo2 != null) {
+ activityOptions2.setApplyMultipleTaskFlagForShortcut(true);
+ }
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
} else {
pendingIntent2 = null;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntents",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
}
- mStageCoordinator.startIntents(pendingIntent1, fillInIntent1, shortcutInfo1, options1,
- pendingIntent2, fillInIntent2, shortcutInfo2, options2, splitPosition, splitRatio,
- remoteTransition, instanceId);
+ mStageCoordinator.startIntents(pendingIntent1, fillInIntent1, shortcutInfo1,
+ activityOptions1.toBundle(), pendingIntent2, fillInIntent2, shortcutInfo2,
+ activityOptions2.toBundle(), splitPosition, splitRatio, remoteTransition,
+ instanceId);
}
@Override
@@ -766,6 +809,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
} else {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntent",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index d21f8a48e62a..99be5b8ee861 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -43,7 +43,6 @@ import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
@@ -109,7 +108,7 @@ class SplitScreenTransitions {
if (pendingTransition.mCanceled) {
// The pending transition was canceled, so skip playing animation.
startTransaction.apply();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
return;
}
@@ -211,7 +210,7 @@ class SplitScreenTransitions {
}
}
t.apply();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
}
/** Play animation for drag divider dismiss transition. */
@@ -238,7 +237,7 @@ class SplitScreenTransitions {
mAnimations.remove(va);
if (animated) {
mTransitions.getMainExecutor().execute(() -> {
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
});
}
});
@@ -250,7 +249,7 @@ class SplitScreenTransitions {
}
}
startTransaction.apply();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
}
/** Play animation for resize transition. */
@@ -283,7 +282,7 @@ class SplitScreenTransitions {
mAnimations.remove(va);
if (animated) {
mTransitions.getMainExecutor().execute(() -> {
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
});
}
});
@@ -291,7 +290,7 @@ class SplitScreenTransitions {
}
startTransaction.apply();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
}
boolean isPendingTransition(IBinder transition) {
@@ -391,7 +390,7 @@ class SplitScreenTransitions {
if (mPendingResize != null) {
mPendingResize.cancel(null);
mAnimations.clear();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
}
IBinder transition = mTransitions.startTransition(TRANSIT_CHANGE, wct, handler);
@@ -450,7 +449,7 @@ class SplitScreenTransitions {
}
}
- void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
+ void onFinish(WindowContainerTransaction wct) {
if (!mAnimations.isEmpty()) return;
if (wct == null) wct = new WindowContainerTransaction();
@@ -470,7 +469,7 @@ class SplitScreenTransitions {
mOnFinish.run();
if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(wct /* wct */, wctCB /* wctCB */);
+ mFinishCallback.onTransitionFinished(wct /* wct */);
mFinishCallback = null;
}
}
@@ -495,7 +494,7 @@ class SplitScreenTransitions {
mTransactionPool.release(transaction);
mTransitions.getMainExecutor().execute(() -> {
mAnimations.remove(va);
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
});
}
});
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 7699e2f7c13d..3758b6890f48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -28,6 +28,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
@@ -41,6 +42,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.common.split.SplitScreenConstants.splitPositionToString;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
+import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -81,7 +83,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
@@ -121,6 +122,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -138,6 +140,7 @@ import com.android.wm.shell.transition.LegacyTransitions;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.util.SplitBounds;
import com.android.wm.shell.util.TransitionUtil;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -193,6 +196,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// if user is opening another task(s).
private final ArrayList<Integer> mPausingTasks = new ArrayList<>();
private final Optional<RecentTasksController> mRecentTasks;
+ private final LaunchAdjacentController mLaunchAdjacentController;
+ private final Optional<WindowDecorViewModel> mWindowDecorViewModel;
private final Rect mTempRect1 = new Rect();
private final Rect mTempRect2 = new Rect();
@@ -213,6 +218,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private boolean mIsDropEntering;
private boolean mIsExiting;
private boolean mIsRootTranslucent;
+ @VisibleForTesting
+ int mTopStageAfterFoldDismiss;
private DefaultMixedHandler mMixedHandler;
private final Toast mSplitUnsupportedToast;
@@ -270,7 +277,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool,
IconProvider iconProvider, ShellExecutor mainExecutor,
- Optional<RecentTasksController> recentTasks) {
+ Optional<RecentTasksController> recentTasks,
+ LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
@@ -278,6 +287,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mLogger = new SplitscreenEventLogger();
mMainExecutor = mainExecutor;
mRecentTasks = recentTasks;
+ mLaunchAdjacentController = launchAdjacentController;
+ mWindowDecorViewModel = windowDecorViewModel;
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);
@@ -288,7 +299,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mMainStageListener,
mSyncQueue,
mSurfaceSession,
- iconProvider);
+ iconProvider,
+ mWindowDecorViewModel);
mSideStage = new SideStage(
mContext,
mTaskOrganizer,
@@ -296,7 +308,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSideStageListener,
mSyncQueue,
mSurfaceSession,
- iconProvider);
+ iconProvider,
+ mWindowDecorViewModel);
mDisplayController = displayController;
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
@@ -323,7 +336,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
ShellExecutor mainExecutor,
- Optional<RecentTasksController> recentTasks) {
+ Optional<RecentTasksController> recentTasks,
+ LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
@@ -340,6 +355,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mLogger = new SplitscreenEventLogger();
mMainExecutor = mainExecutor;
mRecentTasks = recentTasks;
+ mLaunchAdjacentController = launchAdjacentController;
+ mWindowDecorViewModel = windowDecorViewModel;
mDisplayController.addDisplayWindowListener(this);
transitions.addHandler(this);
mSplitUnsupportedToast = Toast.makeText(mContext,
@@ -459,6 +476,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (isEnteringSplit && mSideStage.getChildCount() == 0) {
mMainExecutor.execute(() -> exitSplitScreen(
null /* childrenToTop */, EXIT_REASON_UNKNOWN));
+ Log.w(TAG, splitFailureMessage("startShortcut",
+ "side stage was not populated"));
mSplitUnsupportedToast.show();
}
@@ -546,6 +565,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (isEnteringSplit && mSideStage.getChildCount() == 0) {
mMainExecutor.execute(() -> exitSplitScreen(
null /* childrenToTop */, EXIT_REASON_UNKNOWN));
+ Log.w(TAG, splitFailureMessage("startIntentLegacy",
+ "side stage was not populated"));
mSplitUnsupportedToast.show();
}
@@ -718,12 +739,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mMainStage.activate(wct, false /* reparent */);
}
+ setSideStagePosition(splitPosition, wct);
mSplitLayout.setDivideRatio(splitRatio);
updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true);
setRootForceTranslucent(false, wct);
- setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
if (shortcutInfo1 != null) {
@@ -1076,6 +1097,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mMainExecutor.execute(() ->
exitSplitScreen(mMainStage.getChildCount() == 0
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+ Log.w(TAG, splitFailureMessage("onRemoteAnimationFinishedOrCancelled",
+ "main or side stage was not populated."));
mSplitUnsupportedToast.show();
} else {
mSyncQueue.queue(evictWct);
@@ -1095,6 +1118,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+ Log.w(TAG, splitFailureMessage("onRemoteAnimationFinished",
+ "main or side stage was not populated"));
mSplitUnsupportedToast.show();
return;
}
@@ -1279,20 +1304,30 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final boolean mainStageVisible = mMainStage.mRootTaskInfo.isVisible;
final boolean oneStageVisible =
mMainStage.mRootTaskInfo.isVisible != mSideStage.mRootTaskInfo.isVisible;
- if (oneStageVisible) {
+ if (oneStageVisible && !ENABLE_SHELL_TRANSITIONS) {
// Dismiss split because there's show-when-locked activity showing on top of keyguard.
// Also make sure the task contains show-when-locked activity remains on top after split
// dismissed.
- if (!ENABLE_SHELL_TRANSITIONS) {
- final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
- exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
- } else {
- final int dismissTop = mainStageVisible ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
+ exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+ }
+
+ // Dismiss split if the flag record any side of stages.
+ if (mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
+ if (ENABLE_SHELL_TRANSITIONS) {
+ // Need manually clear here due to this transition might be aborted due to keyguard
+ // on top and lead to no visible change.
+ clearSplitPairedInRecents(EXIT_REASON_DEVICE_FOLDED);
final WindowContainerTransaction wct = new WindowContainerTransaction();
- prepareExitSplitScreen(dismissTop, wct);
- mSplitTransitions.startDismissTransition(wct, this, dismissTop,
- EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+ prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
+ mSplitTransitions.startDismissTransition(wct, this,
+ mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
+ } else {
+ exitSplitScreen(
+ mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
+ EXIT_REASON_DEVICE_FOLDED);
}
+ mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
}
}
@@ -1330,15 +1365,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!mMainStage.isActive() || mIsExiting) return;
onSplitScreenExit();
+ clearSplitPairedInRecents(exitReason);
- mRecentTasks.ifPresent(recentTasks -> {
- // Notify recents if we are exiting in a way that breaks the pair, and disable further
- // updates to splits in the recents until we enter split again
- if (shouldBreakPairedTaskInRecents(exitReason) && mShouldUpdateRecents) {
- recentTasks.removeSplitPair(mMainStage.getTopVisibleChildTaskId());
- recentTasks.removeSplitPair(mSideStage.getTopVisibleChildTaskId());
- }
- });
mShouldUpdateRecents = false;
mIsDividerRemoteAnimating = false;
mSplitRequest = null;
@@ -1465,6 +1493,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
+ void clearSplitPairedInRecents(@ExitReason int exitReason) {
+ if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) return;
+
+ mRecentTasks.ifPresent(recentTasks -> {
+ // Notify recents if we are exiting in a way that breaks the pair, and disable further
+ // updates to splits in the recents until we enter split again
+ mMainStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+ mSideStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+ });
+ }
+
/**
* Unlike exitSplitScreen, this takes a stagetype vs an actual stage-reference and populates
* an existing WindowContainerTransaction (rather than applying immediately). This is intended
@@ -1547,6 +1586,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// split bounds.
wct.setSmallestScreenWidthDp(mMainStage.mRootTaskInfo.token,
SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
+ mSplitLayout.getInvisibleBounds(mTempRect1);
+ mSplitLayout.setTaskBounds(wct, mSideStage.mRootTaskInfo, mTempRect1);
}
wct.reorder(mRootTaskInfo.token, true);
setRootForceTranslucent(false, wct);
@@ -1733,12 +1774,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mRootTaskInfo == null || mRootTaskInfo.taskId != taskInfo.taskId) {
throw new IllegalArgumentException(this + "\n Unknown task info changed: " + taskInfo);
}
-
+ mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
mRootTaskInfo = taskInfo;
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
- && mMainStage.isActive()
- && !ENABLE_SHELL_TRANSITIONS) {
+ && mMainStage.isActive()) {
// Clear the divider remote animating flag as the divider will be re-rendered to apply
// the new rotation config.
mIsDividerRemoteAnimating = false;
@@ -1781,7 +1821,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.reparent(mSideStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
// Make the stages adjacent to each other so they occlude what's behind them.
wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
- wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
setRootForceTranslucent(true, wct);
mSplitLayout.getInvisibleBounds(mTempRect1);
wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
@@ -1789,6 +1828,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSyncQueue.runInSync(t -> {
t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.top);
});
+ mLaunchAdjacentController.setLaunchAdjacentRoot(mSideStage.mRootTaskInfo.token);
}
/** Callback when split roots have child task appeared under it, this is a little different from
@@ -1818,9 +1858,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void onRootTaskVanished() {
final WindowContainerTransaction wct = new WindowContainerTransaction();
- if (mRootTaskInfo != null) {
- wct.clearLaunchAdjacentFlagRoot(mRootTaskInfo.token);
- }
+ mLaunchAdjacentController.clearLaunchAdjacentRoot();
applyExitSplitScreen(null /* childrenToTop */, wct, EXIT_REASON_ROOT_TASK_VANISHED);
mDisplayInsetsController.removeInsetsChangedListener(mDisplayId, mSplitLayout);
}
@@ -2178,21 +2216,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDisplayController.addDisplayChangingController(this::onDisplayChange);
}
- @Override
- public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- if (mSplitLayout != null && mSplitLayout.isDensityChanged(newConfig.densityDpi)
- && mMainStage.isActive()
- && mSplitLayout.updateConfiguration(newConfig)
- && ENABLE_SHELL_TRANSITIONS) {
- mSplitLayout.update(null /* t */);
- onLayoutSizeChanged(mSplitLayout);
- }
- }
-
- void updateSurfaces(SurfaceControl.Transaction transaction) {
+ /**
+ * Update surfaces of the split screen layout based on the current state
+ * @param transaction to write the updates to
+ */
+ public void updateSurfaces(SurfaceControl.Transaction transaction) {
updateSurfaceBounds(mSplitLayout, transaction, /* applyResizingOffset */ false);
mSplitLayout.update(transaction);
}
@@ -2211,26 +2239,18 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@VisibleForTesting
void onFoldedStateChanged(boolean folded) {
- int topStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+ mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
if (!folded) return;
- if (!mMainStage.isActive()) return;
+ if (!isSplitActive() || !isSplitScreenVisible()) return;
+ // To avoid split dismiss when user fold the device and unfold to use later, we only
+ // record the flag here and try to dismiss on wakeUp callback to ensure split dismiss
+ // when user interact on phone folded.
if (mMainStage.isFocused()) {
- topStageAfterFoldDismiss = STAGE_TYPE_MAIN;
+ mTopStageAfterFoldDismiss = STAGE_TYPE_MAIN;
} else if (mSideStage.isFocused()) {
- topStageAfterFoldDismiss = STAGE_TYPE_SIDE;
- }
-
- if (ENABLE_SHELL_TRANSITIONS) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- prepareExitSplitScreen(topStageAfterFoldDismiss, wct);
- mSplitTransitions.startDismissTransition(wct, this,
- topStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
- } else {
- exitSplitScreen(
- topStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
- EXIT_REASON_DEVICE_FOLDED);
+ mTopStageAfterFoldDismiss = STAGE_TYPE_SIDE;
}
}
@@ -2364,6 +2384,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// so appends operations to exit split.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
}
+ } else if (type == TRANSIT_KEYGUARD_OCCLUDE && triggerTask.topActivity != null
+ && isSplitScreenVisible()) {
+ // Split include show when lock activity case, check the top activity under which
+ // stage and move it to the top.
+ int top = triggerTask.topActivity.equals(mMainStage.mRootTaskInfo.topActivity)
+ ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ prepareExitSplitScreen(top, out);
+ mSplitTransitions.setDismissTransition(transition, top,
+ EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
// When split in the background, it should be only opening/dismissing transition and
@@ -2519,6 +2548,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// so don't handle it.
Log.e(TAG, "Somehow removed the last task in a stage outside of a proper "
+ "transition.");
+ // This new transition would be merged to current one so we need to clear
+ // tile manually here.
+ clearSplitPairedInRecents(EXIT_REASON_APP_FINISHED);
final WindowContainerTransaction wct = new WindowContainerTransaction();
final int dismissTop = (dismissStages.size() == 1
&& getStageType(dismissStages.valueAt(0)) == STAGE_TYPE_MAIN)
@@ -2688,19 +2720,27 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
== TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
// Open to side should only be used when split already active and foregorund.
if (mainChild == null && sideChild == null) {
- Log.w(TAG, "Launched a task in split, but didn't receive any task in transition.");
+ Log.w(TAG, splitFailureMessage("startPendingEnterAnimation",
+ "Launched a task in split, but didn't receive any task in transition."));
// This should happen when the target app is already on front, so just cancel.
mSplitTransitions.mPendingEnter.cancel(null);
return true;
}
} else {
if (mainChild == null || sideChild == null) {
- Log.w(TAG, "Launched 2 tasks in split, but didn't receive"
- + " 2 tasks in transition. Possibly one of them failed to launch");
final int dismissTop = mainChild != null ? STAGE_TYPE_MAIN :
(sideChild != null ? STAGE_TYPE_SIDE : STAGE_TYPE_UNDEFINED);
mSplitTransitions.mPendingEnter.cancel(
(cancelWct, cancelT) -> prepareExitSplitScreen(dismissTop, cancelWct));
+ Log.w(TAG, splitFailureMessage("startPendingEnterAnimation",
+ "launched 2 tasks in split, but didn't receive "
+ + "2 tasks in transition. Possibly one of them failed to launch"));
+ if (mRecentTasks.isPresent() && mainChild != null) {
+ mRecentTasks.get().removeSplitPair(mainChild.getTaskInfo().taskId);
+ }
+ if (mRecentTasks.isPresent() && sideChild != null) {
+ mRecentTasks.get().removeSplitPair(sideChild.getTaskInfo().taskId);
+ }
mSplitUnsupportedToast.show();
return true;
}
@@ -3158,7 +3198,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onNoLongerSupportMultiWindow() {
+ public void onNoLongerSupportMultiWindow(ActivityManager.RunningTaskInfo taskInfo) {
if (mMainStage.isActive()) {
final boolean isMainStage = mMainStageListener == this;
if (!ENABLE_SHELL_TRANSITIONS) {
@@ -3173,6 +3213,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
prepareExitSplitScreen(stageType, wct);
mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
+ Log.w(TAG, splitFailureMessage("onNoLongerSupportMultiWindow",
+ "app package " + taskInfo.baseActivity.getPackageName()
+ + " does not support splitscreen, or is a controlled activity type"));
mSplitUnsupportedToast.show();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index a01eddbc9b9f..af7bf360f036 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -51,8 +51,11 @@ import com.android.wm.shell.common.SurfaceUtils;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.io.PrintWriter;
+import java.util.Optional;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -79,7 +82,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
void onRootTaskVanished();
- void onNoLongerSupportMultiWindow();
+ void onNoLongerSupportMultiWindow(ActivityManager.RunningTaskInfo taskInfo);
}
private final Context mContext;
@@ -87,6 +90,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
private final SurfaceSession mSurfaceSession;
private final SyncTransactionQueue mSyncQueue;
private final IconProvider mIconProvider;
+ private final Optional<WindowDecorViewModel> mWindowDecorViewModel;
protected ActivityManager.RunningTaskInfo mRootTaskInfo;
protected SurfaceControl mRootLeash;
@@ -98,12 +102,14 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
StageTaskListener(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession, IconProvider iconProvider) {
+ SurfaceSession surfaceSession, IconProvider iconProvider,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
mContext = context;
mCallbacks = callbacks;
mSyncQueue = syncQueue;
mSurfaceSession = surfaceSession;
mIconProvider = iconProvider;
+ mWindowDecorViewModel = windowDecorViewModel;
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
}
@@ -202,6 +208,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
@CallSuper
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
if (mRootTaskInfo.taskId == taskInfo.taskId) {
// Inflates split decor view only when the root task is visible.
if (!ENABLE_SHELL_TRANSITIONS && mRootTaskInfo.isVisible != taskInfo.isVisible) {
@@ -220,7 +227,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
taskInfo.getWindowingMode())) {
// Leave split screen if the task no longer supports multi window or have
// uncontrolled task.
- mCallbacks.onNoLongerSupportMultiWindow();
+ mCallbacks.onNoLongerSupportMultiWindow(taskInfo);
return;
}
mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
@@ -341,6 +348,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */);
}
+ void doForAllChildTasks(Consumer<Integer> consumer) {
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
+ final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
+ consumer.accept(taskInfo.taskId);
+ }
+ }
+
/** Collects all the current child tasks and prepares transaction to evict them to display. */
void evictAllChildren(WindowContainerTransaction wct) {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
index 27d520d81c41..a2301b133426 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
@@ -27,6 +27,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
@@ -58,6 +59,7 @@ public class TvSplitScreenController extends SplitScreenController {
private final TransactionPool mTransactionPool;
private final IconProvider mIconProvider;
private final Optional<RecentTasksController> mRecentTasksOptional;
+ private final LaunchAdjacentController mLaunchAdjacentController;
private final Handler mMainHandler;
private final SystemWindows mSystemWindows;
@@ -77,13 +79,15 @@ public class TvSplitScreenController extends SplitScreenController {
TransactionPool transactionPool,
IconProvider iconProvider,
Optional<RecentTasksController> recentTasks,
+ LaunchAdjacentController launchAdjacentController,
ShellExecutor mainExecutor,
Handler mainHandler,
SystemWindows systemWindows) {
super(context, shellInit, shellCommandHandler, shellController, shellTaskOrganizer,
syncQueue, rootTDAOrganizer, displayController, displayImeController,
displayInsetsController, dragAndDropController, transitions, transactionPool,
- iconProvider, recentTasks, mainExecutor);
+ iconProvider, recentTasks, launchAdjacentController, Optional.empty(),
+ mainExecutor);
mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
@@ -96,6 +100,7 @@ public class TvSplitScreenController extends SplitScreenController {
mTransactionPool = transactionPool;
mIconProvider = iconProvider;
mRecentTasksOptional = recentTasks;
+ mLaunchAdjacentController = launchAdjacentController;
mMainHandler = mainHandler;
mSystemWindows = systemWindows;
@@ -111,7 +116,7 @@ public class TvSplitScreenController extends SplitScreenController {
mTaskOrganizer, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mTransitions, mTransactionPool,
mIconProvider, mMainExecutor, mMainHandler,
- mRecentTasksOptional, mSystemWindows);
+ mRecentTasksOptional, mLaunchAdjacentController, mSystemWindows);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
index 4d563fbb7f04..79476919221e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
@@ -24,6 +24,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
@@ -51,10 +52,11 @@ public class TvStageCoordinator extends StageCoordinator
IconProvider iconProvider, ShellExecutor mainExecutor,
Handler mainHandler,
Optional<RecentTasksController> recentTasks,
+ LaunchAdjacentController launchAdjacentController,
SystemWindows systemWindows) {
super(context, displayId, syncQueue, taskOrganizer, displayController, displayImeController,
displayInsetsController, transitions, transactionPool, iconProvider,
- mainExecutor, recentTasks);
+ mainExecutor, recentTasks, launchAdjacentController, Optional.empty());
mTvSplitMenuController = new TvSplitMenuController(context, this,
systemWindows, mainHandler);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index dc91a11dc64f..84dcd4db7bb2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -112,28 +112,15 @@ public class SplashscreenContentDrawer {
*/
static final long MAX_ANIMATION_DURATION = MINIMAL_ANIMATION_DURATION + TIME_WINDOW_DURATION;
- // The acceptable area ratio of foreground_icon_area/background_icon_area, if there is an
- // icon which it's non-transparent foreground area is similar to it's background area, then
- // do not enlarge the foreground drawable.
- // For example, an icon with the foreground 108*108 opaque pixels and it's background
- // also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon.
- private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f);
-
- /**
- * If the developer doesn't specify a background for the icon, we slightly scale it up.
- *
- * The background is either manually specified in the theme or the Adaptive Icon
- * background is used if it's different from the window background.
- */
- private static final float NO_BACKGROUND_SCALE = 192f / 160;
private final Context mContext;
private final HighResIconProvider mHighResIconProvider;
-
private int mIconSize;
private int mDefaultIconSize;
private int mBrandingImageWidth;
private int mBrandingImageHeight;
private int mMainWindowShiftLength;
+ private float mEnlargeForegroundIconThreshold;
+ private float mNoBackgroundScale;
private int mLastPackageContextConfigHash;
private final TransactionPool mTransactionPool;
private final SplashScreenWindowAttrs mTmpAttrs = new SplashScreenWindowAttrs();
@@ -336,6 +323,10 @@ public class SplashscreenContentDrawer {
com.android.wm.shell.R.dimen.starting_surface_brand_image_height);
mMainWindowShiftLength = mContext.getResources().getDimensionPixelSize(
com.android.wm.shell.R.dimen.starting_surface_exit_animation_window_shift_length);
+ mEnlargeForegroundIconThreshold = mContext.getResources().getFloat(
+ com.android.wm.shell.R.dimen.splash_icon_enlarge_foreground_threshold);
+ mNoBackgroundScale = mContext.getResources().getFloat(
+ com.android.wm.shell.R.dimen.splash_icon_no_background_scale_factor);
}
/**
@@ -604,14 +595,14 @@ public class SplashscreenContentDrawer {
// There is no background below the icon, so scale the icon up
if (mTmpAttrs.mIconBgColor == Color.TRANSPARENT
|| mTmpAttrs.mIconBgColor == mThemeColor) {
- mFinalIconSize *= NO_BACKGROUND_SCALE;
+ mFinalIconSize *= mNoBackgroundScale;
}
createIconDrawable(iconDrawable, false /* legacy */, false /* loadInDetail */);
} else {
final float iconScale = (float) mIconSize / (float) mDefaultIconSize;
final int densityDpi = mContext.getResources().getConfiguration().densityDpi;
final int scaledIconDpi =
- (int) (0.5f + iconScale * densityDpi * NO_BACKGROUND_SCALE);
+ (int) (0.5f + iconScale * densityDpi * mNoBackgroundScale);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "getIcon");
iconDrawable = mHighResIconProvider.getIcon(
mActivityInfo, densityDpi, scaledIconDpi);
@@ -693,8 +684,8 @@ public class SplashscreenContentDrawer {
// Reference AdaptiveIcon description, outer is 108 and inner is 72, so we
// scale by 192/160 if we only draw adaptiveIcon's foreground.
final float noBgScale =
- iconColor.mFgNonTranslucentRatio < ENLARGE_FOREGROUND_ICON_THRESHOLD
- ? NO_BACKGROUND_SCALE : 1f;
+ iconColor.mFgNonTranslucentRatio < mEnlargeForegroundIconThreshold
+ ? mNoBackgroundScale : 1f;
// Using AdaptiveIconDrawable here can help keep the shape consistent with the
// current settings.
mFinalIconSize = (int) (0.5f + mIconSize * noBgScale);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
index 5f54f58557d1..56c0d0e67cab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
@@ -38,8 +38,6 @@ public class ShellSharedConstants {
public static final String KEY_EXTRA_SHELL_RECENT_TASKS = "extra_shell_recent_tasks";
// See IBackAnimation.aidl
public static final String KEY_EXTRA_SHELL_BACK_ANIMATION = "extra_shell_back_animation";
- // See IFloatingTasks.aidl
- public static final String KEY_EXTRA_SHELL_FLOATING_TASKS = "extra_shell_floating_tasks";
// See IDesktopMode.aidl
public static final String KEY_EXTRA_SHELL_DESKTOP_MODE = "extra_shell_desktop_mode";
// See IDragAndDrop.aidl
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java
index 4faa92979733..0d77a2e4610c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.view.SurfaceControl;
@@ -69,8 +70,10 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
private final Rect mTmpRect = new Rect();
private final Rect mTmpRootRect = new Rect();
private final int[] mTmpLocation = new int[2];
+ private final Rect mBoundsOnScreen = new Rect();
private final TaskViewTaskController mTaskViewTaskController;
private Region mObscuredTouchRegion;
+ private Insets mCaptionInsets;
public TaskView(Context context, TaskViewTaskController taskViewTaskController) {
super(context, null, 0, 0, true /* disableBackgroundLayer */);
@@ -169,6 +172,25 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
}
/**
+ * Sets a region of the task to inset to allow for a caption bar. Currently only top insets
+ * are supported.
+ * <p>
+ * This region will be factored in as an area of taskview that is not touchable activity
+ * content (i.e. you don't need to additionally set {@link #setObscuredTouchRect(Rect)} for
+ * the caption area).
+ *
+ * @param captionInsets the insets to apply to task view.
+ */
+ public void setCaptionInsets(Insets captionInsets) {
+ mCaptionInsets = captionInsets;
+ if (captionInsets == null) {
+ // If captions are null we can set them now; otherwise they'll get set in
+ // onComputeInternalInsets.
+ mTaskViewTaskController.setCaptionInsets(null);
+ }
+ }
+
+ /**
* Call when view position or size has changed. Do not call when animating.
*/
public void onLocationChanged() {
@@ -230,6 +252,15 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
getLocationInWindow(mTmpLocation);
mTmpRect.set(mTmpLocation[0], mTmpLocation[1],
mTmpLocation[0] + getWidth(), mTmpLocation[1] + getHeight());
+ if (mCaptionInsets != null) {
+ mTmpRect.inset(mCaptionInsets);
+ getBoundsOnScreen(mBoundsOnScreen);
+ mTaskViewTaskController.setCaptionInsets(new Rect(
+ mBoundsOnScreen.left,
+ mBoundsOnScreen.top,
+ mBoundsOnScreen.right + getWidth(),
+ mBoundsOnScreen.top + mCaptionInsets.top));
+ }
inoutInfo.touchableRegion.op(mTmpRect, Region.Op.DIFFERENCE);
if (mObscuredTouchRegion != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
index 163cf501734c..adae21b20b3c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
@@ -33,6 +33,7 @@ import android.os.Binder;
import android.util.CloseGuard;
import android.util.Slog;
import android.view.SurfaceControl;
+import android.view.WindowInsets;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -82,6 +83,10 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
private TaskView.Listener mListener;
private Executor mListenerExecutor;
+ /** Used to inset the activity content to allow space for a caption bar. */
+ private final Binder mCaptionInsetsOwner = new Binder();
+ private Rect mCaptionInsets;
+
public TaskViewTaskController(Context context, ShellTaskOrganizer organizer,
TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) {
mContext = context;
@@ -89,9 +94,11 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
mShellExecutor = organizer.getExecutor();
mSyncQueue = syncQueue;
mTaskViewTransitions = taskViewTransitions;
- if (mTaskViewTransitions != null) {
- mTaskViewTransitions.addTaskView(this);
- }
+ mShellExecutor.execute(() -> {
+ if (mTaskViewTransitions != null) {
+ mTaskViewTransitions.addTaskView(this);
+ }
+ });
mGuard.open("release");
}
@@ -220,10 +227,10 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
}
private void performRelease() {
- if (mTaskViewTransitions != null) {
- mTaskViewTransitions.removeTaskView(this);
- }
mShellExecutor.execute(() -> {
+ if (mTaskViewTransitions != null) {
+ mTaskViewTransitions.removeTaskView(this);
+ }
mTaskOrganizer.removeListener(this);
resetTaskInfo();
});
@@ -312,18 +319,12 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
// we know about -- so leave clean-up here even if shell transitions are enabled.
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
- if (mListener != null) {
- final int taskId = taskInfo.taskId;
- mListenerExecutor.execute(() -> {
- mListener.onTaskRemovalStarted(taskId);
- });
- }
- mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);
+ final SurfaceControl taskLeash = mTaskLeash;
+ handleAndNotifyTaskRemoval(mTaskInfo);
// Unparent the task when this surface is destroyed
- mTransaction.reparent(mTaskLeash, null).apply();
+ mTransaction.reparent(taskLeash, null).apply();
resetTaskInfo();
- mTaskViewBase.onTaskVanished(taskInfo);
}
@Override
@@ -411,9 +412,12 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
if (mTaskToken == null) {
return;
}
- // Sync Transactions can't operate simultaneously with shell transition collection.
+
if (isUsingShellTransitions()) {
- mTaskViewTransitions.setTaskBounds(this, boundsOnScreen);
+ mShellExecutor.execute(() -> {
+ // Sync Transactions can't operate simultaneously with shell transition collection.
+ mTaskViewTransitions.setTaskBounds(this, boundsOnScreen);
+ });
return;
}
@@ -431,9 +435,37 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
Slog.w(TAG, "Trying to remove a task that was never added? (no taskToken)");
return;
}
+ mShellExecutor.execute(() -> {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.removeTask(mTaskToken);
+ mTaskViewTransitions.closeTaskView(wct, this);
+ });
+ }
+
+ /**
+ * Sets a region of the task to inset to allow for a caption bar.
+ *
+ * @param captionInsets the rect for the insets in screen coordinates.
+ */
+ void setCaptionInsets(Rect captionInsets) {
+ if (mCaptionInsets != null && mCaptionInsets.equals(captionInsets)) {
+ return;
+ }
+ mCaptionInsets = captionInsets;
+ applyCaptionInsetsIfNeeded();
+ }
+
+ void applyCaptionInsetsIfNeeded() {
+ if (mTaskToken == null) return;
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.removeTask(mTaskToken);
- mTaskViewTransitions.closeTaskView(wct, this);
+ if (mCaptionInsets != null) {
+ wct.addInsetsSource(mTaskToken, mCaptionInsetsOwner, 0,
+ WindowInsets.Type.captionBar(), mCaptionInsets);
+ } else {
+ wct.removeInsetsSource(mTaskToken, mCaptionInsetsOwner, 0,
+ WindowInsets.Type.captionBar());
+ }
+ mTaskOrganizer.applyTransaction(wct);
}
/** Should be called when the client surface is destroyed. */
@@ -467,6 +499,20 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
}
}
+ /** Notifies listeners of a task being removed and stops intercepting back presses on it. */
+ private void handleAndNotifyTaskRemoval(ActivityManager.RunningTaskInfo taskInfo) {
+ if (taskInfo != null) {
+ if (mListener != null) {
+ final int taskId = taskInfo.taskId;
+ mListenerExecutor.execute(() -> {
+ mListener.onTaskRemovalStarted(taskId);
+ });
+ }
+ mTaskViewBase.onTaskVanished(taskInfo);
+ mTaskOrganizer.setInterceptBackPressedOnTaskRoot(taskInfo.token, false);
+ }
+ }
+
/** Returns the task info for the task in the TaskView. */
@Nullable
public ActivityManager.RunningTaskInfo getTaskInfo() {
@@ -492,18 +538,12 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
*/
void cleanUpPendingTask() {
if (mPendingInfo != null) {
- if (mListener != null) {
- final int taskId = mPendingInfo.taskId;
- mListenerExecutor.execute(() -> {
- mListener.onTaskRemovalStarted(taskId);
- });
- }
- mTaskViewBase.onTaskVanished(mPendingInfo);
- mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mPendingInfo.token, false);
+ final ActivityManager.RunningTaskInfo pendingInfo = mPendingInfo;
+ handleAndNotifyTaskRemoval(pendingInfo);
// Make sure the task is removed
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.removeTask(mPendingInfo.token);
+ wct.removeTask(pendingInfo.token);
mTaskViewTransitions.closeTaskView(wct, this);
}
resetTaskInfo();
@@ -528,16 +568,7 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
* is used instead.
*/
void prepareCloseAnimation() {
- if (mTaskToken != null) {
- if (mListener != null) {
- final int taskId = mTaskInfo.taskId;
- mListenerExecutor.execute(() -> {
- mListener.onTaskRemovalStarted(taskId);
- });
- }
- mTaskViewBase.onTaskVanished(mTaskInfo);
- mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);
- }
+ handleAndNotifyTaskRemoval(mTaskInfo);
resetTaskInfo();
}
@@ -564,6 +595,7 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
mTaskViewTransitions.updateBoundsState(this, boundsOnScreen);
mTaskViewTransitions.updateVisibilityState(this, true /* visible */);
wct.setBounds(mTaskToken, boundsOnScreen);
+ applyCaptionInsetsIfNeeded();
} else {
// The surface has already been destroyed before the task has appeared,
// so go ahead and hide the task entirely
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index 5baf2e320227..e03f82526bdb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -165,19 +165,6 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
return null;
}
- /**
- * Returns all the pending transitions for a given `taskView`.
- * @param taskView the pending transition should be for this.
- */
- ArrayList<PendingTransition> findAllPending(TaskViewTaskController taskView) {
- ArrayList<PendingTransition> list = new ArrayList<>();
- for (int i = mPending.size() - 1; i >= 0; --i) {
- if (mPending.get(i).mTaskView != taskView) continue;
- list.add(mPending.get(i));
- }
- return list;
- }
-
private PendingTransition findPending(IBinder claimed) {
for (int i = 0; i < mPending.size(); ++i) {
if (mPending.get(i).mClaimed != claimed) continue;
@@ -202,15 +189,10 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
if (taskView == null) return null;
// Opening types should all be initiated by shell
if (!TransitionUtil.isClosingType(request.getType())) return null;
- PendingTransition pending = findPendingCloseTransition(taskView);
- if (pending == null) {
- pending = new PendingTransition(request.getType(), null, taskView, null /* cookie */);
- }
- if (pending.mClaimed != null) {
- throw new IllegalStateException("Task is closing in 2 collecting transitions?"
- + " This state doesn't make sense");
- }
+ PendingTransition pending = new PendingTransition(request.getType(), null,
+ taskView, null /* cookie */);
pending.mClaimed = transition;
+ mPending.add(pending);
return new WindowContainerTransaction();
}
@@ -278,10 +260,9 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
// Task view isn't visible, the bounds will next visibility update.
return;
}
- PendingTransition pendingOpen = findPendingOpeningTransition(taskView);
- if (pendingOpen != null) {
- // There is already an opening transition in-flight, the window bounds will be
- // set in prepareOpenAnimation (via the window crop) if needed.
+ if (hasPending()) {
+ // There is already a transition in-flight, the window bounds will be set in
+ // prepareOpenAnimation.
return;
}
WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -409,7 +390,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
}
// No animation, just show it immediately.
startTransaction.apply();
- finishCallback.onTransitionFinished(wct, null /* wctCB */);
+ finishCallback.onTransitionFinished(wct);
startNextTransition();
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index d0a361a8ecd2..986560bd6053 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -40,13 +40,14 @@ import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.split.SplitScreenUtils;
+import com.android.wm.shell.desktopmode.DesktopModeController;
+import com.android.wm.shell.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentsTransitionHandler;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -70,6 +71,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
private RecentsTransitionHandler mRecentsHandler;
private StageCoordinator mSplitHandler;
private final KeyguardTransitionHandler mKeyguardHandler;
+ private DesktopModeController mDesktopModeController;
+ private DesktopTasksController mDesktopTasksController;
private UnfoldTransitionHandler mUnfoldHandler;
private static class MixedTransition {
@@ -87,8 +90,11 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
/** Keyguard exit/occlude/unocclude transition. */
static final int TYPE_KEYGUARD = 5;
+ /** Recents Transition while in desktop mode. */
+ static final int TYPE_RECENTS_DURING_DESKTOP = 6;
+
/** Fuld/Unfold transition. */
- static final int TYPE_UNFOLD = 6;
+ static final int TYPE_UNFOLD = 7;
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -117,14 +123,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
mTransition = transition;
}
- void joinFinishArgs(WindowContainerTransaction wct,
- WindowContainerTransactionCallback wctCB) {
- if (wctCB != null) {
- // Technically can probably support 1, but don't want to encourage CB usage since
- // it creates instabliity, so just throw.
- throw new IllegalArgumentException("Can't mix transitions that require finish"
- + " sync callback");
- }
+ void joinFinishArgs(WindowContainerTransaction wct) {
if (wct != null) {
if (mFinishWCT == null) {
mFinishWCT = wct;
@@ -139,17 +138,20 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
public DefaultMixedHandler(@NonNull ShellInit shellInit, @NonNull Transitions player,
Optional<SplitScreenController> splitScreenControllerOptional,
- Optional<PipTouchHandler> pipTouchHandlerOptional,
+ @Nullable PipTransitionController pipTransitionController,
Optional<RecentsTransitionHandler> recentsHandlerOptional,
KeyguardTransitionHandler keyguardHandler,
+ Optional<DesktopModeController> desktopModeControllerOptional,
+ Optional<DesktopTasksController> desktopTasksControllerOptional,
Optional<UnfoldTransitionHandler> unfoldHandler) {
mPlayer = player;
mKeyguardHandler = keyguardHandler;
- if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent()
+ if (Transitions.ENABLE_SHELL_TRANSITIONS
+ && pipTransitionController != null
&& splitScreenControllerOptional.isPresent()) {
// Add after dependencies because it is higher priority
shellInit.addInitCallback(() -> {
- mPipHandler = pipTouchHandlerOptional.get().getTransitionHandler();
+ mPipHandler = pipTransitionController;
mSplitHandler = splitScreenControllerOptional.get().getTransitionHandler();
mPlayer.addHandler(this);
if (mSplitHandler != null) {
@@ -159,6 +161,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
if (mRecentsHandler != null) {
mRecentsHandler.addMixer(this);
}
+ mDesktopModeController = desktopModeControllerOptional.orElse(null);
+ mDesktopTasksController = desktopTasksControllerOptional.orElse(null);
mUnfoldHandler = unfoldHandler.orElse(null);
}, this);
}
@@ -239,7 +243,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@Override
public Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT) {
- if (mRecentsHandler != null && mSplitHandler.isSplitScreenVisible()) {
+ if (mRecentsHandler != null && (mSplitHandler.isSplitScreenVisible()
+ || DesktopModeStatus.isActive(mPlayer.getContext()))) {
return this;
}
return null;
@@ -254,6 +259,13 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
mixed.mLeftoversHandler = mRecentsHandler;
mActiveTransitions.add(mixed);
+ } else if (DesktopModeStatus.isActive(mPlayer.getContext())) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
+ + "desktop mode is active, so treat it as Mixed.");
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition);
+ mixed.mLeftoversHandler = mRecentsHandler;
+ mActiveTransitions.add(mixed);
} else {
throw new IllegalStateException("Accepted a recents transition but don't know how to"
+ " handle it");
@@ -340,6 +352,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
return animateKeyguard(mixed, info, startTransaction, finishTransaction,
finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
+ return animateRecentsDuringDesktop(mixed, info, startTransaction, finishTransaction,
+ finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
return animateUnfold(mixed, info, startTransaction, finishTransaction, finishCallback);
} else {
@@ -366,12 +381,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
info.getChanges().remove(i);
}
}
- Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ Transitions.TransitionFinishCallback finishCB = (wct) -> {
--mixed.mInFlightSubAnimations;
- mixed.joinFinishArgs(wct, wctCB);
+ mixed.joinFinishArgs(wct);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
+ finishCallback.onTransitionFinished(mixed.mFinishWCT);
};
if (pipChange == null) {
if (mixed.mLeftoversHandler != null) {
@@ -438,15 +453,15 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
return false;
}
final boolean isGoingHome = homeIsOpening;
- Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ Transitions.TransitionFinishCallback finishCB = (wct) -> {
--mixed.mInFlightSubAnimations;
- mixed.joinFinishArgs(wct, wctCB);
+ mixed.joinFinishArgs(wct);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
if (isGoingHome) {
mSplitHandler.onTransitionAnimationComplete();
}
- finishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
+ finishCallback.onTransitionFinished(mixed.mFinishWCT);
};
if (isGoingHome || mSplitHandler.getSplitItemPosition(pipChange.getLastParent())
!= SPLIT_POSITION_UNDEFINED) {
@@ -563,12 +578,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
// We need to split the transition into 2 parts: the split part and the display part.
mixed.mInFlightSubAnimations = 2;
- Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ Transitions.TransitionFinishCallback finishCB = (wct) -> {
--mixed.mInFlightSubAnimations;
- mixed.joinFinishArgs(wct, wctCB);
+ mixed.joinFinishArgs(wct);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(mixed.mFinishWCT, null /* wctCB */);
+ finishCallback.onTransitionFinished(mixed.mFinishWCT);
};
// Dispatch the display change. This will most-likely be taken by the default handler.
@@ -591,7 +606,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
// Split-screen is only interested in the recents transition finishing (and merging), so
// just wrap finish and start recents animation directly.
- Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ Transitions.TransitionFinishCallback finishCB = (wct) -> {
mixed.mInFlightSubAnimations = 0;
mActiveTransitions.remove(mixed);
// If pair-to-pair switching, the post-recents clean-up isn't needed.
@@ -603,7 +618,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
mSplitHandler.onRecentsPairToPairAnimationFinish(wct);
}
mSplitHandler.onTransitionAnimationComplete();
- finishCallback.onTransitionFinished(wct, wctCB);
+ finishCallback.onTransitionFinished(wct);
};
mixed.mInFlightSubAnimations = 1;
mSplitHandler.onRecentsInSplitAnimationStart(info);
@@ -621,11 +636,11 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- final Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ final Transitions.TransitionFinishCallback finishCB = (wct) -> {
mixed.mInFlightSubAnimations--;
if (mixed.mInFlightSubAnimations == 0) {
mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(wct, wctCB);
+ finishCallback.onTransitionFinished(wct);
}
};
mixed.mInFlightSubAnimations++;
@@ -641,22 +656,49 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
return true;
}
+ private boolean animateRecentsDuringDesktop(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ boolean consumed = mRecentsHandler.startAnimation(
+ mixed.mTransition, info, startTransaction, finishTransaction, finishCallback);
+ if (!consumed) {
+ return false;
+ }
+ //Sync desktop mode state (proto 1)
+ if (mDesktopModeController != null) {
+ mDesktopModeController.syncSurfaceState(info, finishTransaction);
+ return true;
+ }
+ //Sync desktop mode state (proto 2)
+ if (mDesktopTasksController != null) {
+ mDesktopTasksController.syncSurfaceState(info, finishTransaction);
+ return true;
+ }
+
+ return false;
+ }
+
private boolean animateUnfold(@NonNull final MixedTransition mixed,
@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- final Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ final Transitions.TransitionFinishCallback finishCB = (wct) -> {
mixed.mInFlightSubAnimations--;
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(wct, wctCB);
+ finishCallback.onTransitionFinished(wct);
};
mixed.mInFlightSubAnimations = 1;
// Sync pip state.
if (mPipHandler != null) {
mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction);
}
+ if (mSplitHandler != null && mSplitHandler.isSplitActive()) {
+ mSplitHandler.updateSurfaces(startTransaction);
+ }
return mUnfoldHandler.startAnimation(
mixed.mTransition, info, startTransaction, finishTransaction, finishCB);
}
@@ -727,6 +769,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
mKeyguardHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
+ mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
+ finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
mUnfoldHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
} else {
@@ -754,6 +799,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
+ mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
} else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
mUnfoldHandler.onTransitionConsumed(transition, aborted, finishT);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index e52fd00e7df7..7df658e6c9db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -300,7 +300,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
// immediately finishes since there is no animation for screen-wake.
if (info.getType() == WindowManager.TRANSIT_WAKE && !info.isKeyguardGoingAway()) {
startTransaction.apply();
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
return true;
}
@@ -309,7 +309,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|| (info.getFlags() & WindowManager.TRANSIT_FLAG_INVISIBLE) != 0) {
startTransaction.apply();
finishTransaction.apply();
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
return true;
}
@@ -323,7 +323,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
final Runnable onAnimFinish = () -> {
if (!animations.isEmpty()) return;
mAnimations.remove(transition);
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
};
final List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks =
@@ -407,7 +407,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
change.getEndAbsBounds().width(), change.getEndAbsBounds().height());
}
// Rotation change of independent non display window container.
- if (change.getParent() == null
+ if (change.getParent() == null && !change.hasFlags(FLAG_IS_DISPLAY)
&& change.getStartRotation() != change.getEndRotation()) {
startRotationAnimation(startTransaction, change, info,
ROTATION_ANIMATION_ROTATE, animations, onAnimFinish);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 4e3d220f1ea2..fab2dd2bf3e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -68,7 +68,7 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
final IBinder.DeathRecipient remoteDied = () -> {
Log.e(Transitions.TAG, "Remote transition died, finishing");
mMainExecutor.execute(
- () -> finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */));
+ () -> finishCallback.onTransitionFinished(null /* wct */));
};
IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
@Override
@@ -81,7 +81,7 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
finishTransaction.merge(sct);
}
mMainExecutor.execute(() -> {
- finishCallback.onTransitionFinished(wct, null /* wctCB */);
+ finishCallback.onTransitionFinished(wct);
});
}
};
@@ -104,7 +104,7 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
if (mRemote.asBinder() != null) {
mRemote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
}
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
}
return true;
}
@@ -122,8 +122,7 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
// remote applied the transaction, but applying twice will break surfaceflinger
// so just assume the worst-case and clear the local transaction.
t.clear();
- mMainExecutor.execute(
- () -> finishCallback.onTransitionFinished(wct, null /* wctCB */));
+ mMainExecutor.execute(() -> finishCallback.onTransitionFinished(wct));
}
};
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index a242c72db8b3..bbf67a6155d7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -133,7 +133,7 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
}
mMainExecutor.execute(() -> {
mRequestedRemotes.remove(transition);
- finishCallback.onTransitionFinished(wct, null /* wctCB */);
+ finishCallback.onTransitionFinished(wct);
});
}
};
@@ -153,8 +153,7 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
Log.e(Transitions.TAG, "Error running remote transition.", e);
unhandleDeath(remote.asBinder(), finishCallback);
mRequestedRemotes.remove(transition);
- mMainExecutor.execute(
- () -> finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */));
+ mMainExecutor.execute(() -> finishCallback.onTransitionFinished(null /* wct */));
}
return true;
}
@@ -186,9 +185,12 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
final RemoteTransition remoteTransition = mRequestedRemotes.get(mergeTarget);
- final IRemoteTransition remote = remoteTransition.getRemoteTransition();
+ if (remoteTransition == null) return;
+
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Merge into remote: %s",
remoteTransition);
+
+ final IRemoteTransition remote = remoteTransition.getRemoteTransition();
if (remote == null) return;
IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
@@ -207,7 +209,7 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
+ "that the mergeTarget's RemoteTransition impl erroneously "
+ "accepted/ran the merge request after finishing the mergeTarget");
}
- finishCallback.onTransitionFinished(wct, null /* wctCB */);
+ finishCallback.onTransitionFinished(wct);
});
}
};
@@ -313,8 +315,7 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
}
}
for (int i = mPendingFinishCallbacks.size() - 1; i >= 0; --i) {
- mPendingFinishCallbacks.get(i).onTransitionFinished(
- null /* wct */, null /* wctCB */);
+ mPendingFinishCallbacks.get(i).onTransitionFinished(null /* wct */);
}
mPendingFinishCallbacks.clear();
});
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java
index d2795959494a..87c438a5b37d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java
@@ -43,7 +43,7 @@ class SleepHandler implements Transitions.TransitionHandler {
@NonNull Transitions.TransitionFinishCallback finishCallback) {
mSleepTransitions.remove(transition);
startTransaction.apply();
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index d978eafa97f3..d07d2b7b6db9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -346,7 +346,7 @@ public class TransitionAnimationHelper {
.setFrameScale(1)
.setPixelFormat(PixelFormat.RGBA_8888)
.setChildrenOnly(true)
- .setAllowProtected(true)
+ .setAllowProtected(false)
.setCaptureSecureLayers(true)
.build();
final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 2327d86ab618..b4d0a31dc8c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -27,6 +27,7 @@ import static android.view.WindowManager.TRANSIT_SLEEP;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.fixScale;
+import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
@@ -61,7 +62,6 @@ import android.window.TransitionInfo;
import android.window.TransitionMetrics;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
import androidx.annotation.BinderThread;
@@ -148,19 +148,28 @@ public class Transitions implements RemoteCallable<Transitions>,
/** Transition type for maximize to freeform transition. */
public static final int TRANSIT_RESTORE_FROM_MAXIMIZE = WindowManager.TRANSIT_FIRST_CUSTOM + 9;
- /** Transition type to freeform in desktop mode. */
- public static final int TRANSIT_ENTER_FREEFORM = WindowManager.TRANSIT_FIRST_CUSTOM + 10;
+ /** Transition type for starting the move to desktop mode. */
+ public static final int TRANSIT_START_DRAG_TO_DESKTOP_MODE =
+ WindowManager.TRANSIT_FIRST_CUSTOM + 10;
- /** Transition type to freeform in desktop mode. */
- public static final int TRANSIT_ENTER_DESKTOP_MODE = WindowManager.TRANSIT_FIRST_CUSTOM + 11;
+ /** Transition type for finalizing the move to desktop mode. */
+ public static final int TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE =
+ WindowManager.TRANSIT_FIRST_CUSTOM + 11;
/** Transition type to fullscreen from desktop mode. */
public static final int TRANSIT_EXIT_DESKTOP_MODE = WindowManager.TRANSIT_FIRST_CUSTOM + 12;
/** Transition type to animate back to fullscreen when drag to freeform is cancelled. */
- public static final int TRANSIT_CANCEL_ENTERING_DESKTOP_MODE =
+ public static final int TRANSIT_CANCEL_DRAG_TO_DESKTOP_MODE =
WindowManager.TRANSIT_FIRST_CUSTOM + 13;
+ /** Transition type to animate the toggle resize between the max and default desktop sizes. */
+ public static final int TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE =
+ WindowManager.TRANSIT_FIRST_CUSTOM + 14;
+
+ /** Transition to animate task to desktop. */
+ public static final int TRANSIT_MOVE_TO_DESKTOP = WindowManager.TRANSIT_FIRST_CUSTOM + 15;
+
private final WindowOrganizer mOrganizer;
private final Context mContext;
private final ShellExecutor mMainExecutor;
@@ -724,11 +733,15 @@ public class Transitions implements RemoteCallable<Transitions>,
final int changeSize = info.getChanges().size();
boolean taskChange = false;
boolean transferStartingWindow = false;
+ int noAnimationBehindStartingWindow = 0;
boolean allOccluded = changeSize > 0;
for (int i = changeSize - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
taskChange |= change.getTaskInfo() != null;
transferStartingWindow |= change.hasFlags(FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT);
+ if (change.hasAllFlags(FLAG_IS_BEHIND_STARTING_WINDOW | FLAG_NO_ANIMATION)) {
+ noAnimationBehindStartingWindow++;
+ }
if (!change.hasFlags(FLAG_IS_OCCLUDED)) {
allOccluded = false;
}
@@ -736,9 +749,11 @@ public class Transitions implements RemoteCallable<Transitions>,
// There does not need animation when:
// A. Transfer starting window. Apply transfer starting window directly if there is no other
// task change. Since this is an activity->activity situation, we can detect it by selecting
- // transitions with only 2 changes where neither are tasks and one is a starting-window
- // recipient.
- if (!taskChange && transferStartingWindow && changeSize == 2
+ // transitions with only 2 changes where
+ // 1. neither are tasks, and
+ // 2. one is a starting-window recipient, or all change is behind starting window.
+ if (!taskChange && (transferStartingWindow || noAnimationBehindStartingWindow == changeSize)
+ && changeSize == 2
// B. It's visibility change if the TRANSIT_TO_BACK/TO_FRONT happened when all
// changes are underneath another change.
|| ((info.getType() == TRANSIT_TO_BACK || info.getType() == TRANSIT_TO_FRONT)
@@ -813,7 +828,7 @@ public class Transitions implements RemoteCallable<Transitions>,
ready.mStartT.apply();
}
// finish now since there's nothing to animate. Calls back into processReadyQueue
- onFinish(ready, null, null);
+ onFinish(ready, null);
return;
}
playTransition(ready);
@@ -833,7 +848,7 @@ public class Transitions implements RemoteCallable<Transitions>,
+ " in case they can be merged", ready, playing);
mTracer.logMergeRequested(ready.mInfo.getDebugId(), playing.mInfo.getDebugId());
playing.mHandler.mergeAnimation(ready.mToken, ready.mInfo, ready.mStartT,
- playing.mToken, (wct, cb) -> onMerged(playing, ready));
+ playing.mToken, (wct) -> onMerged(playing, ready));
}
private void onMerged(@NonNull ActiveTransition playing, @NonNull ActiveTransition merged) {
@@ -883,7 +898,7 @@ public class Transitions implements RemoteCallable<Transitions>,
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " try firstHandler %s",
active.mHandler);
boolean consumed = active.mHandler.startAnimation(active.mToken, active.mInfo,
- active.mStartT, active.mFinishT, (wct, cb) -> onFinish(active, wct, cb));
+ active.mStartT, active.mFinishT, (wct) -> onFinish(active, wct));
if (consumed) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " animated by firstHandler");
mTracer.logDispatched(active.mInfo.getDebugId(), active.mHandler);
@@ -892,7 +907,7 @@ public class Transitions implements RemoteCallable<Transitions>,
}
// Otherwise give every other handler a chance
active.mHandler = dispatchTransition(active.mToken, active.mInfo, active.mStartT,
- active.mFinishT, (wct, cb) -> onFinish(active, wct, cb), active.mHandler);
+ active.mFinishT, (wct) -> onFinish(active, wct), active.mHandler);
}
/**
@@ -969,8 +984,7 @@ public class Transitions implements RemoteCallable<Transitions>,
}
private void onFinish(ActiveTransition active,
- @Nullable WindowContainerTransaction wct,
- @Nullable WindowContainerTransactionCallback wctCB) {
+ @Nullable WindowContainerTransaction wct) {
final Track track = mTracks.get(active.getTrack());
if (track.mActiveTransition != active) {
Log.e(TAG, "Trying to finish a non-running transition. Either remote crashed or "
@@ -1019,11 +1033,11 @@ public class Transitions implements RemoteCallable<Transitions>,
// Now perform all the finish callbacks (starting with the playing one and then all the
// transitions merged into it).
releaseSurfaces(active.mInfo);
- mOrganizer.finishTransition(active.mToken, wct, wctCB);
+ mOrganizer.finishTransition(active.mToken, wct);
if (active.mMerged != null) {
for (int iM = 0; iM < active.mMerged.size(); ++iM) {
ActiveTransition merged = active.mMerged.get(iM);
- mOrganizer.finishTransition(merged.mToken, null /* wct */, null /* wctCB */);
+ mOrganizer.finishTransition(merged.mToken, null /* wct */);
releaseSurfaces(merged.mInfo);
}
active.mMerged.clear();
@@ -1162,7 +1176,7 @@ public class Transitions implements RemoteCallable<Transitions>,
forceFinish.mHandler.onTransitionConsumed(
forceFinish.mToken, true /* aborted */, null /* finishTransaction */);
}
- onFinish(forceFinish, null, null);
+ onFinish(forceFinish, null);
}
}
if (track.isIdle() || mReadyDuringSync.isEmpty()) {
@@ -1182,7 +1196,7 @@ public class Transitions implements RemoteCallable<Transitions>,
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Attempt to merge sync %s"
+ " into %s via a SLEEP proxy", nextSync, playing);
playing.mHandler.mergeAnimation(nextSync.mToken, dummyInfo, dummyT,
- playing.mToken, (wct, cb) -> {});
+ playing.mToken, (wct) -> {});
// it's possible to complete immediately. If that happens, just repeat the signal
// loop until we either finish everything or start playing an animation that isn't
// finishing immediately.
@@ -1210,11 +1224,8 @@ public class Transitions implements RemoteCallable<Transitions>,
* The transition must not touch the surfaces after this has been called.
*
* @param wct A WindowContainerTransaction to run along with the transition clean-up.
- * @param wctCB A sync callback that will be run when the transition clean-up is done and
- * wct has been applied.
*/
- void onTransitionFinished(@Nullable WindowContainerTransaction wct,
- @Nullable WindowContainerTransactionCallback wctCB);
+ void onTransitionFinished(@Nullable WindowContainerTransaction wct);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index f148412205bf..2eb6e71456db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -169,7 +169,7 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
animator.stop();
}
- mFinishCallback.onTransitionFinished(null, null);
+ mFinishCallback.onTransitionFinished(null);
mFinishCallback = null;
mTransition = null;
}
@@ -193,7 +193,7 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
}
// Apply changes happening during the unfold animation immediately
t.apply();
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java
index f81fc6fbea49..6bba0d1386fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java
@@ -110,7 +110,7 @@ public class FullscreenUnfoldTaskAnimator implements UnfoldTaskAnimator,
for (int i = state.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
if (source.getType() == WindowInsets.Type.navigationBars()
- && source.insetsRoundedCornerFrame()) {
+ && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
return source;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
index a4cf149cc3b5..bb5d54652460 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
@@ -50,11 +50,11 @@ import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.unfold.UnfoldAnimationController;
import com.android.wm.shell.unfold.UnfoldBackgroundController;
+import dagger.Lazy;
+
import java.util.Optional;
import java.util.concurrent.Executor;
-import dagger.Lazy;
-
/**
* This helper class contains logic that calculates scaling and cropping parameters
* for the folding/unfolding animation. As an input it receives TaskInfo objects and
@@ -149,7 +149,7 @@ public class SplitTaskUnfoldAnimator implements UnfoldTaskAnimator,
for (int i = state.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
if (source.getType() == WindowInsets.Type.navigationBars()
- && source.insetsRoundedCornerFrame()) {
+ && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
return source;
}
}
@@ -270,7 +270,6 @@ public class SplitTaskUnfoldAnimator implements UnfoldTaskAnimator,
@Override
public void prepareStartTransaction(Transaction transaction) {
mUnfoldBackgroundController.ensureBackground(transaction);
- mSplitScreenController.get().get().updateSplitScreenSurfaces(transaction);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 39fb7936747e..cf1692018518 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -33,11 +33,14 @@ import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import androidx.annotation.Nullable;
+
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
/**
@@ -89,6 +92,9 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
}
@Override
+ public void setSplitScreenController(SplitScreenController splitScreenController) {}
+
+ @Override
public boolean onTaskOpening(
RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
@@ -187,7 +193,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
final DragPositioningCallback dragPositioningCallback =
new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController,
- null /* disallowedAreaForEndBounds */);
+ 0 /* disallowedAreaForEndBoundsHeight */);
final CaptionTouchEventListener touchEventListener =
new CaptionTouchEventListener(taskInfo, dragPositioningCallback);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
@@ -254,7 +260,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
* @return {@code true} if a drag is happening; or {@code false} if it is not
*/
@Override
- public boolean handleMotionEvent(MotionEvent e) {
+ public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
return false;
@@ -268,7 +274,10 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
return false;
}
case MotionEvent.ACTION_MOVE: {
- int dragPointerIdx = e.findPointerIndex(mDragPointerId);
+ if (e.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = e.getPointerId(0);
+ }
+ final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
mDragPositioningCallback.onDragPositioningMove(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
mIsDragging = true;
@@ -276,7 +285,10 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
- int dragPointerIdx = e.findPointerIndex(mDragPointerId);
+ if (e.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = e.getPointerId(0);
+ }
+ final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
mDragPositioningCallback.onDragPositioningEnd(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
final boolean wasDragging = mIsDragging;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 116af7094e13..ce8191067ae9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -113,7 +113,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
mRelayoutParams.reset();
mRelayoutParams.mRunningTaskInfo = taskInfo;
mRelayoutParams.mLayoutResId = R.layout.caption_window_decor;
- mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
+ mRelayoutParams.mCaptionHeightId = getCaptionHeightId();
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
@@ -143,8 +143,11 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
mHandler,
mChoreographer,
mDisplay.getDisplayId(),
+ 0 /* taskCornerRadius */,
mDecorationContainerSurface,
- mDragPositioningCallback);
+ mDragPositioningCallback,
+ mSurfaceControlBuilderSupplier,
+ mSurfaceControlTransactionSupplier);
}
final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext())
@@ -221,4 +224,9 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
closeDragResizeListener();
super.close();
}
+
+ @Override
+ int getCaptionHeightId() {
+ return R.dimen.freeform_decor_caption_height;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 9fd57d7e1201..2b19da2498a6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -19,12 +19,14 @@ package com.android.wm.shell.windowdecor;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.DRAG_FREEFORM_SCALE;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION;
+import static com.android.wm.shell.windowdecor.MoveToDesktopAnimator.DRAG_FREEFORM_SCALE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -42,6 +44,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.util.SparseArray;
import android.view.Choreographer;
+import android.view.GestureDetector;
import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEventReceiver;
@@ -53,6 +56,7 @@ import android.view.View;
import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -68,6 +72,9 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.sysui.KeyguardChangeListener;
+import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.TaskCornersListener;
@@ -85,6 +92,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
private final DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory;
private final ActivityTaskManager mActivityTaskManager;
private final ShellTaskOrganizer mTaskOrganizer;
+ private final ShellController mShellController;
private final Context mContext;
private final Handler mMainHandler;
private final Choreographer mMainChoreographer;
@@ -106,37 +114,41 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
private final Supplier<SurfaceControl.Transaction> mTransactionFactory;
private final Transitions mTransitions;
- private Optional<SplitScreenController> mSplitScreenController;
+ private SplitScreenController mSplitScreenController;
- private ValueAnimator mDragToDesktopValueAnimator;
+ private MoveToDesktopAnimator mMoveToDesktopAnimator;
private final Rect mDragToDesktopAnimationStartBounds = new Rect();
- private boolean mDragToDesktopAnimationStarted;
+ private final DesktopModeKeyguardChangeListener mDesktopModeKeyguardChangeListener;
public DesktopModeWindowDecorViewModel(
Context context,
Handler mainHandler,
Choreographer mainChoreographer,
+ ShellInit shellInit,
ShellTaskOrganizer taskOrganizer,
DisplayController displayController,
+ ShellController shellController,
SyncTransactionQueue syncQueue,
Transitions transitions,
Optional<DesktopModeController> desktopModeController,
- Optional<DesktopTasksController> desktopTasksController,
- Optional<SplitScreenController> splitScreenController) {
+ Optional<DesktopTasksController> desktopTasksController
+ ) {
this(
context,
mainHandler,
mainChoreographer,
+ shellInit,
taskOrganizer,
displayController,
+ shellController,
syncQueue,
transitions,
desktopModeController,
desktopTasksController,
- splitScreenController,
new DesktopModeWindowDecoration.Factory(),
new InputMonitorFactory(),
- SurfaceControl.Transaction::new);
+ SurfaceControl.Transaction::new,
+ new DesktopModeKeyguardChangeListener());
}
@VisibleForTesting
@@ -144,23 +156,25 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
Context context,
Handler mainHandler,
Choreographer mainChoreographer,
+ ShellInit shellInit,
ShellTaskOrganizer taskOrganizer,
DisplayController displayController,
+ ShellController shellController,
SyncTransactionQueue syncQueue,
Transitions transitions,
Optional<DesktopModeController> desktopModeController,
Optional<DesktopTasksController> desktopTasksController,
- Optional<SplitScreenController> splitScreenController,
DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
InputMonitorFactory inputMonitorFactory,
- Supplier<SurfaceControl.Transaction> transactionFactory) {
+ Supplier<SurfaceControl.Transaction> transactionFactory,
+ DesktopModeKeyguardChangeListener desktopModeKeyguardChangeListener) {
mContext = context;
mMainHandler = mainHandler;
mMainChoreographer = mainChoreographer;
mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
mTaskOrganizer = taskOrganizer;
+ mShellController = shellController;
mDisplayController = displayController;
- mSplitScreenController = splitScreenController;
mSyncQueue = syncQueue;
mTransitions = transitions;
mDesktopModeController = desktopModeController;
@@ -169,6 +183,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
mInputMonitorFactory = inputMonitorFactory;
mTransactionFactory = transactionFactory;
+ mDesktopModeKeyguardChangeListener = desktopModeKeyguardChangeListener;
+
+ shellInit.addInitCallback(this::onInit, this);
+ }
+
+ private void onInit() {
+ mShellController.addKeyguardChangeListener(mDesktopModeKeyguardChangeListener);
}
@Override
@@ -177,6 +198,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
@Override
+ public void setSplitScreenController(SplitScreenController splitScreenController) {
+ mSplitScreenController = splitScreenController;
+ }
+
+ @Override
public boolean onTaskOpening(
ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
@@ -193,7 +219,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change) {
if (change.getMode() == WindowManager.TRANSIT_CHANGE
- && (info.getType() == Transitions.TRANSIT_ENTER_DESKTOP_MODE)) {
+ && (info.getType() == Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE
+ || info.getType() == Transitions.TRANSIT_CANCEL_DRAG_TO_DESKTOP_MODE
+ || info.getType() == Transitions.TRANSIT_EXIT_DESKTOP_MODE
+ || info.getType() == Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE
+ || info.getType() == Transitions.TRANSIT_MOVE_TO_DESKTOP)) {
mWindowDecorByTaskId.get(change.getTaskInfo().taskId)
.addTransitionPausingRelayout(transition);
}
@@ -225,7 +255,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
removeTaskFromEventReceiver(oldTaskInfo.displayId);
incrementEventReceiverTasks(taskInfo.displayId);
}
-
decoration.relayout(taskInfo);
}
@@ -236,7 +265,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
-
if (!shouldShowWindowDecor(taskInfo)) {
if (decoration != null) {
destroyWindowDecoration(taskInfo);
@@ -275,15 +303,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
}
- private class DesktopModeTouchEventListener implements
- View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler {
+ private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
+ implements View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler {
private final int mTaskId;
private final WindowContainerToken mTaskToken;
private final DragPositioningCallback mDragPositioningCallback;
private final DragDetector mDragDetector;
+ private final GestureDetector mGestureDetector;
private boolean mIsDragging;
+ private boolean mShouldClick;
private int mDragPointerId = -1;
private DesktopModeTouchEventListener(
@@ -293,6 +323,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mTaskToken = taskInfo.token;
mDragPositioningCallback = dragPositioningCallback;
mDragDetector = new DragDetector(this);
+ mGestureDetector = new GestureDetector(mContext, this);
}
@Override
@@ -301,14 +332,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
final int id = v.getId();
if (id == R.id.close_window || id == R.id.close_button) {
mTaskOperations.closeTask(mTaskToken);
- if (mSplitScreenController.isPresent()
- && mSplitScreenController.get().isSplitScreenVisible()) {
- int remainingTaskPosition = mTaskId == mSplitScreenController.get()
+ if (mSplitScreenController != null
+ && mSplitScreenController.isSplitScreenVisible()) {
+ int remainingTaskPosition = mTaskId == mSplitScreenController
.getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT).taskId
? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
- ActivityManager.RunningTaskInfo remainingTask = mSplitScreenController.get()
+ ActivityManager.RunningTaskInfo remainingTask = mSplitScreenController
.getTaskInfo(remainingTaskPosition);
- mSplitScreenController.get().moveTaskToFullscreen(remainingTask.taskId);
+ mSplitScreenController.moveTaskToFullscreen(remainingTask.taskId);
}
} else if (id == R.id.back_button) {
mTaskOperations.injectBackKey();
@@ -321,7 +352,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
} else if (id == R.id.desktop_button) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
- mDesktopTasksController.ifPresent(c -> c.moveToDesktop(mTaskId));
+ if (mDesktopTasksController.isPresent()) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ // App sometimes draws before the insets from WindowDecoration#relayout have
+ // been added, so they must be added here
+ mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct);
+ decoration.incrementRelayoutBlock();
+ mDesktopTasksController.get().moveToDesktop(decoration, mTaskId, wct);
+ }
decoration.closeHandleMenu();
} else if (id == R.id.fullscreen_button) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false));
@@ -336,6 +374,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId));
decoration.closeHandleMenu();
}
+ } else if (id == R.id.maximize_window) {
+ final RunningTaskInfo taskInfo = decoration.mTaskInfo;
+ mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(
+ taskInfo, decoration));
+ decoration.closeHandleMenu();
}
}
@@ -347,7 +390,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
return false;
}
moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
- return mDragDetector.onMotionEvent(e);
+ return mDragDetector.onMotionEvent(v, e);
}
private void moveTaskToFront(RunningTaskInfo taskInfo) {
@@ -362,7 +405,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
* @return {@code true} if the motion event is handled.
*/
@Override
- public boolean handleMotionEvent(MotionEvent e) {
+ public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
if (DesktopModeStatus.isProto2Enabled()
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
@@ -373,6 +416,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
== WINDOWING_MODE_FULLSCREEN) {
return false;
}
+ if (mGestureDetector.onTouchEvent(e)) {
+ return true;
+ }
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
mDragPointerId = e.getPointerId(0);
@@ -380,21 +426,38 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
0 /* ctrlType */, e.getRawX(0),
e.getRawY(0));
mIsDragging = false;
- return false;
+ mShouldClick = true;
+ return true;
}
case MotionEvent.ACTION_MOVE: {
final DesktopModeWindowDecoration decoration =
mWindowDecorByTaskId.get(mTaskId);
+ if (e.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = e.getPointerId(0);
+ }
final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
- mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo,
- decoration.mTaskSurface, e.getRawY(dragPointerIdx)));
- mDragPositioningCallback.onDragPositioningMove(
+ final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningMove(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
+ mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo,
+ decoration.mTaskSurface, newTaskBounds.top));
mIsDragging = true;
+ mShouldClick = false;
return true;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
+ final boolean wasDragging = mIsDragging;
+ if (!wasDragging) {
+ if (mShouldClick && v != null) {
+ v.performClick();
+ mShouldClick = false;
+ return true;
+ }
+ return false;
+ }
+ if (e.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = e.getPointerId(0);
+ }
final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
// Position of the task is calculated by subtracting the raw location of the
// motion event (the location of the motion relative to the display) by the
@@ -402,17 +465,25 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
final Point position = new Point(
(int) (e.getRawX(dragPointerIdx) - e.getX(dragPointerIdx)),
(int) (e.getRawY(dragPointerIdx) - e.getY(dragPointerIdx)));
- mDragPositioningCallback.onDragPositioningEnd(
+ final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningEnd(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
mDesktopTasksController.ifPresent(c -> c.onDragPositioningEnd(taskInfo,
- position));
- final boolean wasDragging = mIsDragging;
+ position, newTaskBounds.top, mWindowDecorByTaskId.get(mTaskId)));
mIsDragging = false;
- return wasDragging;
+ return true;
}
}
return true;
}
+
+ @Override
+ public boolean onDoubleTap(@NonNull MotionEvent e) {
+ final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+ mDesktopTasksController.ifPresent(c -> {
+ c.toggleDesktopTaskSize(taskInfo, mWindowDecorByTaskId.get(taskInfo.taskId));
+ });
+ return true;
+ }
}
// InputEventReceiver to listen for touch input outside of caption bounds
@@ -540,9 +611,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
relevantDecor.mTaskInfo.configuration.windowConfiguration.getBounds());
boolean dragFromStatusBarAllowed = false;
if (DesktopModeStatus.isProto2Enabled()) {
- // In proto2 any full screen task can be dragged to freeform
- dragFromStatusBarAllowed = relevantDecor.mTaskInfo.getWindowingMode()
- == WINDOWING_MODE_FULLSCREEN;
+ // In proto2 any full screen or multi-window task can be dragged to
+ // freeform.
+ final int windowingMode = relevantDecor.mTaskInfo.getWindowingMode();
+ dragFromStatusBarAllowed = windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_MULTI_WINDOW;
}
if (dragFromStatusBarAllowed && relevantDecor.checkTouchEventInHandle(ev)) {
@@ -553,7 +626,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
case MotionEvent.ACTION_UP: {
if (relevantDecor == null) {
- mDragToDesktopAnimationStarted = false;
+ mMoveToDesktopAnimator = null;
mTransitionDragActive = false;
return;
}
@@ -567,14 +640,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
} else if (DesktopModeStatus.isProto1Enabled()) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
}
- mDragToDesktopAnimationStarted = false;
+ mMoveToDesktopAnimator = null;
return;
- } else if (mDragToDesktopAnimationStarted) {
- Point position = new Point((int) ev.getX(), (int) ev.getY());
+ } else if (mMoveToDesktopAnimator != null) {
+ relevantDecor.incrementRelayoutBlock();
mDesktopTasksController.ifPresent(
- c -> c.cancelMoveToFreeform(relevantDecor.mTaskInfo,
- position));
- mDragToDesktopAnimationStarted = false;
+ c -> c.cancelMoveToDesktop(relevantDecor.mTaskInfo,
+ mMoveToDesktopAnimator));
+ mMoveToDesktopAnimator = null;
return;
}
}
@@ -594,21 +667,19 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
final int statusBarHeight = getStatusBarHeight(
relevantDecor.mTaskInfo.displayId);
if (ev.getY() > statusBarHeight) {
- if (!mDragToDesktopAnimationStarted) {
- mDragToDesktopAnimationStarted = true;
+ if (mMoveToDesktopAnimator == null) {
+ mMoveToDesktopAnimator = new MoveToDesktopAnimator(
+ mDragToDesktopAnimationStartBounds, relevantDecor.mTaskInfo,
+ relevantDecor.mTaskSurface);
mDesktopTasksController.ifPresent(
- c -> c.moveToFreeform(relevantDecor.mTaskInfo,
- mDragToDesktopAnimationStartBounds));
- startAnimation(relevantDecor);
+ c -> c.startMoveToDesktop(relevantDecor.mTaskInfo,
+ mDragToDesktopAnimationStartBounds,
+ mMoveToDesktopAnimator));
+ mMoveToDesktopAnimator.startAnimation();
}
}
- if (mDragToDesktopAnimationStarted) {
- Transaction t = mTransactionFactory.get();
- float width = (float) mDragToDesktopValueAnimator.getAnimatedValue()
- * mDragToDesktopAnimationStartBounds.width();
- float x = ev.getX() - (width / 2);
- t.setPosition(relevantDecor.mTaskSurface, x, ev.getY());
- t.apply();
+ if (mMoveToDesktopAnimator != null) {
+ mMoveToDesktopAnimator.updatePosition(ev);
}
}
break;
@@ -616,7 +687,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
case MotionEvent.ACTION_CANCEL: {
mTransitionDragActive = false;
- mDragToDesktopAnimationStarted = false;
+ mMoveToDesktopAnimator = null;
}
}
}
@@ -683,24 +754,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
animator.start();
}
- private void startAnimation(@NonNull DesktopModeWindowDecoration focusedDecor) {
- mDragToDesktopValueAnimator = ValueAnimator.ofFloat(1f, DRAG_FREEFORM_SCALE);
- mDragToDesktopValueAnimator.setDuration(FREEFORM_ANIMATION_DURATION);
- final Transaction t = mTransactionFactory.get();
- mDragToDesktopValueAnimator.addUpdateListener(animation -> {
- final float animatorValue = (float) animation.getAnimatedValue();
- SurfaceControl sc = focusedDecor.mTaskSurface;
- t.setScale(sc, animatorValue, animatorValue);
- t.apply();
- });
-
- mDragToDesktopValueAnimator.start();
- }
-
@Nullable
private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) {
- if (mSplitScreenController.isPresent()
- && mSplitScreenController.get().isSplitScreenVisible()) {
+ if (mSplitScreenController != null && mSplitScreenController.isSplitScreenVisible()) {
// We can't look at focused task here as only one task will have focus.
return getSplitScreenDecor(ev);
} else {
@@ -711,9 +767,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
@Nullable
private DesktopModeWindowDecoration getSplitScreenDecor(MotionEvent ev) {
ActivityManager.RunningTaskInfo topOrLeftTask =
- mSplitScreenController.get().getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
+ mSplitScreenController.getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
ActivityManager.RunningTaskInfo bottomOrRightTask =
- mSplitScreenController.get().getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+ mSplitScreenController.getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
if (topOrLeftTask != null && topOrLeftTask.getConfiguration()
.windowConfiguration.getBounds().contains((int) ev.getX(), (int) ev.getY())) {
return mWindowDecorByTaskId.get(topOrLeftTask.taskId);
@@ -765,12 +821,18 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
- if (mSplitScreenController.isPresent()
- && mSplitScreenController.get().isTaskRootOrStageRoot(taskInfo.taskId)) {
+ if (mSplitScreenController != null
+ && mSplitScreenController.isTaskRootOrStageRoot(taskInfo.taskId)) {
+ return false;
+ }
+ if (mDesktopModeKeyguardChangeListener.isKeyguardVisibleAndOccluded()
+ && taskInfo.isFocused) {
return false;
}
return DesktopModeStatus.isProto2Enabled()
+ && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
&& taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
+ && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop()
&& mDisplayController.getDisplayContext(taskInfo.displayId)
.getResources().getConfiguration().smallestScreenWidthDp >= 600;
}
@@ -796,9 +858,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mMainChoreographer,
mSyncQueue);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
+ windowDecoration.createResizeVeil();
final DragPositioningCallback dragPositioningCallback = createDragPositioningCallback(
- windowDecoration, taskInfo);
+ windowDecoration);
final DesktopModeTouchEventListener touchEventListener =
new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback);
@@ -811,20 +874,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
incrementEventReceiverTasks(taskInfo.displayId);
}
private DragPositioningCallback createDragPositioningCallback(
- @NonNull DesktopModeWindowDecoration windowDecoration,
- @NonNull RunningTaskInfo taskInfo) {
- final int screenWidth = mDisplayController.getDisplayLayout(taskInfo.displayId).width();
- final Rect disallowedAreaForEndBounds = new Rect(0, 0, screenWidth,
- getStatusBarHeight(taskInfo.displayId));
+ @NonNull DesktopModeWindowDecoration windowDecoration) {
+ final int transitionAreaHeight = mContext.getResources().getDimensionPixelSize(
+ R.dimen.desktop_mode_transition_area_height);
if (!DesktopModeStatus.isVeiledResizeEnabled()) {
return new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
- mDisplayController, disallowedAreaForEndBounds, mDragStartListener,
- mTransactionFactory);
+ mDisplayController, mDragStartListener, mTransactionFactory,
+ transitionAreaHeight);
} else {
- windowDecoration.createResizeVeil();
return new VeiledResizeTaskPositioner(mTaskOrganizer, windowDecoration,
- mDisplayController, disallowedAreaForEndBounds, mDragStartListener,
- mTransitions);
+ mDisplayController, mDragStartListener, mTransitions,
+ transitionAreaHeight);
}
}
@@ -857,6 +917,22 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mDesktopTasksController.ifPresent(d -> d.removeCornersForTask(taskId));
}
}
+
+ static class DesktopModeKeyguardChangeListener implements KeyguardChangeListener {
+ private boolean mIsKeyguardVisible;
+ private boolean mIsKeyguardOccluded;
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
+ boolean animatingDismiss) {
+ mIsKeyguardVisible = visible;
+ mIsKeyguardOccluded = occluded;
+ }
+
+ public boolean isKeyguardVisibleAndOccluded() {
+ return mIsKeyguardVisible && mIsKeyguardOccluded;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index ce11b2604559..a359395711e3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -23,7 +23,6 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.content.res.TypedArray;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -39,6 +38,7 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.window.WindowContainerTransaction;
+import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -178,15 +178,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
mRelayoutParams.reset();
mRelayoutParams.mRunningTaskInfo = taskInfo;
mRelayoutParams.mLayoutResId = windowDecorLayoutId;
- mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
+ mRelayoutParams.mCaptionHeightId = getCaptionHeightId();
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
- final TypedArray ta = mContext.obtainStyledAttributes(
- new int[]{android.R.attr.dialogCornerRadius});
- mRelayoutParams.mCornerRadius = ta.getDimensionPixelSize(0, 0);
- ta.recycle();
-
+ mRelayoutParams.mCornerRadius =
+ (int) ScreenDecorationsUtils.getWindowCornerRadius(mContext);
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
@@ -235,8 +232,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
mHandler,
mChoreographer,
mDisplay.getDisplayId(),
+ mRelayoutParams.mCornerRadius,
mDecorationContainerSurface,
- mDragPositioningCallback);
+ mDragPositioningCallback,
+ mSurfaceControlBuilderSupplier,
+ mSurfaceControlTransactionSupplier);
}
final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext())
@@ -294,23 +294,37 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
}
/**
- * Fade in the resize veil
+ * Show the resize veil.
*/
- void showResizeVeil(Rect taskBounds) {
+ public void showResizeVeil(Rect taskBounds) {
mResizeVeil.showVeil(mTaskSurface, taskBounds);
}
/**
+ * Show the resize veil.
+ */
+ public void showResizeVeil(SurfaceControl.Transaction tx, Rect taskBounds) {
+ mResizeVeil.showVeil(tx, mTaskSurface, taskBounds, false /* fadeIn */);
+ }
+
+ /**
* Set new bounds for the resize veil
*/
- void updateResizeVeil(Rect newBounds) {
+ public void updateResizeVeil(Rect newBounds) {
mResizeVeil.updateResizeVeil(newBounds);
}
/**
+ * Set new bounds for the resize veil
+ */
+ public void updateResizeVeil(SurfaceControl.Transaction tx, Rect newBounds) {
+ mResizeVeil.updateResizeVeil(tx, newBounds);
+ }
+
+ /**
* Fade the resize veil out.
*/
- void hideResizeVeil() {
+ public void hideResizeVeil() {
mResizeVeil.hideVeil();
}
@@ -479,6 +493,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
}
}
+ @Override
+ int getCaptionHeightId() {
+ return R.dimen.freeform_decor_caption_height;
+ }
+
/**
* Add transition to mTransitionsPausingRelayout
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index 65b5a7a17afe..da268988bac7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -24,6 +24,9 @@ import static android.view.MotionEvent.ACTION_UP;
import android.graphics.PointF;
import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.Nullable;
/**
* A detector for touch inputs that differentiates between drag and click inputs. It receives a flow
@@ -54,14 +57,24 @@ class DragDetector {
*
* @return the result returned by {@link #mEventHandler}, or the result when
* {@link #mEventHandler} handles the previous down event if the event shouldn't be passed
- */
+ */
boolean onMotionEvent(MotionEvent ev) {
+ return onMotionEvent(null /* view */, ev);
+ }
+
+ /**
+ * The receiver of the {@link MotionEvent} flow.
+ *
+ * @return the result returned by {@link #mEventHandler}, or the result when
+ * {@link #mEventHandler} handles the previous down event if the event shouldn't be passed
+ */
+ boolean onMotionEvent(View v, MotionEvent ev) {
final boolean isTouchScreen =
(ev.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
if (!isTouchScreen) {
// Only touches generate noisy moves, so mouse/trackpad events don't need to filtered
// to take the slop threshold into consideration.
- return mEventHandler.handleMotionEvent(ev);
+ return mEventHandler.handleMotionEvent(v, ev);
}
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
@@ -69,12 +82,15 @@ class DragDetector {
float rawX = ev.getRawX(0);
float rawY = ev.getRawY(0);
mInputDownPoint.set(rawX, rawY);
- mResultOfDownAction = mEventHandler.handleMotionEvent(ev);
+ mResultOfDownAction = mEventHandler.handleMotionEvent(v, ev);
return mResultOfDownAction;
}
case ACTION_MOVE: {
+ if (ev.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = ev.getPointerId(0);
+ }
+ final int dragPointerIndex = ev.findPointerIndex(mDragPointerId);
if (!mIsDragEvent) {
- int dragPointerIndex = ev.findPointerIndex(mDragPointerId);
float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x;
float dy = ev.getRawY(dragPointerIndex) - mInputDownPoint.y;
// Touches generate noisy moves, so only once the move is past the touch
@@ -84,7 +100,7 @@ class DragDetector {
// The event handler should only be notified about 'move' events if a drag has been
// detected.
if (mIsDragEvent) {
- return mEventHandler.handleMotionEvent(ev);
+ return mEventHandler.handleMotionEvent(v, ev);
} else {
return mResultOfDownAction;
}
@@ -92,10 +108,10 @@ class DragDetector {
case ACTION_UP:
case ACTION_CANCEL: {
resetState();
- return mEventHandler.handleMotionEvent(ev);
+ return mEventHandler.handleMotionEvent(v, ev);
}
default:
- return mEventHandler.handleMotionEvent(ev);
+ return mEventHandler.handleMotionEvent(v, ev);
}
}
@@ -111,6 +127,6 @@ class DragDetector {
}
interface MotionEventHandler {
- boolean handleMotionEvent(MotionEvent ev);
+ boolean handleMotionEvent(@Nullable View v, MotionEvent ev);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
index 4e98f0c3a48a..1669cf4a222c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
@@ -17,12 +17,15 @@
package com.android.wm.shell.windowdecor;
import android.annotation.IntDef;
+import android.graphics.Rect;
/**
* Callback called when receiving drag-resize or drag-move related input events.
*/
public interface DragPositioningCallback {
- @IntDef({CTRL_TYPE_UNDEFINED, CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM})
+ @IntDef(flag = true, value = {
+ CTRL_TYPE_UNDEFINED, CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM
+ })
@interface CtrlType {}
int CTRL_TYPE_UNDEFINED = 0;
@@ -44,13 +47,15 @@ public interface DragPositioningCallback {
* Called when the pointer moves during a drag-resize or drag-move.
* @param x x coordinate in window decoration coordinate system of the new pointer location
* @param y y coordinate in window decoration coordinate system of the new pointer location
+ * @return the updated task bounds
*/
- void onDragPositioningMove(float x, float y);
+ Rect onDragPositioningMove(float x, float y);
/**
* Called when a drag-resize or drag-move stops.
* @param x x coordinate in window decoration coordinate system where the drag resize stops
* @param y y coordinate in window decoration coordinate system where the drag resize stops
+ * @return the final bounds for the dragged task
*/
- void onDragPositioningEnd(float x, float y);
+ Rect onDragPositioningEnd(float x, float y);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
index 09e29bcbcf9f..e32bd42acf74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
@@ -83,8 +83,6 @@ public class DragPositioningCallbackUtility {
// Make sure the new resizing destination in any direction falls within the stable bounds.
// If not, set the bounds back to the old location that was valid to avoid conflicts with
// some regions such as the gesture area.
- displayController.getDisplayLayout(windowDecoration.mDisplay.getDisplayId())
- .getStableBounds(stableBounds);
if ((ctrlType & CTRL_TYPE_LEFT) != 0) {
final int candidateLeft = repositionTaskBounds.left + (int) delta.x;
repositionTaskBounds.left = (candidateLeft > stableBounds.left)
@@ -136,7 +134,7 @@ public class DragPositioningCallbackUtility {
repositionTaskBounds.top);
}
- static void updateTaskBounds(Rect repositionTaskBounds, Rect taskBoundsAtDragStart,
+ private static void updateTaskBounds(Rect repositionTaskBounds, Rect taskBoundsAtDragStart,
PointF repositionStartPoint, float x, float y) {
final float deltaX = x - repositionStartPoint.x;
final float deltaY = y - repositionStartPoint.y;
@@ -145,6 +143,23 @@ public class DragPositioningCallbackUtility {
}
/**
+ * Updates repositionTaskBounds to the final bounds of the task after the drag is finished. If
+ * the bounds are outside of the stable bounds, they are shifted to place task at the top of the
+ * stable bounds.
+ */
+ static void onDragEnd(Rect repositionTaskBounds, Rect taskBoundsAtDragStart, Rect stableBounds,
+ PointF repositionStartPoint, float x, float y) {
+ updateTaskBounds(repositionTaskBounds, taskBoundsAtDragStart, repositionStartPoint,
+ x, y);
+
+ // If task is outside of stable bounds (in the status bar area), shift the task down.
+ if (stableBounds.top > repositionTaskBounds.top) {
+ final int yShift = stableBounds.top - repositionTaskBounds.top;
+ repositionTaskBounds.offset(0, yShift);
+ }
+ }
+
+ /**
* Apply a bounds change to a task.
* @param windowDecoration decor of task we are changing bounds for
* @param taskBounds new bounds of this task
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 287d86187288..7c6fb99e9c8b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -18,8 +18,11 @@ package com.android.wm.shell.windowdecor;
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT;
@@ -42,11 +45,14 @@ import android.view.InputEventReceiver;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.SurfaceControl;
+import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManagerGlobal;
import com.android.internal.view.BaseIWindow;
+import java.util.function.Supplier;
+
/**
* An input event listener registered to InputDispatcher to receive input events on task edges and
* and corners. Converts them to drag resize requests.
@@ -55,11 +61,11 @@ import com.android.internal.view.BaseIWindow;
*/
class DragResizeInputListener implements AutoCloseable {
private static final String TAG = "DragResizeInputListener";
-
private final IWindowSession mWindowSession = WindowManagerGlobal.getWindowSession();
private final Handler mHandler;
private final Choreographer mChoreographer;
private final InputManager mInputManager;
+ private final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
private final int mDisplayId;
private final BaseIWindow mFakeWindow;
@@ -69,10 +75,15 @@ class DragResizeInputListener implements AutoCloseable {
private final TaskResizeInputEventReceiver mInputEventReceiver;
private final DragPositioningCallback mCallback;
+ private final SurfaceControl mInputSinkSurface;
+ private final BaseIWindow mFakeSinkWindow;
+ private final InputChannel mSinkInputChannel;
+
private int mTaskWidth;
private int mTaskHeight;
private int mResizeHandleThickness;
private int mCornerSize;
+ private int mTaskCornerRadius;
private Rect mLeftTopCornerBounds;
private Rect mRightTopCornerBounds;
@@ -87,15 +98,20 @@ class DragResizeInputListener implements AutoCloseable {
Handler handler,
Choreographer choreographer,
int displayId,
+ int taskCornerRadius,
SurfaceControl decorationSurface,
- DragPositioningCallback callback) {
+ DragPositioningCallback callback,
+ Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
+ Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier) {
mInputManager = context.getSystemService(InputManager.class);
mHandler = handler;
mChoreographer = choreographer;
+ mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
mDisplayId = displayId;
+ mTaskCornerRadius = taskCornerRadius;
mDecorationSurface = decorationSurface;
- // Use a fake window as the backing surface is a container layer and we don't want to create
- // a buffer layer for it so we can't use ViewRootImpl.
+ // Use a fake window as the backing surface is a container layer, and we don't want to
+ // create a buffer layer for it, so we can't use ViewRootImpl.
mFakeWindow = new BaseIWindow();
mFakeWindow.setSession(mWindowSession);
mFocusGrantToken = new Binder();
@@ -108,7 +124,7 @@ class DragResizeInputListener implements AutoCloseable {
null /* hostInputToken */,
FLAG_NOT_FOCUSABLE,
PRIVATE_FLAG_TRUSTED_OVERLAY,
- 0 /* inputFeatures */,
+ INPUT_FEATURE_SPY,
TYPE_APPLICATION,
null /* windowToken */,
mFocusGrantToken,
@@ -123,15 +139,39 @@ class DragResizeInputListener implements AutoCloseable {
mCallback = callback;
mDragDetector = new DragDetector(mInputEventReceiver);
mDragDetector.setTouchSlop(ViewConfiguration.get(context).getScaledTouchSlop());
+
+ mInputSinkSurface = surfaceControlBuilderSupplier.get()
+ .setName("TaskInputSink of " + decorationSurface)
+ .setContainerLayer()
+ .setParent(mDecorationSurface)
+ .build();
+ mSurfaceControlTransactionSupplier.get()
+ .setLayer(mInputSinkSurface, WindowDecoration.INPUT_SINK_Z_ORDER)
+ .show(mInputSinkSurface)
+ .apply();
+ mFakeSinkWindow = new BaseIWindow();
+ mSinkInputChannel = new InputChannel();
+ try {
+ mWindowSession.grantInputChannel(
+ mDisplayId,
+ mInputSinkSurface,
+ mFakeSinkWindow,
+ null /* hostInputToken */,
+ FLAG_NOT_FOCUSABLE,
+ 0 /* privateFlags */,
+ INPUT_FEATURE_NO_INPUT_CHANNEL,
+ TYPE_INPUT_CONSUMER,
+ null /* windowToken */,
+ mFocusGrantToken,
+ "TaskInputSink of " + decorationSurface,
+ mSinkInputChannel);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
- * Updates geometry of this drag resize handler. Needs to be called every time there is a size
- * change to notify the input event receiver it's ready to take the next input event. Otherwise
- * it'll keep batching move events and the drag resize process is stalled.
- *
- * This is also used to update the touch regions of this handler every event dispatched here is
- * a potential resize request.
+ * Updates the geometry (the touch region) of this drag resize handler.
*
* @param taskWidth The width of the task.
* @param taskHeight The height of the task.
@@ -221,7 +261,35 @@ class DragResizeInputListener implements AutoCloseable {
mDecorationSurface,
FLAG_NOT_FOCUSABLE,
PRIVATE_FLAG_TRUSTED_OVERLAY,
- 0 /* inputFeatures */,
+ INPUT_FEATURE_SPY,
+ touchRegion);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+
+ mSurfaceControlTransactionSupplier.get()
+ .setWindowCrop(mInputSinkSurface, mTaskWidth, mTaskHeight)
+ .apply();
+ // The touch region of the TaskInputSink should be the touch region of this
+ // DragResizeInputHandler minus the task bounds. Pilfering events isn't enough to prevent
+ // input windows from handling down events, which will bring tasks in the back to front.
+ //
+ // Note not the entire touch region responds to both mouse and touchscreen events.
+ // Therefore, in the region that only responds to one of them, it would be a no-op to
+ // perform a gesture in the other type of events. We currently only have a mouse-only region
+ // out of the task bounds, and due to the roughness of touchscreen events, it's not a severe
+ // issue. However, were there touchscreen-only a region out of the task bounds, mouse
+ // gestures will become no-op in that region, even though the mouse gestures may appear to
+ // be performed on the input window behind the resize handle.
+ touchRegion.op(0, 0, mTaskWidth, mTaskHeight, Region.Op.DIFFERENCE);
+ try {
+ mWindowSession.updateInputChannel(
+ mSinkInputChannel.getToken(),
+ mDisplayId,
+ mInputSinkSurface,
+ FLAG_NOT_FOCUSABLE,
+ 0 /* privateFlags */,
+ INPUT_FEATURE_NO_INPUT_CHANNEL,
touchRegion);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -250,6 +318,16 @@ class DragResizeInputListener implements AutoCloseable {
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
+
+ mSinkInputChannel.dispose();
+ try {
+ mWindowSession.remove(mFakeSinkWindow);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ mSurfaceControlTransactionSupplier.get()
+ .remove(mInputSinkSurface)
+ .apply();
}
private class TaskResizeInputEventReceiver extends InputEventReceiver
@@ -258,6 +336,7 @@ class DragResizeInputListener implements AutoCloseable {
private final Runnable mConsumeBatchEventRunnable;
private boolean mConsumeBatchEventScheduled;
private boolean mShouldHandleEvents;
+ private int mLastCursorType = PointerIcon.TYPE_DEFAULT;
private TaskResizeInputEventReceiver(
InputChannel inputChannel, Handler handler, Choreographer choreographer) {
@@ -303,7 +382,7 @@ class DragResizeInputListener implements AutoCloseable {
}
@Override
- public boolean handleMotionEvent(MotionEvent e) {
+ public boolean handleMotionEvent(View v, MotionEvent e) {
boolean result = false;
// Check if this is a touch event vs mouse event.
// Touch events are tracked in four corners. Other events are tracked in resize edges.
@@ -318,6 +397,8 @@ class DragResizeInputListener implements AutoCloseable {
mShouldHandleEvents = isInResizeHandleBounds(x, y);
}
if (mShouldHandleEvents) {
+ mInputManager.pilferPointers(mInputChannel.getToken());
+
mDragPointerId = e.getPointerId(0);
float rawX = e.getRawX(0);
float rawY = e.getRawY(0);
@@ -357,7 +438,6 @@ class DragResizeInputListener implements AutoCloseable {
break;
}
case MotionEvent.ACTION_HOVER_EXIT:
- mInputManager.setPointerIconType(PointerIcon.TYPE_DEFAULT);
result = true;
break;
}
@@ -383,19 +463,71 @@ class DragResizeInputListener implements AutoCloseable {
@DragPositioningCallback.CtrlType
private int calculateResizeHandlesCtrlType(float x, float y) {
int ctrlType = 0;
- if (x < 0) {
+ // mTaskCornerRadius is only used in comparing with corner regions. Comparisons with
+ // sides will use the bounds specified in setGeometry and not go into task bounds.
+ if (x < mTaskCornerRadius) {
ctrlType |= CTRL_TYPE_LEFT;
}
- if (x > mTaskWidth) {
+ if (x > mTaskWidth - mTaskCornerRadius) {
ctrlType |= CTRL_TYPE_RIGHT;
}
- if (y < 0) {
+ if (y < mTaskCornerRadius) {
ctrlType |= CTRL_TYPE_TOP;
}
- if (y > mTaskHeight) {
+ if (y > mTaskHeight - mTaskCornerRadius) {
ctrlType |= CTRL_TYPE_BOTTOM;
}
- return ctrlType;
+ // Check distances from the center if it's in one of four corners.
+ if ((ctrlType & (CTRL_TYPE_LEFT | CTRL_TYPE_RIGHT)) != 0
+ && (ctrlType & (CTRL_TYPE_TOP | CTRL_TYPE_BOTTOM)) != 0) {
+ return checkDistanceFromCenter(ctrlType, x, y);
+ }
+ // Otherwise, we should make sure we don't resize tasks inside task bounds.
+ return (x < 0 || y < 0 || x >= mTaskWidth || y >= mTaskHeight) ? ctrlType : 0;
+ }
+
+ // If corner input is not within appropriate distance of corner radius, do not use it.
+ // If input is not on a corner or is within valid distance, return ctrlType.
+ @DragPositioningCallback.CtrlType
+ private int checkDistanceFromCenter(@DragPositioningCallback.CtrlType int ctrlType,
+ float x, float y) {
+ int centerX;
+ int centerY;
+
+ // Determine center of rounded corner circle; this is simply the corner if radius is 0.
+ switch (ctrlType) {
+ case CTRL_TYPE_LEFT | CTRL_TYPE_TOP: {
+ centerX = mTaskCornerRadius;
+ centerY = mTaskCornerRadius;
+ break;
+ }
+ case CTRL_TYPE_LEFT | CTRL_TYPE_BOTTOM: {
+ centerX = mTaskCornerRadius;
+ centerY = mTaskHeight - mTaskCornerRadius;
+ break;
+ }
+ case CTRL_TYPE_RIGHT | CTRL_TYPE_TOP: {
+ centerX = mTaskWidth - mTaskCornerRadius;
+ centerY = mTaskCornerRadius;
+ break;
+ }
+ case CTRL_TYPE_RIGHT | CTRL_TYPE_BOTTOM: {
+ centerX = mTaskWidth - mTaskCornerRadius;
+ centerY = mTaskHeight - mTaskCornerRadius;
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("ctrlType should be complex, but it's 0x"
+ + Integer.toHexString(ctrlType));
+ }
+ }
+ double distanceFromCenter = Math.hypot(x - centerX, y - centerY);
+
+ if (distanceFromCenter < mTaskCornerRadius + mResizeHandleThickness
+ && distanceFromCenter >= mTaskCornerRadius) {
+ return ctrlType;
+ }
+ return 0;
}
@DragPositioningCallback.CtrlType
@@ -439,7 +571,19 @@ class DragResizeInputListener implements AutoCloseable {
cursorType = PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW;
break;
}
- mInputManager.setPointerIconType(cursorType);
+ // Only update the cursor type to default once so that views behind the decor container
+ // layer that aren't in the active resizing regions have chances to update the cursor
+ // type. We would like to enforce the cursor type by setting the cursor type multilple
+ // times in active regions because we shouldn't allow the views behind to change it, as
+ // we'll pilfer the gesture initiated in this area. This is necessary because 1) we
+ // should allow the views behind regions only for touches to set the cursor type; and 2)
+ // there is a small region out of each rounded corner that's inside the task bounds,
+ // where views in the task can receive input events because we can't set touch regions
+ // of input sinks to have rounded corners.
+ if (mLastCursorType != cursorType || cursorType != PointerIcon.TYPE_DEFAULT) {
+ mInputManager.setPointerIconType(cursorType);
+ mLastCursorType = cursorType;
+ }
}
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
index 9082323452c9..e0ee25242550 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
@@ -21,8 +21,6 @@ import android.graphics.Rect;
import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
-import androidx.annotation.Nullable;
-
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
@@ -42,28 +40,29 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
- // If a task move (not resize) finishes in this region, the positioner will not attempt to
+ // If a task move (not resize) finishes with the positions y less than this value, do not
// finalize the bounds there using WCT#setBounds
- private final Rect mDisallowedAreaForEndBounds;
+ private final int mDisallowedAreaForEndBoundsHeight;
private boolean mHasDragResized;
private int mCtrlType;
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController, @Nullable Rect disallowedAreaForEndBounds) {
- this(taskOrganizer, windowDecoration, displayController, disallowedAreaForEndBounds,
- dragStartListener -> {}, SurfaceControl.Transaction::new);
+ DisplayController displayController, int disallowedAreaForEndBoundsHeight) {
+ this(taskOrganizer, windowDecoration, displayController, dragStartListener -> {},
+ SurfaceControl.Transaction::new, disallowedAreaForEndBoundsHeight);
}
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController, @Nullable Rect disallowedAreaForEndBounds,
+ DisplayController displayController,
DragPositioningCallbackUtility.DragStartListener dragStartListener,
- Supplier<SurfaceControl.Transaction> supplier) {
+ Supplier<SurfaceControl.Transaction> supplier,
+ int disallowedAreaForEndBoundsHeight) {
mTaskOrganizer = taskOrganizer;
mWindowDecoration = windowDecoration;
mDisplayController = displayController;
- mDisallowedAreaForEndBounds = new Rect(disallowedAreaForEndBounds);
mDragStartListener = dragStartListener;
mTransactionSupplier = supplier;
+ mDisallowedAreaForEndBoundsHeight = disallowedAreaForEndBoundsHeight;
}
@Override
@@ -79,10 +78,14 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
mTaskOrganizer.applyTransaction(wct);
}
mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
+ if (mStableBounds.isEmpty()) {
+ mDisplayController.getDisplayLayout(mWindowDecoration.mDisplay.getDisplayId())
+ .getStableBounds(mStableBounds);
+ }
}
@Override
- public void onDragPositioningMove(float x, float y) {
+ public Rect onDragPositioningMove(float x, float y) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint);
if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType,
@@ -103,10 +106,11 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y);
t.apply();
}
+ return new Rect(mRepositionTaskBounds);
}
@Override
- public void onDragPositioningEnd(float x, float y) {
+ public Rect onDragPositioningEnd(float x, float y) {
// If task has been resized or task was dragged into area outside of
// mDisallowedAreaForEndBounds, apply WCT to finish it.
if (isResizing() && mHasDragResized) {
@@ -121,10 +125,10 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
}
mTaskOrganizer.applyTransaction(wct);
} else if (mCtrlType == CTRL_TYPE_UNDEFINED
- && !mDisallowedAreaForEndBounds.contains((int) x, (int) y)) {
+ && y > mDisallowedAreaForEndBoundsHeight) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
- DragPositioningCallbackUtility.updateTaskBounds(mRepositionTaskBounds,
- mTaskBoundsAtDragStart, mRepositionStartPoint, x, y);
+ DragPositioningCallbackUtility.onDragEnd(mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mStableBounds, mRepositionStartPoint, x, y);
wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds);
mTaskOrganizer.applyTransaction(wct);
}
@@ -133,6 +137,7 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
mRepositionStartPoint.set(0, 0);
mCtrlType = CTRL_TYPE_UNDEFINED;
mHasDragResized = false;
+ return new Rect(mRepositionTaskBounds);
}
private boolean isResizing() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt
new file mode 100644
index 000000000000..b2267ddb6ba7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt
@@ -0,0 +1,72 @@
+package com.android.wm.shell.windowdecor
+
+import android.animation.ValueAnimator
+import android.app.ActivityManager.RunningTaskInfo
+import android.graphics.PointF
+import android.graphics.Rect
+import android.view.MotionEvent
+import android.view.SurfaceControl
+
+/**
+ * Creates an animator to shrink and position task after a user drags a fullscreen task from
+ * the top of the screen to transition it into freeform and before the user releases the task. The
+ * MoveToDesktopAnimator object also holds information about the state of the task that are
+ * accessed by the EnterDesktopTaskTransitionHandler.
+ */
+class MoveToDesktopAnimator @JvmOverloads constructor(
+ private val startBounds: Rect,
+ private val taskInfo: RunningTaskInfo,
+ private val taskSurface: SurfaceControl,
+ private val transactionFactory: () -> SurfaceControl.Transaction =
+ SurfaceControl::Transaction
+) {
+ companion object {
+ // The size of the screen during drag relative to the fullscreen size
+ const val DRAG_FREEFORM_SCALE: Float = 0.4f
+ const val ANIMATION_DURATION = 336
+ }
+
+ private val animatedTaskWidth
+ get() = dragToDesktopAnimator.animatedValue as Float * startBounds.width()
+ private val dragToDesktopAnimator: ValueAnimator = ValueAnimator.ofFloat(1f,
+ DRAG_FREEFORM_SCALE)
+ .setDuration(ANIMATION_DURATION.toLong())
+ .apply {
+ val t = SurfaceControl.Transaction()
+ addUpdateListener { animation ->
+ val animatorValue = animation.animatedValue as Float
+ t.setScale(taskSurface, animatorValue, animatorValue)
+ .apply()
+ }
+ }
+
+ val taskId get() = taskInfo.taskId
+ val position: PointF = PointF(0.0f, 0.0f)
+
+ /**
+ * Starts the animation that scales the task down.
+ */
+ fun startAnimation() {
+ dragToDesktopAnimator.start()
+ }
+
+ /**
+ * Uses the position of the motion event and the current scale of the task as defined by the
+ * ValueAnimator to update the local position variable and set the task surface's position
+ */
+ fun updatePosition(ev: MotionEvent) {
+ position.x = ev.x - animatedTaskWidth / 2
+ position.y = ev.y
+
+ val t = transactionFactory()
+ t.setPosition(taskSurface, position.x, position.y)
+ t.apply()
+ }
+
+ /**
+ * Ends the animation, setting the scale and position to the final animation value
+ */
+ fun endAnimator() {
+ dragToDesktopAnimator.end()
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
index 82771095cd82..bfce72bcadf0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
@@ -102,11 +102,17 @@ public class ResizeVeil {
}
/**
- * Animate veil's alpha to 1, fading it in.
+ * Shows the veil surface/view.
+ *
+ * @param t the transaction to apply in sync with the veil draw
+ * @param parentSurface the surface that the veil should be a child of
+ * @param taskBounds the bounds of the task that owns the veil
+ * @param fadeIn if true, the veil will fade-in with an animation, if false, it will be shown
+ * immediately
*/
- public void showVeil(SurfaceControl parentSurface, Rect taskBounds) {
+ public void showVeil(SurfaceControl.Transaction t, SurfaceControl parentSurface,
+ Rect taskBounds, boolean fadeIn) {
// Parent surface can change, ensure it is up to date.
- SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
if (!parentSurface.equals(mParentSurface)) {
t.reparent(mVeilSurface, parentSurface);
mParentSurface = parentSurface;
@@ -115,22 +121,36 @@ public class ResizeVeil {
int backgroundColorId = getBackgroundColorId();
mViewHost.getView().setBackgroundColor(mContext.getColor(backgroundColorId));
- final ValueAnimator animator = new ValueAnimator();
- animator.setFloatValues(0f, 1f);
- animator.setDuration(RESIZE_ALPHA_DURATION);
- animator.addUpdateListener(animation -> {
- t.setAlpha(mVeilSurface, animator.getAnimatedFraction());
- t.apply();
- });
-
relayout(taskBounds, t);
- t.show(mVeilSurface)
- .addTransactionCommittedListener(mContext.getMainExecutor(), () -> animator.start())
- .setAlpha(mVeilSurface, 0);
+ if (fadeIn) {
+ final ValueAnimator animator = new ValueAnimator();
+ animator.setFloatValues(0f, 1f);
+ animator.setDuration(RESIZE_ALPHA_DURATION);
+ animator.addUpdateListener(animation -> {
+ t.setAlpha(mVeilSurface, animator.getAnimatedFraction());
+ t.apply();
+ });
+
+ t.show(mVeilSurface)
+ .addTransactionCommittedListener(
+ mContext.getMainExecutor(), () -> animator.start())
+ .setAlpha(mVeilSurface, 0);
+ } else {
+ // Show the veil immediately at full opacity.
+ t.show(mVeilSurface).setAlpha(mVeilSurface, 1);
+ }
mViewHost.getView().getViewRootImpl().applyTransactionOnDraw(t);
}
/**
+ * Animate veil's alpha to 1, fading it in.
+ */
+ public void showVeil(SurfaceControl parentSurface, Rect taskBounds) {
+ SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
+ showVeil(t, parentSurface, taskBounds, true /* fadeIn */);
+ }
+
+ /**
* Update veil bounds to match bounds changes.
* @param newBounds bounds to update veil to.
*/
@@ -147,6 +167,16 @@ public class ResizeVeil {
*/
public void updateResizeVeil(Rect newBounds) {
SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
+ updateResizeVeil(t, newBounds);
+ }
+
+ /**
+ * Calls relayout to update task and veil bounds.
+ *
+ * @param t a transaction to be applied in sync with the veil draw.
+ * @param newBounds bounds to update veil to.
+ */
+ public void updateResizeVeil(SurfaceControl.Transaction t, Rect newBounds) {
relayout(newBounds, t);
mViewHost.getView().getViewRootImpl().applyTransactionOnDraw(t);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index 58c78e6a5b9f..c9c58de6e82a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -53,33 +53,33 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
- // If a task move (not resize) finishes in this region, the positioner will not attempt to
+ // If a task move (not resize) finishes with the positions y less than this value, do not
// finalize the bounds there using WCT#setBounds
- private final Rect mDisallowedAreaForEndBounds = new Rect();
+ private final int mDisallowedAreaForEndBoundsHeight;
private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
private int mCtrlType;
public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
DesktopModeWindowDecoration windowDecoration, DisplayController displayController,
- Rect disallowedAreaForEndBounds,
DragPositioningCallbackUtility.DragStartListener dragStartListener,
- Transitions transitions) {
- this(taskOrganizer, windowDecoration, displayController, disallowedAreaForEndBounds,
- dragStartListener, SurfaceControl.Transaction::new, transitions);
+ Transitions transitions,
+ int disallowedAreaForEndBoundsHeight) {
+ this(taskOrganizer, windowDecoration, displayController, dragStartListener,
+ SurfaceControl.Transaction::new, transitions, disallowedAreaForEndBoundsHeight);
}
public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
DesktopModeWindowDecoration windowDecoration, DisplayController displayController,
- Rect disallowedAreaForEndBounds,
DragPositioningCallbackUtility.DragStartListener dragStartListener,
- Supplier<SurfaceControl.Transaction> supplier, Transitions transitions) {
+ Supplier<SurfaceControl.Transaction> supplier, Transitions transitions,
+ int disallowedAreaForEndBoundsHeight) {
mTaskOrganizer = taskOrganizer;
mDesktopWindowDecoration = windowDecoration;
mDisplayController = displayController;
mDragStartListener = dragStartListener;
- mDisallowedAreaForEndBounds.set(disallowedAreaForEndBounds);
mTransactionSupplier = supplier;
mTransitions = transitions;
+ mDisallowedAreaForEndBoundsHeight = disallowedAreaForEndBoundsHeight;
}
@Override
@@ -98,10 +98,14 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
}
mDragStartListener.onDragStart(mDesktopWindowDecoration.mTaskInfo.taskId);
mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
+ if (mStableBounds.isEmpty()) {
+ mDisplayController.getDisplayLayout(mDesktopWindowDecoration.mDisplay.getDisplayId())
+ .getStableBounds(mStableBounds);
+ }
}
@Override
- public void onDragPositioningMove(float x, float y) {
+ public Rect onDragPositioningMove(float x, float y) {
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint);
if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType,
mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
@@ -110,14 +114,14 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
} else if (mCtrlType == CTRL_TYPE_UNDEFINED) {
final SurfaceControl.Transaction t = mTransactionSupplier.get();
DragPositioningCallbackUtility.setPositionOnDrag(mDesktopWindowDecoration,
- mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t,
- x, y);
+ mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y);
t.apply();
}
+ return new Rect(mRepositionTaskBounds);
}
@Override
- public void onDragPositioningEnd(float x, float y) {
+ public Rect onDragPositioningEnd(float x, float y) {
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y,
mRepositionStartPoint);
if (isResizing()) {
@@ -138,9 +142,9 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
// won't be called.
mDesktopWindowDecoration.hideResizeVeil();
}
- } else if (!mDisallowedAreaForEndBounds.contains((int) x, (int) y)) {
- DragPositioningCallbackUtility.updateTaskBounds(mRepositionTaskBounds,
- mTaskBoundsAtDragStart, mRepositionStartPoint, x, y);
+ } else if (y > mDisallowedAreaForEndBoundsHeight) {
+ DragPositioningCallbackUtility.onDragEnd(mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mStableBounds, mRepositionStartPoint, x, y);
DragPositioningCallbackUtility.applyTaskBoundsChange(new WindowContainerTransaction(),
mDesktopWindowDecoration, mRepositionTaskBounds, mTaskOrganizer);
}
@@ -148,6 +152,7 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
mCtrlType = CTRL_TYPE_UNDEFINED;
mTaskBoundsAtDragStart.setEmpty();
mRepositionStartPoint.set(0, 0);
+ return new Rect(mRepositionTaskBounds);
}
private boolean isResizing() {
@@ -163,7 +168,7 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
startTransaction.apply();
mDesktopWindowDecoration.hideResizeVeil();
mCtrlType = CTRL_TYPE_UNDEFINED;
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
index 9f03d9aec166..ae1a3d914be3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
@@ -22,6 +22,7 @@ import android.view.SurfaceControl;
import android.window.TransitionInfo;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
+import com.android.wm.shell.splitscreen.SplitScreenController;
/**
* The interface used by some {@link com.android.wm.shell.ShellTaskOrganizer.TaskListener} to help
@@ -39,6 +40,11 @@ public interface WindowDecorViewModel {
void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter);
/**
+ * Sets the {@link SplitScreenController} if available.
+ */
+ void setSplitScreenController(SplitScreenController splitScreenController);
+
+ /**
* Creates a window decoration for the given task. Can be {@code null} for Fullscreen tasks but
* not Freeform ones.
*
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index ac5ff2075901..0b0d9d5086f4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -64,6 +64,24 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
implements AutoCloseable {
/**
+ * The Z-order of {@link #mCaptionContainerSurface}.
+ * <p>
+ * We use {@link #mDecorationContainerSurface} to define input window for task resizing; by
+ * layering it in front of {@link #mCaptionContainerSurface}, we can allow it to handle input
+ * prior to caption view itself, treating corner inputs as resize events rather than
+ * repositioning.
+ */
+ static final int CAPTION_LAYER_Z_ORDER = -1;
+ /**
+ * The Z-order of the task input sink in {@link DragPositioningCallback}.
+ * <p>
+ * This task input sink is used to prevent undesired dispatching of motion events out of task
+ * bounds; by layering it behind {@link #mCaptionContainerSurface}, we allow captions to handle
+ * input events first.
+ */
+ static final int INPUT_SINK_Z_ORDER = -2;
+
+ /**
* System-wide context. Only used to create context with overridden configurations.
*/
final Context mContext;
@@ -237,7 +255,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
final int captionWidth = taskBounds.width();
+
startT.setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight)
+ .setLayer(mCaptionContainerSurface, CAPTION_LAYER_Z_ORDER)
.show(mCaptionContainerSurface);
if (ViewRootImpl.CAPTION_ON_SHELL) {
@@ -248,6 +268,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight + params.mCaptionY;
wct.addInsetsSource(mTaskInfo.token,
mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect);
+ wct.addInsetsSource(mTaskInfo.token,
+ mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures(),
+ mCaptionInsetsRect);
} else {
startT.hide(mCaptionContainerSurface);
}
@@ -264,6 +287,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
.setColor(mTaskSurface, mTmpColor)
.show(mTaskSurface);
finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
+ .setShadowRadius(mTaskSurface, shadowRadius)
.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
@@ -301,6 +325,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
}
}
+ int getCaptionHeightId() {
+ return Resources.ID_NULL;
+ }
+
/**
* Obtains the {@link Display} instance for the display ID in {@link #mTaskInfo} if it exists or
* registers {@link #mOnDisplaysChangedListener} if it doesn't.
@@ -345,6 +373,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
final WindowContainerTransaction wct = mWindowContainerTransactionSupplier.get();
wct.removeInsetsSource(mTaskInfo.token,
mOwner, 0 /* index */, WindowInsets.Type.captionBar());
+ wct.removeInsetsSource(mTaskInfo.token,
+ mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures());
mTaskOrganizer.applyTransaction(wct);
}
@@ -413,6 +443,21 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
mSurfaceControlTransactionSupplier);
}
+ /**
+ * Adds caption inset source to a WCT
+ */
+ public void addCaptionInset(WindowContainerTransaction wct) {
+ final int captionHeightId = getCaptionHeightId();
+ if (!ViewRootImpl.CAPTION_ON_SHELL || captionHeightId == Resources.ID_NULL) {
+ return;
+ }
+
+ final int captionHeight = loadDimensionPixelSize(mContext.getResources(), captionHeightId);
+ final Rect captionInsets = new Rect(0, 0, 0, captionHeight);
+ wct.addInsetsSource(mTaskInfo.token, mOwner, 0 /* index */, WindowInsets.Type.captionBar(),
+ captionInsets);
+ }
+
static class RelayoutParams {
RunningTaskInfo mRunningTaskInfo;
int mLayoutResId;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
index b67acd5c15bb..672e57aab5ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
@@ -28,6 +28,7 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder(
private val openMenuButton: View = rootView.findViewById(R.id.open_menu_button)
private val closeWindowButton: ImageButton = rootView.findViewById(R.id.close_window)
private val expandMenuButton: ImageButton = rootView.findViewById(R.id.expand_menu_button)
+ private val maximizeWindowButton: ImageButton = rootView.findViewById(R.id.maximize_window)
private val appNameTextView: TextView = rootView.findViewById(R.id.application_name)
private val appIconImageView: ImageView = rootView.findViewById(R.id.application_icon)
@@ -37,6 +38,7 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder(
openMenuButton.setOnClickListener(onCaptionButtonClickListener)
openMenuButton.setOnTouchListener(onCaptionTouchListener)
closeWindowButton.setOnClickListener(onCaptionButtonClickListener)
+ maximizeWindowButton.setOnClickListener(onCaptionButtonClickListener)
closeWindowButton.setOnTouchListener(onCaptionTouchListener)
appNameTextView.text = appName
appIconImageView.setImageDrawable(appIcon)
@@ -49,6 +51,8 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder(
closeWindowButton.imageTintList = ColorStateList.valueOf(
getCaptionCloseButtonColor(taskInfo))
+ maximizeWindowButton.imageTintList = ColorStateList.valueOf(
+ getCaptionMaximizeButtonColor(taskInfo))
expandMenuButton.imageTintList = ColorStateList.valueOf(
getCaptionExpandButtonColor(taskInfo))
appNameTextView.setTextColor(getCaptionAppNameTextColor(taskInfo))
@@ -70,6 +74,14 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder(
}
}
+ private fun getCaptionMaximizeButtonColor(taskInfo: RunningTaskInfo): Int {
+ return if (shouldUseLightCaptionColors(taskInfo)) {
+ context.getColor(R.color.desktop_mode_caption_maximize_button_light)
+ } else {
+ context.getColor(R.color.desktop_mode_caption_maximize_button_dark)
+ }
+ }
+
private fun getCaptionExpandButtonColor(taskInfo: RunningTaskInfo): Int {
return if (shouldUseLightCaptionColors(taskInfo)) {
context.getColor(R.color.desktop_mode_caption_expand_button_light)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt
index 514ea52cb8ae..d293cf73a0f7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt
@@ -1,28 +1,35 @@
package com.android.wm.shell.windowdecor.viewholder
import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.content.Context
import android.graphics.Color
import android.view.View
+import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
/**
* Encapsulates the root [View] of a window decoration and its children to facilitate looking up
* children (via findViewById) and updating to the latest data from [RunningTaskInfo].
*/
internal abstract class DesktopModeWindowDecorationViewHolder(rootView: View) {
- val context: Context = rootView.context
+ val context: Context = rootView.context
- /**
- * A signal to the view holder that new data is available and that the views should be updated
- * to reflect it.
- */
- abstract fun bindData(taskInfo: RunningTaskInfo)
+ /**
+ * A signal to the view holder that new data is available and that the views should be updated to
+ * reflect it.
+ */
+ abstract fun bindData(taskInfo: RunningTaskInfo)
- /**
- * Whether the caption items should use the 'light' color variant so that there's good contrast
- * with the caption background color.
- */
- protected fun shouldUseLightCaptionColors(taskInfo: RunningTaskInfo): Boolean {
- return Color.valueOf(taskInfo.taskDescription.statusBarColor).luminance() < 0.5
+ /**
+ * Whether the caption items should use the 'light' color variant so that there's good contrast
+ * with the caption background color.
+ */
+ protected fun shouldUseLightCaptionColors(taskInfo: RunningTaskInfo): Boolean {
+ return if (Color.alpha(taskInfo.taskDescription.statusBarColor) != 0 &&
+ taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+ Color.valueOf(taskInfo.taskDescription.statusBarColor).luminance() < 0.5
+ } else {
+ taskInfo.taskDescription.statusBarAppearance and APPEARANCE_LIGHT_STATUS_BARS == 0
}
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index b6696c70dbb1..dfbadae2b853 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -23,14 +23,84 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
-android_test {
- name: "WMShellFlickerTests",
+filegroup {
+ name: "WMShellFlickerTestsUtils-src",
+ srcs: ["src/com/android/wm/shell/flicker/utils/*.kt"],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsBase-src",
+ srcs: ["src/com/android/wm/shell/flicker/*.kt"],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsBubbles-src",
+ srcs: ["src/com/android/wm/shell/flicker/bubble/*.kt"],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsPip-src",
+ srcs: ["src/com/android/wm/shell/flicker/pip/*.kt"],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsSplitScreenBase-src",
srcs: [
- "src/**/*.java",
- "src/**/*.kt",
+ "src/com/android/wm/shell/flicker/splitscreen/benchmark/*.kt",
+ ],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsSplitScreenGroup1-src",
+ srcs: [
+ "src/com/android/wm/shell/flicker/splitscreen/A*.kt",
+ "src/com/android/wm/shell/flicker/splitscreen/B*.kt",
+ "src/com/android/wm/shell/flicker/splitscreen/C*.kt",
+ "src/com/android/wm/shell/flicker/splitscreen/D*.kt",
+ "src/com/android/wm/shell/flicker/splitscreen/E*.kt",
+ ],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsSplitScreenGroup2-src",
+ srcs: [
+ "src/com/android/wm/shell/flicker/splitscreen/*.kt",
+ ],
+}
+
+filegroup {
+ name: "WMShellFlickerServiceTests-src",
+ srcs: [
+ "src/com/android/wm/shell/flicker/service/**/*.kt",
+ ],
+}
+
+java_library {
+ name: "wm-shell-flicker-utils",
+ platform_apis: true,
+ optimize: {
+ enabled: false,
+ },
+ srcs: [
+ ":WMShellFlickerTestsUtils-src",
+ ],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "flickertestapplib",
+ "flickerlib",
+ "flickerlib-helpers",
+ "platform-test-annotations",
+ "wm-flicker-common-app-helpers",
+ "wm-flicker-common-assertions",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl",
],
- manifest: "AndroidManifest.xml",
- test_config: "AndroidTest.xml",
+}
+
+java_defaults {
+ name: "WMShellFlickerTestsDefault",
+ manifest: "manifests/AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
platform_apis: true,
certificate: "platform",
optimize: {
@@ -39,17 +109,104 @@ android_test {
test_suites: ["device-tests"],
libs: ["android.test.runner"],
static_libs: [
+ "wm-shell-flicker-utils",
"androidx.test.ext.junit",
+ "flickertestapplib",
"flickerlib",
- "flickerlib-apphelpers",
"flickerlib-helpers",
- "truth-prebuilt",
- "app-helpers-core",
+ "platform-test-annotations",
+ "wm-flicker-common-app-helpers",
+ "wm-flicker-common-assertions",
"launcher-helper-lib",
"launcher-aosp-tapl",
- "wm-flicker-common-assertions",
- "wm-flicker-common-app-helpers",
- "platform-test-annotations",
- "flickertestapplib",
+ ],
+ data: [
+ ":FlickerTestApp",
+ "trace_config/*",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsOther",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestOther.xml"],
+ package_name: "com.android.wm.shell.flicker",
+ instrumentation_target_package: "com.android.wm.shell.flicker",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ exclude_srcs: [
+ ":WMShellFlickerTestsBubbles-src",
+ ":WMShellFlickerTestsPip-src",
+ ":WMShellFlickerTestsSplitScreenGroup1-src",
+ ":WMShellFlickerTestsSplitScreenGroup2-src",
+ ":WMShellFlickerTestsSplitScreenBase-src",
+ ":WMShellFlickerServiceTests-src",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsBubbles",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestBubbles.xml"],
+ package_name: "com.android.wm.shell.flicker.bubbles",
+ instrumentation_target_package: "com.android.wm.shell.flicker.bubbles",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerTestsBubbles-src",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsPip",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestPip.xml"],
+ package_name: "com.android.wm.shell.flicker.pip",
+ instrumentation_target_package: "com.android.wm.shell.flicker.pip",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerTestsPip-src",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsSplitScreenGroup1",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestSplitScreen.xml"],
+ package_name: "com.android.wm.shell.flicker.splitscreen",
+ instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerTestsSplitScreenBase-src",
+ ":WMShellFlickerTestsSplitScreenGroup1-src",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsSplitScreenGroup2",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestSplitScreen.xml"],
+ package_name: "com.android.wm.shell.flicker.splitscreen",
+ instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerTestsSplitScreenBase-src",
+ ":WMShellFlickerTestsSplitScreenGroup2-src",
+ ],
+ exclude_srcs: [
+ ":WMShellFlickerTestsSplitScreenGroup1-src",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerServiceTests",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestService.xml"],
+ package_name: "com.android.wm.shell.flicker.service",
+ instrumentation_target_package: "com.android.wm.shell.flicker.service",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerServiceTests-src",
],
}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
deleted file mode 100644
index b5937ae80f0a..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright 2020 Google Inc. All Rights Reserved.
- -->
-<configuration description="Runs WindowManager Shell Flicker Tests">
- <option name="test-tag" value="FlickerTests" />
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <!-- keeps the screen on during tests -->
- <option name="screen-always-on" value="on" />
- <!-- prevents the phone from restarting -->
- <option name="force-skip-system-props" value="true" />
- <!-- set WM tracing verbose level to all -->
- <option name="run-command" value="cmd window tracing level all" />
- <!-- set WM tracing to frame (avoid incomplete states) -->
- <option name="run-command" value="cmd window tracing frame" />
- <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
- <option name="run-command" value="pm disable com.google.android.internal.betterbug" />
- <!-- ensure lock screen mode is swipe -->
- <option name="run-command" value="locksettings set-disabled false" />
- <!-- restart launcher to activate TAPL -->
- <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
- <!-- Ensure output directory is empty at the start -->
- <option name="run-command" value="rm -rf /sdcard/flicker" />
- <!-- Increase trace size: 20mb for WM and 80mb for SF -->
- <option name="run-command" value="cmd window tracing size 20480" />
- <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
- <option name="run-command" value="settings put system show_touches 1" />
- <option name="run-command" value="settings put system pointer_location 1" />
- <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" />
- <option name="teardown-command" value="settings delete system show_touches" />
- <option name="teardown-command" value="settings delete system pointer_location" />
- <option name="teardown-command" value="cmd overlay enable com.android.internal.systemui.navbar.gestural" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true"/>
- <option name="test-file-name" value="WMShellFlickerTests.apk"/>
- <option name="test-file-name" value="FlickerTestApp.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest">
- <option name="package" value="com.android.wm.shell.flicker"/>
- <option name="shell-timeout" value="6600s" />
- <option name="test-timeout" value="6000s" />
- <option name="hidden-api-checks" value="false" />
- </test>
- <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="directory-keys" value="/sdcard/flicker" />
- <option name="collect-on-run-ended-only" value="true" />
- <option name="clean-up" value="true" />
- </metrics_collector>
-</configuration>
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
new file mode 100644
index 000000000000..87b20ed6305e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}">
+ <option name="test-tag" value="FlickerTests"/>
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on"/>
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true"/>
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all"/>
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame"/>
+ <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
+ <option name="run-command" value="pm disable com.google.android.internal.betterbug"/>
+ <!-- ensure lock screen mode is swipe -->
+ <option name="run-command" value="locksettings set-disabled false"/>
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command"
+ value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/>
+ <!-- Increase trace size: 20mb for WM and 80mb for SF -->
+ <option name="run-command" value="cmd window tracing size 20480"/>
+ <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/>
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="test-user-token" value="%TEST_USER%"/>
+ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
+ <option name="run-command" value="settings put system show_touches 1"/>
+ <option name="run-command" value="settings put system pointer_location 1"/>
+ <option name="teardown-command"
+ value="settings delete secure show_ime_with_hard_keyboard"/>
+ <option name="teardown-command" value="settings delete system show_touches"/>
+ <option name="teardown-command" value="settings delete system pointer_location"/>
+ <option name="teardown-command"
+ value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/>
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="{MODULE}.apk"/>
+ <option name="test-file-name" value="FlickerTestApp.apk"/>
+ </target_preparer>
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file"
+ key="trace_config.textproto"
+ value="/data/misc/perfetto-traces/trace_config.textproto"
+ />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="{PACKAGE}"/>
+ <option name="shell-timeout" value="6600s"/>
+ <option name="test-timeout" value="6000s"/>
+ <option name="hidden-api-checks" value="false"/>
+ <option name="device-listeners" value="android.device.collectors.PerfettoListener"/>
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/>
+ <option name="instrumentation-arg"
+ key="perfetto_config_file"
+ value="trace_config.textproto"
+ />
+ <option name="instrumentation-arg" key="per_run" value="true"/>
+ </test>
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker.pip/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.server.wm.flicker.service/files"/>
+ <option name="collect-on-run-ended-only" value="true"/>
+ <option name="clean-up" value="true"/>
+ </metrics_collector>
+</configuration>
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
index 4721741611cf..6a87de47def4 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
@@ -15,6 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="com.android.wm.shell.flicker">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
@@ -57,10 +58,11 @@
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
- </application>
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.wm.shell.flicker"
- android:label="WindowManager Shell Flicker Tests">
- </instrumentation>
+ <!-- (b/197936012) Remove startup provider due to test timeout issue -->
+ <provider
+ android:name="androidx.startup.InitializationProvider"
+ android:authorities="${applicationId}.androidx-startup"
+ tools:node="remove" />
+ </application>
</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestBubbles.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestBubbles.xml
new file mode 100644
index 000000000000..437871f1bb8f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestBubbles.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.bubble">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker.bubble"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestOther.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestOther.xml
new file mode 100644
index 000000000000..cf642f63a41d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestOther.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml
new file mode 100644
index 000000000000..5a8155a66d30
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.pip">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker.pip"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestService.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestService.xml
new file mode 100644
index 000000000000..c7aca1a72696
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestService.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.service">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker.service"
+ android:label="WindowManager Flicker Service Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestSplitScreen.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestSplitScreen.xml
new file mode 100644
index 000000000000..887d8db3042f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestSplitScreen.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.splitscreen">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker.splitscreen"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
index e06e074ee98a..0f3e0f5ef043 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
@@ -19,14 +19,14 @@ package com.android.wm.shell.flicker
import android.app.Instrumentation
import android.tools.device.flicker.junit.FlickerBuilderProvider
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
abstract class BaseBenchmarkTest
@JvmOverloads
constructor(
- protected open val flicker: FlickerTest,
+ protected open val flicker: LegacyFlickerTest,
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
index c98c5a0ad1a6..735fbfb341f5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
@@ -18,9 +18,10 @@ package com.android.wm.shell.flicker
import android.app.Instrumentation
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.utils.ICommonAssertions
/**
* Base test class containing common assertions for [ComponentNameMatcher.NAV_BAR],
@@ -30,7 +31,7 @@ import com.android.launcher3.tapl.LauncherInstrumentation
abstract class BaseTest
@JvmOverloads
constructor(
- override val flicker: FlickerTest,
+ override val flicker: LegacyFlickerTest,
instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
tapl: LauncherInstrumentation = LauncherInstrumentation()
) : BaseBenchmarkTest(flicker, instrumentation, tapl), ICommonAssertions
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index 61781565270b..77f14f1b66a3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -17,28 +17,26 @@
package com.android.wm.shell.flicker.appcompat
import android.content.Context
-import android.system.helpers.CommandsHelper
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import com.android.server.wm.flicker.helpers.setRotation
+import android.tools.device.flicker.legacy.FlickerTestData
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.helpers.LetterboxAppHelper
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import android.tools.device.flicker.legacy.IFlickerTestData
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.wm.shell.flicker.BaseTest
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.layerKeepVisible
-import org.junit.After
+import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtStart
+import com.android.wm.shell.flicker.utils.appWindowKeepVisible
+import com.android.wm.shell.flicker.utils.layerKeepVisible
import org.junit.Assume
import org.junit.Before
-import org.junit.runners.Parameterized
+import org.junit.Rule
-abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class BaseAppCompat(flicker: LegacyFlickerTest) : BaseTest(flicker) {
protected val context: Context = instrumentation.context
protected val letterboxApp = LetterboxAppHelper(instrumentation)
- lateinit var cmdHelper: CommandsHelper
- private lateinit var letterboxStyle: HashMap<String, String>
+
+ @JvmField @Rule val letterboxRule: LetterboxRule = LetterboxRule()
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -48,62 +46,17 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
letterboxApp.launchViaIntent(wmHelper)
setEndRotation()
}
- teardown {
- letterboxApp.exit(wmHelper)
- }
+ teardown { letterboxApp.exit(wmHelper) }
}
@Before
fun before() {
- cmdHelper = CommandsHelper.getInstance(instrumentation)
- Assume.assumeTrue(tapl.isTablet && isIgnoreOrientationRequest())
- letterboxStyle = mapLetterboxStyle()
- setLetterboxEducationEnabled(false)
- }
-
- @After
- fun after() {
- resetLetterboxEducationEnabled()
- }
-
- private fun mapLetterboxStyle(): HashMap<String, String> {
- val res = cmdHelper.executeShellCommand("wm get-letterbox-style")
- val lines = res.lines()
- val map = HashMap<String, String>()
- for (line in lines) {
- val keyValuePair = line.split(":")
- if (keyValuePair.size == 2) {
- val key = keyValuePair[0].trim()
- map[key] = keyValuePair[1].trim()
- }
- }
- return map
- }
-
- private fun getLetterboxStyle(): HashMap<String, String> {
- if (!::letterboxStyle.isInitialized) {
- letterboxStyle = mapLetterboxStyle()
- }
- return letterboxStyle
- }
-
- private fun resetLetterboxEducationEnabled() {
- val enabled = getLetterboxStyle().getValue("Is education enabled")
- cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
- }
-
- private fun setLetterboxEducationEnabled(enabled: Boolean) {
- cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
- }
-
- private fun isIgnoreOrientationRequest(): Boolean {
- val res = cmdHelper.executeShellCommand("wm get-ignore-orientation-request")
- return res != null && res.contains("true")
+ Assume.assumeTrue(tapl.isTablet && letterboxRule.isIgnoreOrientationRequest)
}
- fun IFlickerTestData.setStartRotation() = setRotation(flicker.scenario.startRotation)
+ fun FlickerTestData.setStartRotation() = setRotation(flicker.scenario.startRotation)
- fun IFlickerTestData.setEndRotation() = setRotation(flicker.scenario.endRotation)
+ fun FlickerTestData.setEndRotation() = setRotation(flicker.scenario.endRotation)
/** Checks that app entering letterboxed state have rounded corners */
fun assertLetterboxAppAtStartHasRoundedCorners() {
@@ -118,7 +71,7 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
/** Only run on tests with config_letterboxActivityCornersRadius != 0 in devices */
private fun assumeLetterboxRoundedCornersEnabled() {
- Assume.assumeTrue(getLetterboxStyle().getValue("Corner radius") != "0")
+ Assume.assumeTrue(letterboxRule.hasCornerRadius)
}
fun assertLetterboxAppVisibleAtStartAndEnd() {
@@ -126,25 +79,21 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
flicker.appWindowIsVisibleAtEnd(letterboxApp)
}
+ fun assertLetterboxAppKeepVisible() {
+ assertLetterboxAppWindowKeepVisible()
+ assertLetterboxAppLayerKeepVisible()
+ }
+
fun assertAppLetterboxedAtEnd() =
- flicker.assertLayersEnd { isVisible(ComponentNameMatcher.LETTERBOX) }
+ flicker.assertLayersEnd { isVisible(ComponentNameMatcher.LETTERBOX) }
fun assertAppLetterboxedAtStart() =
- flicker.assertLayersStart { isVisible(ComponentNameMatcher.LETTERBOX) }
+ flicker.assertLayersStart { isVisible(ComponentNameMatcher.LETTERBOX) }
+
+ fun assertAppStaysLetterboxed() =
+ flicker.assertLayers { isVisible(ComponentNameMatcher.LETTERBOX) }
fun assertLetterboxAppLayerKeepVisible() = flicker.layerKeepVisible(letterboxApp)
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
- }
- }
+ fun assertLetterboxAppWindowKeepVisible() = flicker.appWindowKeepVisible(letterboxApp)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt
new file mode 100644
index 000000000000..744e8c2eb06f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 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.flicker.appcompat
+
+import android.app.Instrumentation
+import android.system.helpers.CommandsHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/** JUnit Rule to handle letterboxStyles and states */
+class LetterboxRule(
+ private val withLetterboxEducationEnabled: Boolean = false,
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
+ private val cmdHelper: CommandsHelper = CommandsHelper.getInstance(instrumentation)
+) : TestRule {
+
+ private val execAdb: (String) -> String = { cmd -> cmdHelper.executeShellCommand(cmd) }
+ private lateinit var _letterboxStyle: MutableMap<String, String>
+
+ val letterboxStyle: Map<String, String>
+ get() {
+ if (!::_letterboxStyle.isInitialized) {
+ _letterboxStyle = mapLetterboxStyle()
+ }
+ return _letterboxStyle
+ }
+
+ val cornerRadius: Int?
+ get() = asInt(letterboxStyle["Corner radius"])
+
+ val hasCornerRadius: Boolean
+ get() {
+ val radius = cornerRadius
+ return radius != null && radius > 0
+ }
+
+ val isIgnoreOrientationRequest: Boolean
+ get() = execAdb("wm get-ignore-orientation-request")?.contains("true") ?: false
+
+ override fun apply(base: Statement?, description: Description?): Statement {
+ resetLetterboxStyle()
+ _letterboxStyle = mapLetterboxStyle()
+ val isLetterboxEducationEnabled = _letterboxStyle.getValue("Is education enabled")
+ var hasLetterboxEducationStateChanged = false
+ if ("$withLetterboxEducationEnabled" != isLetterboxEducationEnabled) {
+ hasLetterboxEducationStateChanged = true
+ execAdb("wm set-letterbox-style --isEducationEnabled " + withLetterboxEducationEnabled)
+ }
+ return try {
+ object : Statement() {
+ @Throws(Throwable::class)
+ override fun evaluate() {
+ base!!.evaluate()
+ }
+ }
+ } finally {
+ if (hasLetterboxEducationStateChanged) {
+ execAdb(
+ "wm set-letterbox-style --isEducationEnabled " + isLetterboxEducationEnabled
+ )
+ }
+ resetLetterboxStyle()
+ }
+ }
+
+ private fun mapLetterboxStyle(): HashMap<String, String> {
+ val res = execAdb("wm get-letterbox-style")
+ val lines = res.lines()
+ val map = HashMap<String, String>()
+ for (line in lines) {
+ val keyValuePair = line.split(":")
+ if (keyValuePair.size == 2) {
+ val key = keyValuePair[0].trim()
+ map[key] = keyValuePair[1].trim()
+ }
+ }
+ return map
+ }
+
+ private fun resetLetterboxStyle() {
+ execAdb("wm reset-letterbox-style")
+ }
+
+ private fun asInt(str: String?): Int? =
+ try {
+ str?.toInt()
+ } catch (e: NumberFormatException) {
+ null
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index c2141a370f10..1e5e42fb077e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -17,10 +17,12 @@
package com.android.wm.shell.flicker.appcompat
import android.platform.test.annotations.Postsubmit
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.Test
import org.junit.runner.RunWith
@@ -29,7 +31,7 @@ import org.junit.runners.Parameterized
/**
* Test launching app in size compat mode.
*
- * To run this test: `atest WMShellFlickerTests:OpenAppInSizeCompatModeTest`
+ * To run this test: `atest WMShellFlickerTestsOther:OpenAppInSizeCompatModeTest`
*
* Actions:
* ```
@@ -45,7 +47,7 @@ import org.junit.runners.Parameterized
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class OpenAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
+class OpenAppInSizeCompatModeTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -64,15 +66,14 @@ class OpenAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker)
*/
@Postsubmit
@Test
- fun letterboxAppFocusedAtEnd() = flicker.assertEventLog { focusChanges(letterboxApp.`package`) }
+ fun letterboxAppFocusedAtEnd() =
+ flicker.assertEventLog { focusChanges(letterboxApp.packageName) }
@Postsubmit
@Test
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
- @Postsubmit
- @Test
- fun appIsLetterboxedAtEnd() = assertAppLetterboxedAtEnd()
+ @Postsubmit @Test fun appIsLetterboxedAtEnd() = assertAppLetterboxedAtEnd()
/**
* Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
@@ -90,4 +91,18 @@ class OpenAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker)
.isInvisible(ComponentNameMatcher.ROTATION)
}
}
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.rotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return LegacyFlickerTestFactory.rotationTests()
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
new file mode 100644
index 000000000000..2fa1ec386781
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2023 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.flicker.appcompat
+
+import android.platform.test.annotations.Postsubmit
+import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching app in size compat mode.
+ *
+ * To run this test: `atest WMShellFlickerTestsOther:OpenTransparentActivityTest`
+ *
+ * Actions:
+ * ```
+ * Launch a letteboxed app and then a transparent activity from it. We test the bounds
+ * are the same.
+ * ```
+ *
+ * Notes:
+ * ```
+ * Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [BaseTest]
+ * ```
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+class OpenTransparentActivityTest(flicker: LegacyFlickerTest) : TransparentBaseAppCompat(flicker) {
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { letterboxTranslucentLauncherApp.launchViaIntent(wmHelper) }
+ transitions {
+ waitAndGetLaunchTransparent()?.click() ?: error("Launch Transparent not found")
+ }
+ teardown {
+ letterboxTranslucentApp.exit(wmHelper)
+ letterboxTranslucentLauncherApp.exit(wmHelper)
+ }
+ }
+
+ /** Checks the transparent activity is launched on top of the opaque one */
+ @Postsubmit
+ @Test
+ fun translucentActivityIsLaunchedOnTopOfOpaqueActivity() {
+ flicker.assertWm {
+ this.isAppWindowOnTop(letterboxTranslucentLauncherApp)
+ .then()
+ .isAppWindowOnTop(letterboxTranslucentApp)
+ }
+ }
+
+ /** Checks that the activity is letterboxed */
+ @Postsubmit
+ @Test
+ fun translucentActivityIsLetterboxed() {
+ flicker.assertLayers { isVisible(ComponentNameMatcher.LETTERBOX) }
+ }
+
+ /** Checks that the translucent activity inherits bounds from the opaque one. */
+ @Postsubmit
+ @Test
+ fun translucentActivityInheritsBoundsFromOpaqueActivity() {
+ flicker.assertLayersEnd {
+ this.visibleRegion(letterboxTranslucentApp)
+ .coversExactly(visibleRegion(letterboxTranslucentLauncherApp).region)
+ }
+ }
+
+ /** Checks that the translucent activity has rounded corners */
+ @Postsubmit
+ @Test
+ fun translucentActivityHasRoundedCorners() {
+ flicker.assertLayersEnd { this.hasRoundedCorners(letterboxTranslucentApp) }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation
+ * modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return LegacyFlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(Rotation.ROTATION_90)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
new file mode 100644
index 000000000000..b74aa1d7bf73
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2023 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.flicker.appcompat
+
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.RequiresDevice
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.datatypes.Rect
+import android.tools.common.flicker.assertions.FlickerTest
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switching to letterboxed app from launcher
+ *
+ * To run this test: `atest WMShellFlickerTestsOther:QuickSwitchLauncherToLetterboxAppTest`
+ *
+ * Actions:
+ * ```
+ * Launch a letterboxed app
+ * Navigate home to show launcher
+ * Swipe right from the bottom of the screen to quick switch back to the app
+ * ```
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class QuickSwitchLauncherToLetterboxAppTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) {
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.setExpectedRotationCheckEnabled(false)
+
+ tapl.setExpectedRotation(flicker.scenario.startRotation.value)
+
+ letterboxApp.launchViaIntent(wmHelper)
+ tapl.goHome()
+ wmHelper
+ .StateSyncBuilder()
+ .withHomeActivityVisible()
+ .withWindowSurfaceDisappeared(letterboxApp)
+ .waitForAndVerify()
+
+ startDisplayBounds =
+ wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
+ }
+ transitions {
+ tapl.workspace.quickSwitchToPreviousApp()
+ wmHelper
+ .StateSyncBuilder()
+ .withFullScreenApp(letterboxApp)
+ .withNavOrTaskBarVisible()
+ .withStatusBarVisible()
+ .waitForAndVerify()
+ }
+ teardown { letterboxApp.exit(wmHelper) }
+ }
+
+ /**
+ * Checks that [letterboxApp] is the top window at the end of the transition once we have fully
+ * quick switched from the launcher back to the [letterboxApp].
+ */
+ @Postsubmit
+ @Test
+ fun endsWithAppBeingOnTop() {
+ flicker.assertWmEnd { this.isAppWindowOnTop(letterboxApp) }
+ }
+
+ /** Checks that the transition starts with the home activity being tagged as visible. */
+ @Postsubmit
+ @Test
+ fun startsWithHomeActivityFlaggedVisible() {
+ flicker.assertWmStart { this.isHomeActivityVisible() }
+ }
+
+ /**
+ * Checks that the transition starts with the [ComponentNameMatcher.LAUNCHER] windows
+ * filling/covering exactly display size
+ */
+ @Postsubmit
+ @Test
+ fun startsWithLauncherWindowsCoverFullScreen() {
+ flicker.assertWmStart {
+ this.visibleRegion(ComponentNameMatcher.LAUNCHER).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that the transition starts with the [ComponentNameMatcher.LAUNCHER] layers
+ * filling/covering exactly the display size.
+ */
+ @Postsubmit
+ @Test
+ fun startsWithLauncherLayersCoverFullScreen() {
+ flicker.assertLayersStart {
+ this.visibleRegion(ComponentNameMatcher.LAUNCHER).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that the transition starts with the [ComponentNameMatcher.LAUNCHER] being the top
+ * window.
+ */
+ @Postsubmit
+ @Test
+ fun startsWithLauncherBeingOnTop() {
+ flicker.assertWmStart { this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER) }
+ }
+
+ /**
+ * Checks that the transition ends with the home activity being flagged as not visible. By this
+ * point we should have quick switched away from the launcher back to the [letterboxApp].
+ */
+ @Postsubmit
+ @Test
+ fun endsWithHomeActivityFlaggedInvisible() {
+ flicker.assertWmEnd { this.isHomeActivityInvisible() }
+ }
+
+ /**
+ * Checks that [letterboxApp]'s window starts off invisible and becomes visible at some point
+ * before the end of the transition and then stays visible until the end of the transition.
+ */
+ @Postsubmit
+ @Test
+ fun appWindowBecomesAndStaysVisible() {
+ flicker.assertWm {
+ this.isAppWindowInvisible(letterboxApp).then().isAppWindowVisible(letterboxApp)
+ }
+ }
+
+ /**
+ * Checks that [letterboxApp]'s layer starts off invisible and becomes visible at some point
+ * before the end of the transition and then stays visible until the end of the transition.
+ */
+ @Postsubmit
+ @Test
+ fun appLayerBecomesAndStaysVisible() {
+ flicker.assertLayers { this.isInvisible(letterboxApp).then().isVisible(letterboxApp) }
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.LAUNCHER] window starts off visible and becomes
+ * invisible at some point before the end of the transition and then stays invisible until the
+ * end of the transition.
+ */
+ @Postsubmit
+ @Test
+ fun launcherWindowBecomesAndStaysInvisible() {
+ flicker.assertWm {
+ this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
+ .then()
+ .isAppWindowNotOnTop(ComponentNameMatcher.LAUNCHER)
+ }
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.LAUNCHER] layer starts off visible and becomes
+ * invisible at some point before the end of the transition and then stays invisible until the
+ * end of the transition.
+ */
+ @Postsubmit
+ @Test
+ fun launcherLayerBecomesAndStaysInvisible() {
+ flicker.assertLayers {
+ this.isVisible(ComponentNameMatcher.LAUNCHER)
+ .then()
+ .isInvisible(ComponentNameMatcher.LAUNCHER)
+ }
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.LAUNCHER] window is visible at least until the app
+ * window is visible. Ensures that at any point, either the launcher or [letterboxApp] windows
+ * are at least partially visible.
+ */
+ @Postsubmit
+ @Test
+ fun appWindowIsVisibleOnceLauncherWindowIsInvisible() {
+ flicker.assertWm {
+ this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
+ .then()
+ .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
+ .then()
+ .isAppWindowVisible(letterboxApp)
+ }
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.LAUNCHER] layer is visible at least until the app layer
+ * is visible. Ensures that at any point, either the launcher or [letterboxApp] layers are at
+ * least partially visible.
+ */
+ @Postsubmit
+ @Test
+ fun appLayerIsVisibleOnceLauncherLayerIsInvisible() {
+ flicker.assertLayers {
+ this.isVisible(ComponentNameMatcher.LAUNCHER)
+ .then()
+ .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
+ .then()
+ .isVisible(letterboxApp)
+ }
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.LETTERBOX] layer is visible as soon as the
+ * [letterboxApp] layer is visible at the end of the transition once we have fully quick
+ * switched from the launcher back to the [letterboxApp].
+ */
+ @Postsubmit
+ @Test
+ fun appAndLetterboxLayersBothVisibleOnceLauncherIsInvisible() {
+ flicker.assertLayers {
+ this.isVisible(ComponentNameMatcher.LAUNCHER)
+ .then()
+ .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
+ .then()
+ .isVisible(letterboxApp)
+ .isVisible(ComponentNameMatcher.LETTERBOX)
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Postsubmit
+ @Test
+ override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
+
+ /** {@inheritDoc} */
+ @Postsubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ companion object {
+ /** {@inheritDoc} */
+ private var startDisplayBounds = Rect.EMPTY
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return LegacyFlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL),
+ supportedRotations = listOf(Rotation.ROTATION_90)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
new file mode 100644
index 000000000000..68fa8d2fc2e8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 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.flicker.appcompat
+
+import android.platform.test.annotations.Postsubmit
+import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.device.helpers.WindowUtils
+import androidx.test.filters.RequiresDevice
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching a fixed portrait letterboxed app in landscape and repositioning to the right.
+ *
+ * To run this test: `atest WMShellFlickerTestsOther:RepositionFixedPortraitAppTest`
+ *
+ * Actions:
+ *
+ * ```
+ * Launch a fixed portrait app in landscape to letterbox app
+ * Double tap to the right to reposition app and wait for app to move
+ * ```
+ *
+ * Notes:
+ *
+ * ```
+ * Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [BaseTest]
+ * ```
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+class RepositionFixedPortraitAppTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) {
+
+ val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation).bounds
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ setStartRotation()
+ letterboxApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ letterboxApp.repositionHorizontally(displayBounds, true)
+ letterboxApp.waitForAppToMoveHorizontallyTo(wmHelper, displayBounds, true)
+ }
+ teardown {
+ letterboxApp.repositionHorizontally(displayBounds, false)
+ letterboxApp.exit(wmHelper)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
+
+ @Postsubmit @Test fun letterboxAppLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
+
+ @Postsubmit @Test fun appStaysLetterboxed() = assertAppStaysLetterboxed()
+
+ @Postsubmit @Test fun appKeepVisible() = assertLetterboxAppKeepVisible()
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return LegacyFlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(Rotation.ROTATION_90)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index b0e1a42306df..fcb6931af9a2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -17,9 +17,11 @@
package com.android.wm.shell.flicker.appcompat
import android.platform.test.annotations.Postsubmit
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import org.junit.Test
@@ -29,7 +31,7 @@ import org.junit.runners.Parameterized
/**
* Test restarting app in size compat mode.
*
- * To run this test: `atest WMShellFlickerTests:RestartAppInSizeCompatModeTest`
+ * To run this test: `atest WMShellFlickerTestsOther:RestartAppInSizeCompatModeTest`
*
* Actions:
* ```
@@ -46,7 +48,7 @@ import org.junit.runners.Parameterized
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
+class RestartAppInSizeCompatModeTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -69,13 +71,9 @@ class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flick
}
}
- @Postsubmit
- @Test
- fun appLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
+ @Postsubmit @Test fun appLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
- @Postsubmit
- @Test
- fun appIsLetterboxedAtStart() = assertAppLetterboxedAtStart()
+ @Postsubmit @Test fun appIsLetterboxedAtStart() = assertAppLetterboxedAtStart()
@Postsubmit
@Test
@@ -88,4 +86,18 @@ class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flick
val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
flicker.assertLayersEnd { visibleRegion(letterboxApp).coversAtMost(displayBounds) }
}
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.rotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return LegacyFlickerTestFactory.rotationTests()
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt
new file mode 100644
index 000000000000..9792c859cced
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.flicker.appcompat
+
+import android.content.Context
+import android.tools.device.flicker.legacy.FlickerTestData
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.helpers.FIND_TIMEOUT
+import android.tools.device.traces.parsers.toFlickerComponent
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.LetterboxAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.flicker.BaseTest
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Rule
+
+abstract class TransparentBaseAppCompat(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+ protected val context: Context = instrumentation.context
+ protected val letterboxTranslucentLauncherApp =
+ LetterboxAppHelper(
+ instrumentation,
+ launcherName = ActivityOptions.LaunchTransparentActivity.LABEL,
+ component = ActivityOptions.LaunchTransparentActivity.COMPONENT.toFlickerComponent()
+ )
+ protected val letterboxTranslucentApp =
+ LetterboxAppHelper(
+ instrumentation,
+ launcherName = ActivityOptions.TransparentActivity.LABEL,
+ component = ActivityOptions.TransparentActivity.COMPONENT.toFlickerComponent()
+ )
+
+ @JvmField @Rule val letterboxRule: LetterboxRule = LetterboxRule()
+
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet && letterboxRule.isIgnoreOrientationRequest)
+ }
+
+ protected fun FlickerTestData.waitAndGetLaunchTransparent(): UiObject2? =
+ device.wait(Until.findObject(By.text("Launch Transparent")), FIND_TIMEOUT)
+
+ protected fun FlickerTestData.goBack() = device.pressBack()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index bab81d79c804..97147a3e1672 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -23,9 +23,9 @@ import android.content.pm.PackageManager
import android.os.ServiceManager
import android.tools.common.Rotation
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import android.tools.device.flicker.legacy.IFlickerTestData
+import android.tools.device.flicker.legacy.FlickerTestData
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.SYSTEMUI_PACKAGE
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiObject2
@@ -35,7 +35,7 @@ import com.android.wm.shell.flicker.BaseTest
import org.junit.runners.Parameterized
/** Base configurations for Bubble flicker tests */
-abstract class BaseBubbleScreen(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class BaseBubbleScreen(flicker: LegacyFlickerTest) : BaseTest(flicker) {
protected val context: Context = instrumentation.context
protected val testApp = LaunchBubbleHelper(instrumentation)
@@ -47,7 +47,7 @@ abstract class BaseBubbleScreen(flicker: FlickerTest) : BaseTest(flicker) {
private val uid =
context.packageManager
- .getApplicationInfo(testApp.`package`, PackageManager.ApplicationInfoFlags.of(0))
+ .getApplicationInfo(testApp.packageName, PackageManager.ApplicationInfoFlags.of(0))
.uid
@JvmOverloads
@@ -57,7 +57,7 @@ abstract class BaseBubbleScreen(flicker: FlickerTest) : BaseTest(flicker) {
return {
setup {
notifyManager.setBubblesAllowed(
- testApp.`package`,
+ testApp.packageName,
uid,
NotificationManager.BUBBLE_PREFERENCE_ALL
)
@@ -68,32 +68,35 @@ abstract class BaseBubbleScreen(flicker: FlickerTest) : BaseTest(flicker) {
teardown {
notifyManager.setBubblesAllowed(
- testApp.`package`,
+ testApp.packageName,
uid,
NotificationManager.BUBBLE_PREFERENCE_NONE
)
- testApp.exit()
+ device.wait(
+ Until.gone(By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)),
+ FIND_OBJECT_TIMEOUT
+ )
+ testApp.exit(wmHelper)
}
extraSpec(this)
}
}
- protected fun IFlickerTestData.waitAndGetAddBubbleBtn(): UiObject2? =
+ protected fun FlickerTestData.waitAndGetAddBubbleBtn(): UiObject2? =
device.wait(Until.findObject(By.text("Add Bubble")), FIND_OBJECT_TIMEOUT)
- protected fun IFlickerTestData.waitAndGetCancelAllBtn(): UiObject2? =
+ protected fun FlickerTestData.waitAndGetCancelAllBtn(): UiObject2? =
device.wait(Until.findObject(By.text("Cancel All Bubble")), FIND_OBJECT_TIMEOUT)
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
- const val FIND_OBJECT_TIMEOUT = 2000L
+ const val FIND_OBJECT_TIMEOUT = 4000L
const val SYSTEM_UI_PACKAGE = SYSTEMUI_PACKAGE
const val BUBBLE_RES_NAME = "bubble_view"
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
index 2474ecf74cf9..9cc9fb94353d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
@@ -21,8 +21,7 @@ import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
@@ -40,11 +39,10 @@ import org.junit.runners.Parameterized
* Switch in different bubble notifications
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FlakyTest(bugId = 217777115)
-open class ChangeActiveActivityFromBubbleTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+class ChangeActiveActivityFromBubbleTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
index 8474ce0e64e5..9ca7bf113589 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
@@ -19,12 +19,13 @@ package com.android.wm.shell.flicker.bubble
import android.content.Context
import android.graphics.Point
import android.platform.test.annotations.Presubmit
+import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.util.DisplayMetrics
import android.view.WindowManager
-import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Test
@@ -41,10 +42,9 @@ import org.junit.runners.Parameterized
* Dismiss a bubble notification
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class DragToDismissBubbleScreenTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+class DragToDismissBubbleScreenTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
private val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
private val displaySize = DisplayMetrics()
@@ -73,4 +73,15 @@ open class DragToDismissBubbleScreenTest(flicker: FlickerTest) : BaseBubbleScree
open fun testAppIsAlwaysVisible() {
flicker.assertLayers { this.isVisible(testApp) }
}
+
+ @Presubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ flicker.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +
+ listOf(testApp, ComponentNameMatcher(className = "Bubbles!#"))
+ )
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
index 889e1771593d..26aca1830889 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
@@ -21,7 +21,7 @@ import android.platform.test.annotations.Postsubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.view.WindowInsets
import android.view.WindowManager
import androidx.test.filters.RequiresDevice
@@ -48,7 +48,8 @@ import org.junit.runners.Parameterized
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class OpenActivityFromBubbleOnLocksreenTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+class OpenActivityFromBubbleOnLocksreenTest(flicker: LegacyFlickerTest) :
+ BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -80,7 +81,7 @@ class OpenActivityFromBubbleOnLocksreenTest(flicker: FlickerTest) : BaseBubbleSc
instrumentation.uiAutomation.syncInputTransactions()
val showBubble =
device.wait(
- Until.findObject(By.res("com.android.systemui", "bubble_view")),
+ Until.findObject(By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)),
FIND_OBJECT_TIMEOUT
)
showBubble?.click() ?: error("Bubble notify not found")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
index 07ba41333071..4959672d865b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
@@ -19,8 +19,7 @@ package com.android.wm.shell.flicker.bubble
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Test
@@ -39,10 +38,9 @@ import org.junit.runners.Parameterized
* The activity for the bubble is launched
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class OpenActivityFromBubbleTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+class OpenActivityFromBubbleTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
index 29f76d01af83..0d95574aca06 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
@@ -19,8 +19,7 @@ package com.android.wm.shell.flicker.bubble
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Test
@@ -38,10 +37,9 @@ import org.junit.runners.Parameterized
* Send a bubble notification
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class SendBubbleNotificationTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+class SendBubbleNotificationTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -55,6 +53,7 @@ open class SendBubbleNotificationTest(flicker: FlickerTest) : BaseBubbleScreen(f
FIND_OBJECT_TIMEOUT
)
?: error("No bubbles found")
+ device.waitForIdle()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
index f7ce87088040..c335d3dc7f4b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
@@ -16,26 +16,19 @@
package com.android.wm.shell.flicker.pip
-import android.app.Instrumentation
-import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.common.Rotation
-import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import android.tools.device.traces.parsers.toFlickerComponent
import androidx.test.filters.RequiresDevice
-import androidx.test.uiautomator.By
-import androidx.test.uiautomator.BySelector
-import androidx.test.uiautomator.UiObject2
-import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
-import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
@@ -69,17 +62,16 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: FlickerTest) :
- AutoEnterPipOnGoToHomeTest(flicker) {
+class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) :
+ AutoEnterPipOnGoToHomeTest(flicker) {
private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
/** Second app used to enter split screen mode */
- protected val secondAppForSplitScreen = getSplitScreenApp(instrumentation)
- fun getSplitScreenApp(instrumentation: Instrumentation): StandardAppHelper =
- SimpleAppHelper(
- instrumentation,
- ActivityOptions.SplitScreen.Primary.LABEL,
- ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent()
- )
+ private val secondAppForSplitScreen =
+ SimpleAppHelper(
+ instrumentation,
+ ActivityOptions.SplitScreen.Primary.LABEL,
+ ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent()
+ )
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
@@ -88,14 +80,7 @@ class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: FlickerTest) :
secondAppForSplitScreen.launchViaIntent(wmHelper)
pipApp.launchViaIntent(wmHelper)
tapl.goHome()
- enterSplitScreen()
- // wait until split screen is established
- wmHelper
- .StateSyncBuilder()
- .withWindowSurfaceAppeared(pipApp)
- .withWindowSurfaceAppeared(secondAppForSplitScreen)
- .withSplitDividerVisible()
- .waitForAndVerify()
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, pipApp, secondAppForSplitScreen)
pipApp.enableAutoEnterForPipActivity()
}
teardown {
@@ -107,46 +92,6 @@ class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: FlickerTest) :
transitions { tapl.goHome() }
}
- // TODO(b/285400227) merge the code in a common utility - this is copied from SplitScreenUtils
- private val TIMEOUT_MS = 3_000L
- private val overviewSnapshotSelector: BySelector
- get() = By.res(LAUNCHER_UI_PACKAGE_NAME, "snapshot")
- private fun enterSplitScreen() {
- // Note: The initial split position in landscape is different between tablet and phone.
- // In landscape, tablet will let the first app split to right side, and phone will
- // split to left side.
- if (tapl.isTablet) {
- // TAPL's currentTask on tablet is sometimes not what we expected if the overview
- // contains more than 3 task views. We need to use uiautomator directly to find the
- // second task to split.
- tapl.workspace.switchToOverview().overviewActions.clickSplit()
- val snapshots = tapl.device.wait(Until.findObjects(overviewSnapshotSelector),
- TIMEOUT_MS)
- if (snapshots == null || snapshots.size < 1) {
- error("Fail to find a overview snapshot to split.")
- }
-
- // Find the second task in the upper right corner in split select mode by sorting
- // 'left' in descending order and 'top' in ascending order.
- snapshots.sortWith { t1: UiObject2, t2: UiObject2 ->
- t2.getVisibleBounds().left - t1.getVisibleBounds().left
- }
- snapshots.sortWith { t1: UiObject2, t2: UiObject2 ->
- t1.getVisibleBounds().top - t2.getVisibleBounds().top
- }
- snapshots[0].click()
- } else {
- tapl.workspace
- .switchToOverview()
- .currentTask
- .tapMenu()
- .tapSplitMenuItem()
- .currentTask
- .open()
- }
- SystemClock.sleep(TIMEOUT_MS)
- }
-
@Presubmit
@Test
override fun pipOverlayLayerAppearThenDisappear() {
@@ -190,11 +135,10 @@ class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index b95732e43357..bf686d6c3825 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -16,10 +16,11 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import org.junit.Assume
import org.junit.FixMethodOrder
@@ -53,10 +54,9 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiButtonTest(flicker) {
- override val thisTransition: FlickerBuilder.() -> Unit = {
- transitions { tapl.goHome() }
- }
+open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) :
+ EnterPipViaAppUiButtonTest(flicker) {
+ override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
override val defaultEnterPip: FlickerBuilder.() -> Unit = {
setup {
@@ -73,7 +73,7 @@ open class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiBu
}
}
- @Presubmit
+ @FlakyTest(bugId = 293133362)
@Test
override fun pipLayerReduces() {
flicker.assertLayers {
@@ -85,7 +85,7 @@ open class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiBu
}
/** Checks that [pipApp] window is animated towards default position in right bottom corner */
- @Presubmit
+ @FlakyTest(bugId = 255578530)
@Test
fun pipLayerMovesTowardsRightBottomCorner() {
// in gestural nav the swipe makes PiP first go upwards
@@ -108,4 +108,10 @@ open class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiBu
Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
super.focusChanges()
}
+
+ @FlakyTest(bugId = 289943985)
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index afcc1729ed16..ca28f5210f6b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -20,8 +20,7 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,11 +48,10 @@ import org.junit.runners.Parameterized
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ClosePipBySwipingDownTest(flicker: FlickerTest) : ClosePipTransition(flicker) {
+class ClosePipBySwipingDownTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions {
val pipRegion = wmHelper.getWindowRegion(pipApp).bounds
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt
deleted file mode 100644
index 02f60100d069..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ClosePipBySwipingDownTestCfArm(flicker: FlickerTest) : ClosePipBySwipingDownTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
index e52b71e602f9..a17144b7cef3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
@@ -20,14 +20,14 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.Test
import org.junit.runners.Parameterized
/** Base class for exiting pip (closing pip window) without returning to the app */
-abstract class ClosePipTransition(flicker: FlickerTest) : PipTransition(flicker) {
+abstract class ClosePipTransition(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
setup { this.setRotation(flicker.scenario.startRotation) }
teardown { this.setRotation(Rotation.ROTATION_0) }
@@ -74,15 +74,14 @@ abstract class ClosePipTransition(flicker: FlickerTest) : PipTransition(flicker)
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index 86fe583c94e6..4da628cfd90c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -19,8 +19,7 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,11 +48,10 @@ import org.junit.runners.Parameterized
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ClosePipWithDismissButtonTest(flicker: FlickerTest) : ClosePipTransition(flicker) {
+class ClosePipWithDismissButtonTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.closePipWindow(wmHelper) }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt
deleted file mode 100644
index 05262feceba5..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ClosePipWithDismissButtonTestCfArm(flicker: FlickerTest) :
- ClosePipWithDismissButtonTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 01d67cc35a14..e0b18dea971d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -19,8 +19,7 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
@@ -40,14 +39,11 @@ import org.junit.runners.Parameterized
* Press Home button or swipe up to go Home and put [pipApp] in pip mode
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipOnUserLeaveHintTest(flicker: FlickerTest) : EnterPipTransition(flicker) {
- override val thisTransition: FlickerBuilder.() -> Unit = {
- transitions { tapl.goHome() }
- }
+class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
+ override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
override val defaultEnterPip: FlickerBuilder.() -> Unit = {
setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt
deleted file mode 100644
index 90f99c0c4cae..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/** This test will fail because of b/264261596 */
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipOnUserLeaveHintTestCfArm(flicker: FlickerTest) : EnterPipOnUserLeaveHintTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index 5480144ba1ce..c003da60c50a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -21,13 +21,13 @@ import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP
@@ -64,19 +64,16 @@ import org.junit.runners.Parameterized
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipToOtherOrientation(flicker: FlickerTest) : PipTransition(flicker) {
+class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val testApp = FixedOrientationAppHelper(instrumentation)
private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
override val thisTransition: FlickerBuilder.() -> Unit = {
- teardown {
- testApp.exit(wmHelper)
- }
+ teardown { testApp.exit(wmHelper) }
transitions {
// Enter PiP, and assert that the PiP is within bounds now that the device is back
// in portrait
@@ -95,14 +92,13 @@ open class EnterPipToOtherOrientation(flicker: FlickerTest) : PipTransition(flic
setup {
// Launch a portrait only app on the fullscreen stack
testApp.launchViaIntent(
- wmHelper,
- stringExtras = mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())
+ wmHelper,
+ stringExtras = mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())
)
// Launch the PiP activity fixed as landscape, but don't enter PiP
pipApp.launchViaIntent(
- wmHelper,
- stringExtras =
- mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
+ wmHelper,
+ stringExtras = mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
)
}
}
@@ -207,13 +203,13 @@ open class EnterPipToOtherOrientation(flicker: FlickerTest) : PipTransition(flic
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ return LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt
deleted file mode 100644
index 58416660826f..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/** This test fails because of b/264261596 */
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipToOtherOrientationCfArm(flicker: FlickerTest) :
- EnterPipToOtherOrientation(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
index cdbdb85a9195..dfa369653caf 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
@@ -20,16 +20,14 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.Test
import org.junit.runners.Parameterized
-abstract class EnterPipTransition(flicker: FlickerTest) : PipTransition(flicker) {
+abstract class EnterPipTransition(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val defaultEnterPip: FlickerBuilder.() -> Unit = {
- setup {
- pipApp.launchViaIntent(wmHelper)
- }
+ setup { pipApp.launchViaIntent(wmHelper) }
}
/** Checks [pipApp] window remains visible throughout the animation */
@@ -119,22 +117,21 @@ abstract class EnterPipTransition(flicker: FlickerTest) : PipTransition(flicker)
@Presubmit
@Test
open fun focusChanges() {
- flicker.assertEventLog { this.focusChanges(pipApp.`package`, "NexusLauncherActivity") }
+ flicker.assertEventLog { this.focusChanges(pipApp.packageName, "NexusLauncherActivity") }
}
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index 95725b64a48a..f9efffe8f5cd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -18,8 +18,7 @@ package com.android.wm.shell.flicker.pip
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -46,11 +45,10 @@ import org.junit.runners.Parameterized
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipViaAppUiButtonTest(flicker: FlickerTest) : EnterPipTransition(flicker) {
+open class EnterPipViaAppUiButtonTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.clickEnterPipButton(wmHelper) }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt
deleted file mode 100644
index 4390f0bb70b2..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipViaAppUiButtonTestCfArm(flicker: FlickerTest) : EnterPipViaAppUiButtonTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
index 5ac9829b6c8f..dfffba831dc3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
@@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import org.junit.Test
import org.junit.runners.Parameterized
/** Base class for pip expand tests */
-abstract class ExitPipToAppTransition(flicker: FlickerTest) : PipTransition(flicker) {
+abstract class ExitPipToAppTransition(flicker: LegacyFlickerTest) : PipTransition(flicker) {
protected val testApp = SimpleAppHelper(instrumentation)
/**
@@ -130,15 +130,14 @@ abstract class ExitPipToAppTransition(flicker: FlickerTest) : PipTransition(flic
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index 0b3d16a8087d..c4e63c3fc408 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -18,8 +18,7 @@ package com.android.wm.shell.flicker.pip
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -48,11 +47,11 @@ import org.junit.runners.Parameterized
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExitPipToAppViaExpandButtonTest(flicker: FlickerTest) : ExitPipToAppTransition(flicker) {
+class ExitPipToAppViaExpandButtonTest(flicker: LegacyFlickerTest) :
+ ExitPipToAppTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
setup {
// launch an app behind the pip one
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt
deleted file mode 100644
index eccb85d98798..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipToAppViaExpandButtonTestCfArm(flicker: FlickerTest) :
- ExitPipToAppViaExpandButtonTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index bb2d40becdc9..839bbd4673a5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -18,8 +18,7 @@ package com.android.wm.shell.flicker.pip
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -47,11 +46,10 @@ import org.junit.runners.Parameterized
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExitPipToAppViaIntentTest(flicker: FlickerTest) : ExitPipToAppTransition(flicker) {
+class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
setup {
// launch an app behind the pip one
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt
deleted file mode 100644
index 6ab6a1f0bb73..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipToAppViaIntentTestCfArm(flicker: FlickerTest) : ExitPipToAppViaIntentTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index fd16b6ea6ada..ea67e3ddae69 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -21,9 +21,8 @@ import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,11 +50,10 @@ import org.junit.runners.Parameterized
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExpandPipOnDoubleClickTest(flicker: FlickerTest) : PipTransition(flicker) {
+class ExpandPipOnDoubleClickTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.doubleClickPipWindow(wmHelper) }
}
@@ -142,15 +140,14 @@ open class ExpandPipOnDoubleClickTest(flicker: FlickerTest) : PipTransition(flic
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt
deleted file mode 100644
index c09623490041..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExpandPipOnDoubleClickTestTestCfArm(flicker: FlickerTest) :
- ExpandPipOnDoubleClickTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index 253aa4cae5c7..0f30cef3fda5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -20,9 +20,8 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -30,11 +29,10 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/** Test expanding a pip window via pinch out gesture. */
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExpandPipOnPinchOpenTest(flicker: FlickerTest) : PipTransition(flicker) {
+class ExpandPipOnPinchOpenTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.pinchOpenPipWindow(wmHelper, 0.25f, 30) }
}
@@ -55,15 +53,14 @@ open class ExpandPipOnPinchOpenTest(flicker: FlickerTest) : PipTransition(flicke
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt
deleted file mode 100644
index e064bf2ee921..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExpandPipOnPinchOpenTestCfArm(flicker: FlickerTest) : ExpandPipOnPinchOpenTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
index 094060f86691..421ad757f76a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
@@ -19,9 +19,9 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.Direction
+import com.android.wm.shell.flicker.utils.Direction
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -55,7 +55,8 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class MovePipDownOnShelfHeightChange(flicker: FlickerTest) : MovePipShelfHeightTransition(flicker) {
+class MovePipDownOnShelfHeightChange(flicker: LegacyFlickerTest) :
+ MovePipShelfHeightTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
teardown { testApp.exit(wmHelper) }
transitions { testApp.launchViaIntent(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
index ff51c27bf116..c10860a5396f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
@@ -18,13 +18,13 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
@@ -34,11 +34,10 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/** Test Pip launch. To run this test: `atest WMShellFlickerTests:PipKeyboardTest` */
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class MovePipOnImeVisibilityChangeTest(flicker: FlickerTest) : PipTransition(flicker) {
+class MovePipOnImeVisibilityChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val imeApp = ImeAppHelper(instrumentation)
override val thisTransition: FlickerBuilder.() -> Unit = {
@@ -80,7 +79,7 @@ open class MovePipOnImeVisibilityChangeTest(flicker: FlickerTest) : PipTransitio
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ return LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt
deleted file mode 100644
index d3d77d20662e..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class MovePipOnImeVisibilityChangeTestCfArm(flicker: FlickerTest) :
- MovePipOnImeVisibilityChangeTest(flicker) {
- companion object {
- private const val TAG_IME_VISIBLE = "imeIsVisible"
-
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
index 109354ab5c79..a8fb63de244b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
@@ -19,15 +19,15 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
-import com.android.wm.shell.flicker.Direction
+import com.android.wm.shell.flicker.utils.Direction
import org.junit.Test
import org.junit.runners.Parameterized
/** Base class for pip tests with Launcher shelf height change */
-abstract class MovePipShelfHeightTransition(flicker: FlickerTest) : PipTransition(flicker) {
+abstract class MovePipShelfHeightTransition(flicker: LegacyFlickerTest) : PipTransition(flicker) {
protected val testApp = FixedOrientationAppHelper(instrumentation)
/** Checks [pipApp] window remains visible throughout the animation */
@@ -111,15 +111,14 @@ abstract class MovePipShelfHeightTransition(flicker: FlickerTest) : PipTransitio
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
index 27b061b67a85..992f1bc4ace3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
@@ -19,9 +19,9 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.Direction
+import com.android.wm.shell.flicker.utils.Direction
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -55,14 +55,13 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class MovePipUpOnShelfHeightChangeTest(flicker: FlickerTest) :
+open class MovePipUpOnShelfHeightChangeTest(flicker: LegacyFlickerTest) :
MovePipShelfHeightTransition(flicker) {
- override val thisTransition: FlickerBuilder.() -> Unit =
- {
- setup { testApp.launchViaIntent(wmHelper) }
- transitions { tapl.pressHome() }
- teardown { testApp.exit(wmHelper) }
- }
+ override val thisTransition: FlickerBuilder.() -> Unit = {
+ setup { testApp.launchViaIntent(wmHelper) }
+ transitions { tapl.pressHome() }
+ teardown { testApp.exit(wmHelper) }
+ }
/** Checks that the visible region of [pipApp] window always moves up during the animation. */
@Presubmit @Test fun pipWindowMovesUp() = pipWindowMoves(Direction.UP)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
index 9f81ba8eee87..0c6fc5636a5b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
@@ -16,12 +16,12 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresDevice
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
import org.junit.Test
@@ -34,7 +34,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipDragTest(flicker: FlickerTest) : PipTransition(flicker) {
+class PipDragTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private var isDraggedLeft: Boolean = true
override val thisTransition: FlickerBuilder.() -> Unit = {
@@ -62,7 +62,7 @@ class PipDragTest(flicker: FlickerTest) : PipTransition(flicker) {
}
}
- @Postsubmit
+ @Presubmit
@Test
fun pipLayerMovesAwayFromEdge() {
flicker.assertLayers {
@@ -81,13 +81,11 @@ class PipDragTest(flicker: FlickerTest) : PipTransition(flicker) {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index 9fe9f52fd4af..de64f78a31eb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -17,12 +17,12 @@
package com.android.wm.shell.flicker.pip
import android.graphics.Rect
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
@@ -38,7 +38,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipDragThenSnapTest(flicker: FlickerTest) : PipTransition(flicker) {
+class PipDragThenSnapTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
// represents the direction in which the pip window should be snapping
private var willSnapRight: Boolean = true
@@ -80,7 +80,7 @@ class PipDragThenSnapTest(flicker: FlickerTest) : PipTransition(flicker) {
/**
* Checks that the visible region area of [pipApp] moves to closest edge during the animation.
*/
- @Postsubmit
+ @Presubmit
@Test
fun pipLayerMovesToClosestEdge() {
flicker.assertLayers {
@@ -99,15 +99,14 @@ class PipDragThenSnapTest(flicker: FlickerTest) : PipTransition(flicker) {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index 60bf5ffdc7af..0295741bc441 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -16,13 +16,12 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
@@ -35,14 +34,13 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 270677470)
-class PipPinchInTest(flicker: FlickerTest) : PipTransition(flicker) {
+class PipPinchInTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.pinchInPipWindow(wmHelper, 0.4f, 30) }
}
/** Checks that the visible region area of [pipApp] always decreases during the animation. */
- @Postsubmit
+ @Presubmit
@Test
fun pipLayerAreaDecreases() {
flicker.assertLayers {
@@ -57,15 +55,14 @@ class PipPinchInTest(flicker: FlickerTest) : PipTransition(flicker) {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index 17a178f78de3..096af39488e9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -22,7 +22,7 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import android.tools.device.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.PipAppHelper
@@ -32,7 +32,7 @@ import com.android.wm.shell.flicker.BaseTest
import com.google.common.truth.Truth
import org.junit.Test
-abstract class PipTransition(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class PipTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
protected val pipApp = PipAppHelper(instrumentation)
protected val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
@@ -78,16 +78,16 @@ abstract class PipTransition(flicker: FlickerTest) : BaseTest(flicker) {
/** Defines the default method of entering PiP */
protected open val defaultEnterPip: FlickerBuilder.() -> Unit = {
setup {
- pipApp.launchViaIntentAndWaitForPip(wmHelper,
- stringExtras = mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true"))
+ pipApp.launchViaIntentAndWaitForPip(
+ wmHelper,
+ stringExtras = mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true")
+ )
}
}
/** Defines the default teardown required to clean up after the test */
protected open val defaultTeardown: FlickerBuilder.() -> Unit = {
- teardown {
- pipApp.exit(wmHelper)
- }
+ teardown { pipApp.exit(wmHelper) }
}
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
index c618e5a24fdf..c315e744bd55 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
@@ -21,10 +21,11 @@ import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -46,7 +47,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SetRequestedOrientationWhilePinned(flicker: FlickerTest) : PipTransition(flicker) {
+open class SetRequestedOrientationWhilePinned(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
@@ -69,20 +70,19 @@ open class SetRequestedOrientationWhilePinned(flicker: FlickerTest) : PipTransit
setup {
// Launch the PiP activity fixed as landscape.
pipApp.launchViaIntent(
- wmHelper,
- stringExtras =
- mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
+ wmHelper,
+ stringExtras = mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
)
// Enter PiP.
broadcastActionTrigger.doAction(ActivityOptions.Pip.ACTION_ENTER_PIP)
// System bar may fade out during fixed rotation.
wmHelper
- .StateSyncBuilder()
- .withPipShown()
- .withRotation(Rotation.ROTATION_0)
- .withNavOrTaskBarVisible()
- .withStatusBarVisible()
- .waitForAndVerify()
+ .StateSyncBuilder()
+ .withPipShown()
+ .withRotation(Rotation.ROTATION_0)
+ .withNavOrTaskBarVisible()
+ .withStatusBarVisible()
+ .waitForAndVerify()
}
}
@@ -150,7 +150,7 @@ open class SetRequestedOrientationWhilePinned(flicker: FlickerTest) : PipTransit
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ return LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
index 43d6c8f26126..e588f8793b82 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
@@ -17,12 +17,12 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
@@ -54,11 +54,10 @@ import org.junit.runners.Parameterized
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowPipAndRotateDisplay(flicker: FlickerTest) : PipTransition(flicker) {
+class ShowPipAndRotateDisplay(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val testApp = SimpleAppHelper(instrumentation)
private val screenBoundsStart = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
private val screenBoundsEnd = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
@@ -154,13 +153,13 @@ open class ShowPipAndRotateDisplay(flicker: FlickerTest) : PipTransition(flicker
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
+ return LegacyFlickerTestFactory.rotationTests()
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt
deleted file mode 100644
index b7a2c47e3b32..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2023 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.flicker.pip
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowPipAndRotateDisplayCfArm(flicker: FlickerTest) : ShowPipAndRotateDisplay(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
index 000ae8f9458e..c6cbcd052fe0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
@@ -26,7 +26,7 @@ import com.android.server.wm.flicker.helpers.PipAppHelper
/** Helper class for PIP app on AndroidTV */
open class PipAppHelperTv(instrumentation: Instrumentation) : PipAppHelper(instrumentation) {
- private val appSelector = By.pkg(`package`).depth(0)
+ private val appSelector = By.pkg(packageName).depth(0)
val ui: UiObject2?
get() = uiDevice.findObject(appSelector)
@@ -46,7 +46,7 @@ open class PipAppHelperTv(instrumentation: Instrumentation) : PipAppHelper(instr
}
override fun clickObject(resId: String) {
- val selector = By.res(`package`, resId)
+ val selector = By.res(packageName, resId)
focusOnObject(selector) || error("Could not focus on `$resId` object")
uiDevice.pressDPadCenter()
}
@@ -68,7 +68,7 @@ open class PipAppHelperTv(instrumentation: Instrumentation) : PipAppHelper(instr
}
fun waitUntilClosed(): Boolean {
- val appSelector = By.pkg(`package`).depth(0)
+ val appSelector = By.pkg(packageName).depth(0)
return uiDevice.wait(Until.gone(appSelector), APP_CLOSE_WAIT_TIME_MS)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
index 0432a8497fbe..d4cd6da4acb1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -20,8 +20,8 @@ import android.graphics.Rect
import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.UiObject2
import com.android.server.wm.flicker.testapp.ActivityOptions
-import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
-import com.android.wm.shell.flicker.wait
+import com.android.wm.shell.flicker.utils.SYSTEM_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.utils.wait
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
index 90406c510bad..4402e2153e9b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
@@ -21,11 +21,11 @@ import android.app.PendingIntent
import android.os.Bundle
import android.service.notification.StatusBarNotification
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.NotificationListener.Companion.findNotification
-import com.android.wm.shell.flicker.NotificationListener.Companion.startNotificationListener
-import com.android.wm.shell.flicker.NotificationListener.Companion.stopNotificationListener
-import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToAppear
-import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToDisappear
+import com.android.wm.shell.flicker.utils.NotificationListener.Companion.findNotification
+import com.android.wm.shell.flicker.utils.NotificationListener.Companion.startNotificationListener
+import com.android.wm.shell.flicker.utils.NotificationListener.Companion.stopNotificationListener
+import com.android.wm.shell.flicker.utils.NotificationListener.Companion.waitForNotificationToAppear
+import com.android.wm.shell.flicker.utils.NotificationListener.Companion.waitForNotificationToDisappear
import org.junit.After
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
index 6104b7bdacba..47bff8de377e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
@@ -24,7 +24,7 @@ import android.tools.device.helpers.wakeUpAndGoToHomeScreen
import android.tools.device.traces.parsers.WindowManagerStateHelper
import android.view.Surface.ROTATION_0
import android.view.Surface.rotationToString
-import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.utils.SYSTEM_UI_PACKAGE_NAME
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assume.assumeTrue
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
index b0adbe1d07ce..4aee61ade10e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
@@ -22,7 +22,7 @@ import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
-import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.utils.SYSTEM_UI_PACKAGE_NAME
/** Id of the root view in the com.android.wm.shell.pip.tv.PipMenuActivity */
private const val TV_PIP_MENU_ROOT_ID = "tv_pip_menu"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt
new file mode 100644
index 000000000000..610cedefe594
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 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.flicker.service
+
+import android.app.Instrumentation
+import android.platform.test.rule.NavigationModeRule
+import android.platform.test.rule.PressHomeRule
+import android.platform.test.rule.UnlockScreenRule
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.apphelpers.MessagingAppHelper
+import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.device.flicker.rules.LaunchAppRule
+import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.rules.RuleChain
+
+object Utils {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ fun testSetupRule(navigationMode: NavBar, rotation: Rotation): RuleChain {
+ return RuleChain.outerRule(UnlockScreenRule())
+ .around(
+ NavigationModeRule(navigationMode.value, /* changeNavigationModeAfterTest */ false)
+ )
+ .around(
+ LaunchAppRule(MessagingAppHelper(instrumentation), clearCacheAfterParsing = false)
+ )
+ .around(RemoveAllTasksButHomeRule())
+ .around(
+ ChangeDisplayOrientationRule(
+ rotation,
+ resetOrientationAfterTest = false,
+ clearCacheAfterParsing = false
+ )
+ )
+ .around(PressHomeRule())
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS
new file mode 100644
index 000000000000..3ab6a1ee061d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS
@@ -0,0 +1,2 @@
+# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > WM Shell > Split Screen
+# Bug component: 928697
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
new file mode 100644
index 000000000000..e37d806c7a14
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
+import org.junit.Test
+
+open class CopyContentInSplitGesturalNavLandscape : CopyContentInSplit(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun copyContentInSplit() = super.copyContentInSplit()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
index e323ebf3b5c8..2a50912e0a5c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
@@ -14,14 +14,17 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.bubble
+package com.android.wm.shell.flicker.service.splitscreen.platinum
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
+import org.junit.Test
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class SendBubbleNotificationTestCfArm(flicker: FlickerTest) :
- SendBubbleNotificationTest(flicker)
+open class CopyContentInSplitGesturalNavPortrait : CopyContentInSplit(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun copyContentInSplit() = super.copyContentInSplit()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
new file mode 100644
index 000000000000..d5da1a8b558c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
+import org.junit.Test
+
+open class DismissSplitScreenByDividerGesturalNavLandscape :
+ DismissSplitScreenByDivider(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dismissSplitScreenByDivider() = super.dismissSplitScreenByDivider()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
new file mode 100644
index 000000000000..7fdcb9be62ee
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
+import org.junit.Test
+
+open class DismissSplitScreenByDividerGesturalNavPortrait :
+ DismissSplitScreenByDivider(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dismissSplitScreenByDivider() = super.dismissSplitScreenByDivider()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
new file mode 100644
index 000000000000..308e954b86c1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
+import org.junit.Test
+
+open class DismissSplitScreenByGoHomeGesturalNavLandscape :
+ DismissSplitScreenByGoHome(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
new file mode 100644
index 000000000000..39e75bd25a71
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
+import org.junit.Test
+
+open class DismissSplitScreenByGoHomeGesturalNavPortrait :
+ DismissSplitScreenByGoHome(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
new file mode 100644
index 000000000000..e18da17175c0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
+import org.junit.Test
+
+open class DragDividerToResizeGesturalNavLandscape : DragDividerToResize(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dragDividerToResize() = super.dragDividerToResize()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
new file mode 100644
index 000000000000..00d60e756ffa
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
+import org.junit.Test
+
+open class DragDividerToResizeGesturalNavPortrait : DragDividerToResize(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dragDividerToResize() = super.dragDividerToResize()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
new file mode 100644
index 000000000000..d7efbc8c0fd4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
+import org.junit.Test
+
+open class EnterSplitScreenByDragFromAllAppsGesturalNavLandscape :
+ EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromAllApps() = super.enterSplitScreenByDragFromAllApps()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
new file mode 100644
index 000000000000..4eece3f62d10
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
+import org.junit.Test
+
+open class EnterSplitScreenByDragFromAllAppsGesturalNavPortrait :
+ EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromAllApps() = super.enterSplitScreenByDragFromAllApps()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
new file mode 100644
index 000000000000..d96b056d8753
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
+import org.junit.Test
+
+open class EnterSplitScreenByDragFromNotificationGesturalNavLandscape :
+ EnterSplitScreenByDragFromNotification(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromNotification() =
+ super.enterSplitScreenByDragFromNotification()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
new file mode 100644
index 000000000000..809b690e0861
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
+import org.junit.Test
+
+open class EnterSplitScreenByDragFromNotificationGesturalNavPortrait :
+ EnterSplitScreenByDragFromNotification(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromNotification() =
+ super.enterSplitScreenByDragFromNotification()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
new file mode 100644
index 000000000000..bbdf2d728494
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
+import org.junit.Test
+
+open class EnterSplitScreenByDragFromShortcutGesturalNavLandscape :
+ EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromShortcut() = super.enterSplitScreenByDragFromShortcut()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
new file mode 100644
index 000000000000..5c29fd8fe57e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
+import org.junit.Test
+
+open class EnterSplitScreenByDragFromShortcutGesturalNavPortrait :
+ EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromShortcut() = super.enterSplitScreenByDragFromShortcut()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
new file mode 100644
index 000000000000..a7398ebf56e8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
+import org.junit.Test
+
+open class EnterSplitScreenByDragFromTaskbarGesturalNavLandscape :
+ EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromTaskbar() = super.enterSplitScreenByDragFromTaskbar()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
new file mode 100644
index 000000000000..eae88ad4ad09
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
+import org.junit.Test
+
+open class EnterSplitScreenByDragFromTaskbarGesturalNavPortrait :
+ EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromTaskbar() = super.enterSplitScreenByDragFromTaskbar()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
new file mode 100644
index 000000000000..7e8ee04a28fa
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
+import org.junit.Test
+
+open class EnterSplitScreenFromOverviewGesturalNavLandscape :
+ EnterSplitScreenFromOverview(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenFromOverview() = super.enterSplitScreenFromOverview()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
new file mode 100644
index 000000000000..9295c330b879
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
+import org.junit.Test
+
+open class EnterSplitScreenFromOverviewGesturalNavPortrait :
+ EnterSplitScreenFromOverview(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenFromOverview() = super.enterSplitScreenFromOverview()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
new file mode 100644
index 000000000000..4b59e9fbd866
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
+import org.junit.Test
+
+open class SwitchAppByDoubleTapDividerGesturalNavLandscape :
+ SwitchAppByDoubleTapDivider(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchAppByDoubleTapDivider() = super.switchAppByDoubleTapDivider()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
new file mode 100644
index 000000000000..5ff36d4aabbb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
+import org.junit.Test
+
+open class SwitchAppByDoubleTapDividerGesturalNavPortrait :
+ SwitchAppByDoubleTapDivider(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchAppByDoubleTapDivider() = super.switchAppByDoubleTapDivider()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
new file mode 100644
index 000000000000..c0cb7219437b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
+import org.junit.Test
+
+open class SwitchBackToSplitFromAnotherAppGesturalNavLandscape :
+ SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromAnotherApp() = super.switchBackToSplitFromAnotherApp()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
new file mode 100644
index 000000000000..8c140884aa50
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
+import org.junit.Test
+
+open class SwitchBackToSplitFromAnotherAppGesturalNavPortrait :
+ SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromAnotherApp() = super.switchBackToSplitFromAnotherApp()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
new file mode 100644
index 000000000000..7b6614b81c11
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
+import org.junit.Test
+
+open class SwitchBackToSplitFromHomeGesturalNavLandscape :
+ SwitchBackToSplitFromHome(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromHome() = super.switchBackToSplitFromHome()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
new file mode 100644
index 000000000000..5df5be9daa8b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
+import org.junit.Test
+
+open class SwitchBackToSplitFromHomeGesturalNavPortrait :
+ SwitchBackToSplitFromHome(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromHome() = super.switchBackToSplitFromHome()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
new file mode 100644
index 000000000000..9d63003bf2a1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
+import org.junit.Test
+
+open class SwitchBackToSplitFromRecentGesturalNavLandscape :
+ SwitchBackToSplitFromRecent(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
new file mode 100644
index 000000000000..9fa04b208ad1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
+import org.junit.Test
+
+open class SwitchBackToSplitFromRecentGesturalNavPortrait :
+ SwitchBackToSplitFromRecent(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
new file mode 100644
index 000000000000..9386aa2b2cf0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
+import org.junit.Test
+
+open class SwitchBetweenSplitPairsGesturalNavLandscape :
+ SwitchBetweenSplitPairs(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBetweenSplitPairs() = super.switchBetweenSplitPairs()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
new file mode 100644
index 000000000000..5ef21672bfe0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
+import org.junit.Test
+
+open class SwitchBetweenSplitPairsGesturalNavPortrait :
+ SwitchBetweenSplitPairs(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBetweenSplitPairs() = super.switchBetweenSplitPairs()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
new file mode 100644
index 000000000000..9caab9b5182a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+open class UnlockKeyguardToSplitScreenGesturalNavLandscape : UnlockKeyguardToSplitScreen() {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
new file mode 100644
index 000000000000..bf484e5cef98
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.platinum
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+open class UnlockKeyguardToSplitScreenGesturalNavPortrait : UnlockKeyguardToSplitScreen() {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
new file mode 100644
index 000000000000..e530f6369609
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class CopyContentInSplit
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+ private val textEditApp = SplitScreenUtils.getIme(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, textEditApp)
+ }
+
+ @Test
+ open fun copyContentInSplit() {
+ SplitScreenUtils.copyContentInSplit(instrumentation, device, primaryApp, textEditApp)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
new file mode 100644
index 000000000000..e9fc43746d27
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class DismissSplitScreenByDivider
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+ }
+
+ @Test
+ open fun dismissSplitScreenByDivider() {
+ if (tapl.isTablet) {
+ SplitScreenUtils.dragDividerToDismissSplit(
+ device,
+ wmHelper,
+ dragToRight = false,
+ dragToBottom = true
+ )
+ } else {
+ SplitScreenUtils.dragDividerToDismissSplit(
+ device,
+ wmHelper,
+ dragToRight = true,
+ dragToBottom = true
+ )
+ }
+ wmHelper.StateSyncBuilder().withFullScreenApp(secondaryApp).waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
new file mode 100644
index 000000000000..416692c37b34
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class DismissSplitScreenByGoHome
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+ }
+
+ @Test
+ open fun dismissSplitScreenByGoHome() {
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
new file mode 100644
index 000000000000..494a246d2f50
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class DragDividerToResize
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+ }
+
+ @Test
+ open fun dragDividerToResize() {
+ SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
new file mode 100644
index 000000000000..9b438163daa8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class EnterSplitScreenByDragFromAllApps
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(tapl.isTablet)
+
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ tapl.goHome()
+ primaryApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun enterSplitScreenByDragFromAllApps() {
+ tapl.launchedAppState.taskbar
+ .openAllApps()
+ .getAppIcon(secondaryApp.appName)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
new file mode 100644
index 000000000000..50151f1b7efe
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class EnterSplitScreenByDragFromNotification
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+ private val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(tapl.isTablet)
+
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ // Send a notification
+ sendNotificationApp.launchViaIntent(wmHelper)
+ sendNotificationApp.postNotification(wmHelper)
+ tapl.goHome()
+ primaryApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun enterSplitScreenByDragFromNotification() {
+ SplitScreenUtils.dragFromNotificationToSplit(instrumentation, device, wmHelper)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, sendNotificationApp)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ sendNotificationApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
new file mode 100644
index 000000000000..76fbf60897ca
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class EnterSplitScreenByDragFromShortcut
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(tapl.isTablet)
+
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ tapl.goHome()
+ SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
+ primaryApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun enterSplitScreenByDragFromShortcut() {
+ tapl.launchedAppState.taskbar
+ .getAppIcon(secondaryApp.appName)
+ .openDeepShortcutMenu()
+ .getMenuItem("Split Screen Secondary Activity")
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+
+ // TODO: Do we want this check in here? Add to the other tests?
+ // flicker.splitScreenEntered(
+ // primaryApp,
+ // secondaryApp,
+ // fromOtherApp = false,
+ // appExistAtStart = false
+ // )
+ }
+
+ @After
+ fun teardwon() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
new file mode 100644
index 000000000000..f8e43f1207e2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class EnterSplitScreenByDragFromTaskbar
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(tapl.isTablet)
+
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ tapl.goHome()
+ SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
+ primaryApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun enterSplitScreenByDragFromTaskbar() {
+ tapl.launchedAppState.taskbar
+ .getAppIcon(secondaryApp.appName)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
new file mode 100644
index 000000000000..c2100f641a55
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class EnterSplitScreenFromOverview
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ primaryApp.launchViaIntent(wmHelper)
+ secondaryApp.launchViaIntent(wmHelper)
+ tapl.goHome()
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
+ }
+
+ @Test
+ open fun enterSplitScreenFromOverview() {
+ SplitScreenUtils.splitFromOverview(tapl, device)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
new file mode 100644
index 000000000000..70f3bed9afdc
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.graphics.Point
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.helpers.WindowUtils
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class SwitchAppByDoubleTapDivider
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+ tapl.workspace.switchToOverview().dismissAllTasks()
+
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+ }
+
+ @Test
+ open fun switchAppByDoubleTapDivider() {
+ SplitScreenUtils.doubleTapDividerToSwitch(device)
+ wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+
+ waitForLayersToSwitch(wmHelper)
+ waitForWindowsToSwitch(wmHelper)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+
+ private fun waitForWindowsToSwitch(wmHelper: WindowManagerStateHelper) {
+ wmHelper
+ .StateSyncBuilder()
+ .add("appWindowsSwitched") {
+ val primaryAppWindow =
+ it.wmState.visibleWindows.firstOrNull { window ->
+ primaryApp.windowMatchesAnyOf(window)
+ }
+ ?: return@add false
+ val secondaryAppWindow =
+ it.wmState.visibleWindows.firstOrNull { window ->
+ secondaryApp.windowMatchesAnyOf(window)
+ }
+ ?: return@add false
+
+ if (isLandscape(rotation)) {
+ return@add if (isTablet()) {
+ secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
+ } else {
+ primaryAppWindow.frame.right <= secondaryAppWindow.frame.left
+ }
+ } else {
+ return@add if (isTablet()) {
+ primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
+ } else {
+ primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
+ }
+ }
+ }
+ .waitForAndVerify()
+ }
+
+ private fun waitForLayersToSwitch(wmHelper: WindowManagerStateHelper) {
+ wmHelper
+ .StateSyncBuilder()
+ .add("appLayersSwitched") {
+ val primaryAppLayer =
+ it.layerState.visibleLayers.firstOrNull { window ->
+ primaryApp.layerMatchesAnyOf(window)
+ }
+ ?: return@add false
+ val secondaryAppLayer =
+ it.layerState.visibleLayers.firstOrNull { window ->
+ secondaryApp.layerMatchesAnyOf(window)
+ }
+ ?: return@add false
+
+ val primaryVisibleRegion = primaryAppLayer.visibleRegion?.bounds ?: return@add false
+ val secondaryVisibleRegion =
+ secondaryAppLayer.visibleRegion?.bounds ?: return@add false
+
+ if (isLandscape(rotation)) {
+ return@add if (isTablet()) {
+ secondaryVisibleRegion.right <= primaryVisibleRegion.left
+ } else {
+ primaryVisibleRegion.right <= secondaryVisibleRegion.left
+ }
+ } else {
+ return@add if (isTablet()) {
+ primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
+ } else {
+ primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
+ }
+ }
+ }
+ .waitForAndVerify()
+ }
+
+ private fun isLandscape(rotation: Rotation): Boolean {
+ val displayBounds = WindowUtils.getDisplayBounds(rotation)
+ return displayBounds.width > displayBounds.height
+ }
+
+ private fun isTablet(): Boolean {
+ val sizeDp: Point = device.displaySizeDp
+ val LARGE_SCREEN_DP_THRESHOLD = 600
+ return sizeDp.x >= LARGE_SCREEN_DP_THRESHOLD && sizeDp.y >= LARGE_SCREEN_DP_THRESHOLD
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
new file mode 100644
index 000000000000..86f394da0231
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class SwitchBackToSplitFromAnotherApp
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+ private val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+
+ thirdApp.launchViaIntent(wmHelper)
+ wmHelper.StateSyncBuilder().withWindowSurfaceAppeared(thirdApp).waitForAndVerify()
+ }
+
+ @Test
+ open fun switchBackToSplitFromAnotherApp() {
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
new file mode 100644
index 000000000000..d7b611e04d9d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class SwitchBackToSplitFromHome
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+
+ @Test
+ open fun switchBackToSplitFromHome() {
+ tapl.workspace.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
new file mode 100644
index 000000000000..3cc5df09b16e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class SwitchBackToSplitFromRecent
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+ tapl.workspace.switchToOverview().dismissAllTasks()
+
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+
+ @Test
+ open fun switchBackToSplitFromRecent() {
+ tapl.workspace.switchToOverview().currentTask.open()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
new file mode 100644
index 000000000000..4a9c32f10415
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class SwitchBetweenSplitPairs
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+ private val thirdApp = SplitScreenUtils.getIme(instrumentation)
+ private val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, thirdApp, fourthApp)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, thirdApp, fourthApp)
+ }
+
+ @Test
+ open fun switchBetweenSplitPairs() {
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ thirdApp.exit(wmHelper)
+ fourthApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
new file mode 100644
index 000000000000..383a6b39a2b6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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.flicker.service.splitscreen.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class UnlockKeyguardToSplitScreen {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(Rotation.ROTATION_0.value)
+
+ SplitScreenUtils.enterSplitViaIntent(wmHelper, primaryApp, secondaryApp)
+ }
+
+ @Test
+ open fun unlockKeyguardToSplitScreen() {
+ device.sleep()
+ wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+ device.wakeUp()
+ device.pressMenu()
+ wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index d1f0980786bf..3702be9541a3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -17,25 +17,20 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.common.traces.component.EdgeExtensionComponentMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
-import com.android.wm.shell.flicker.appWindowKeepVisible
-import com.android.wm.shell.flicker.layerKeepVisible
-import com.android.wm.shell.flicker.splitAppLayerBoundsKeepVisible
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
import com.android.wm.shell.flicker.splitscreen.benchmark.CopyContentInSplitBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.utils.appWindowKeepVisible
+import com.android.wm.shell.flicker.utils.layerKeepVisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsKeepVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,13 +40,13 @@ import org.junit.runners.Parameterized
/**
* Test copy content from the left to the right side of the split-screen.
*
- * To run this test: `atest WMShellFlickerTests:CopyContentInSplit`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:CopyContentInSplit`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CopyContentInSplit(override val flicker: FlickerTest) :
+class CopyContentInSplit(override val flicker: LegacyFlickerTest) :
CopyContentInSplitBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -60,21 +55,6 @@ class CopyContentInSplit(override val flicker: FlickerTest) :
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- override fun cujCompleted() {
- flicker.appWindowIsVisibleAtStart(primaryApp)
- flicker.appWindowIsVisibleAtStart(textEditApp)
- flicker.splitScreenDividerIsVisibleAtStart()
-
- flicker.appWindowIsVisibleAtEnd(primaryApp)
- flicker.appWindowIsVisibleAtEnd(textEditApp)
- flicker.splitScreenDividerIsVisibleAtEnd()
-
- // The validation of copied text is already done in SplitScreenUtils.copyContentInSplit()
- }
-
@Presubmit
@Test
fun splitScreenDividerKeepVisible() = flicker.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
@@ -136,8 +116,6 @@ class CopyContentInSplit(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
index 4505b9978b76..8b906305506f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
@@ -21,17 +21,17 @@ import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.appWindowBecomesInvisible
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.layerBecomesInvisible
-import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesInvisible
-import com.android.wm.shell.flicker.splitScreenDividerBecomesInvisible
import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByDividerBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.appWindowBecomesInvisible
+import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.layerBecomesInvisible
+import com.android.wm.shell.flicker.utils.layerIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesInvisible
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesInvisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -41,13 +41,13 @@ import org.junit.runners.Parameterized
/**
* Test dismiss split screen by dragging the divider bar.
*
- * To run this test: `atest WMShellFlickerTests:DismissSplitScreenByDivider`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:DismissSplitScreenByDivider`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByDivider(override val flicker: FlickerTest) :
+class DismissSplitScreenByDivider(override val flicker: LegacyFlickerTest) :
DismissSplitScreenByDividerBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index e05b22141e4d..50f6a382a702 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -20,15 +20,15 @@ import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.appWindowBecomesInvisible
-import com.android.wm.shell.flicker.layerBecomesInvisible
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesInvisible
-import com.android.wm.shell.flicker.splitScreenDividerBecomesInvisible
import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByGoHomeBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.appWindowBecomesInvisible
+import com.android.wm.shell.flicker.utils.layerBecomesInvisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesInvisible
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesInvisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -38,13 +38,13 @@ import org.junit.runners.Parameterized
/**
* Test dismiss split screen by go home.
*
- * To run this test: `atest WMShellFlickerTests:DismissSplitScreenByGoHome`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:DismissSplitScreenByGoHome`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByGoHome(override val flicker: FlickerTest) :
+class DismissSplitScreenByGoHome(override val flicker: LegacyFlickerTest) :
DismissSplitScreenByGoHomeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -154,8 +154,6 @@ class DismissSplitScreenByGoHome(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index 63c5d14d85e1..cc3b783e53d2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -17,23 +17,18 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
-import com.android.wm.shell.flicker.appWindowKeepVisible
-import com.android.wm.shell.flicker.layerKeepVisible
-import com.android.wm.shell.flicker.splitAppLayerBoundsChanges
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
import com.android.wm.shell.flicker.splitscreen.benchmark.DragDividerToResizeBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.utils.appWindowKeepVisible
+import com.android.wm.shell.flicker.utils.layerKeepVisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsChanges
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -43,13 +38,13 @@ import org.junit.runners.Parameterized
/**
* Test resize split by dragging the divider bar.
*
- * To run this test: `atest WMShellFlickerTests:DragDividerToResize`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:DragDividerToResize`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DragDividerToResize(override val flicker: FlickerTest) :
+class DragDividerToResize(override val flicker: LegacyFlickerTest) :
DragDividerToResizeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -58,24 +53,11 @@ class DragDividerToResize(override val flicker: FlickerTest) :
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- override fun cujCompleted() {
- flicker.appWindowIsVisibleAtStart(primaryApp)
- flicker.appWindowIsVisibleAtStart(secondaryApp)
- flicker.splitScreenDividerIsVisibleAtStart()
-
- flicker.appWindowIsVisibleAtEnd(primaryApp)
- flicker.appWindowIsVisibleAtEnd(secondaryApp)
- flicker.splitScreenDividerIsVisibleAtEnd()
- }
-
@Presubmit
@Test
fun splitScreenDividerKeepVisible() = flicker.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
- @Presubmit
+ @FlakyTest(bugId = 291678271)
@Test
fun primaryAppLayerVisibilityChanges() {
flicker.assertLayers {
@@ -87,7 +69,7 @@ class DragDividerToResize(override val flicker: FlickerTest) :
}
}
- @Presubmit
+ @FlakyTest(bugId = 291678271)
@Test
fun secondaryAppLayerVisibilityChanges() {
flicker.assertLayers {
@@ -105,7 +87,7 @@ class DragDividerToResize(override val flicker: FlickerTest) :
@Test
fun secondaryAppWindowKeepVisible() = flicker.appWindowKeepVisible(secondaryApp)
- @FlakyTest(bugId = 245472831)
+ @FlakyTest(bugId = 291678271)
@Test
fun primaryAppBoundsChanges() {
flicker.splitAppLayerBoundsChanges(
@@ -115,7 +97,7 @@ class DragDividerToResize(override val flicker: FlickerTest) :
)
}
- @Presubmit
+ @FlakyTest(bugId = 291678271)
@Test
fun secondaryAppBoundsChanges() =
flicker.splitAppLayerBoundsChanges(
@@ -124,11 +106,15 @@ class DragDividerToResize(override val flicker: FlickerTest) :
portraitPosTop = true
)
+ @FlakyTest(bugId = 291678271)
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index e55868675da7..f8d1e1f1f498 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -22,19 +22,19 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowBecomesVisible
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromAllAppsBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.utils.appWindowBecomesVisible
+import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.layerBecomesVisible
+import com.android.wm.shell.flicker.utils.layerIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesVisibleByDrag
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,13 +45,13 @@ import org.junit.runners.Parameterized
* Test enter split screen by dragging app icon from all apps. This test is only for large screen
* devices.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromAllApps`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenByDragFromAllApps`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromAllApps(override val flicker: FlickerTest) :
+class EnterSplitScreenByDragFromAllApps(override val flicker: LegacyFlickerTest) :
EnterSplitScreenByDragFromAllAppsBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -160,11 +160,10 @@ class EnterSplitScreenByDragFromAllApps(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
index ab8ecc54e71c..ff5d93550541 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
@@ -22,18 +22,18 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromNotificationBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.layerBecomesVisible
+import com.android.wm.shell.flicker.utils.layerIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesVisibleByDrag
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,13 +44,13 @@ import org.junit.runners.Parameterized
* Test enter split screen by dragging app icon from notification. This test is only for large
* screen devices.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromNotification`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenByDragFromNotification`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromNotification(override val flicker: FlickerTest) :
+class EnterSplitScreenByDragFromNotification(override val flicker: LegacyFlickerTest) :
EnterSplitScreenByDragFromNotificationBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -162,11 +162,10 @@ class EnterSplitScreenByDragFromNotification(override val flicker: FlickerTest)
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
index 516ca97bc531..7c710777087d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
@@ -21,17 +21,17 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromShortcutBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.layerBecomesVisible
+import com.android.wm.shell.flicker.utils.layerIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesVisibleByDrag
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -41,13 +41,13 @@ import org.junit.runners.Parameterized
/**
* Test enter split screen by dragging a shortcut. This test is only for large screen devices.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromShortcut`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenByDragFromShortcut`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromShortcut(override val flicker: FlickerTest) :
+class EnterSplitScreenByDragFromShortcut(override val flicker: LegacyFlickerTest) :
EnterSplitScreenByDragFromShortcutBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
@@ -105,11 +105,10 @@ class EnterSplitScreenByDragFromShortcut(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
index 4af7e248b660..83717062b05e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
@@ -22,19 +22,19 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowBecomesVisible
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromTaskbarBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.utils.appWindowBecomesVisible
+import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.layerBecomesVisible
+import com.android.wm.shell.flicker.utils.layerIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesVisibleByDrag
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,13 +45,13 @@ import org.junit.runners.Parameterized
* Test enter split screen by dragging app icon from taskbar. This test is only for large screen
* devices.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromTaskbar`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenByDragFromTaskbar`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromTaskbar(override val flicker: FlickerTest) :
+class EnterSplitScreenByDragFromTaskbar(override val flicker: LegacyFlickerTest) :
EnterSplitScreenByDragFromTaskbarBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -163,10 +163,9 @@ class EnterSplitScreenByDragFromTaskbar(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index faad9e82ffef..0bfdbb4de7c5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -20,17 +20,17 @@ import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.appWindowBecomesVisible
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisible
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenFromOverviewBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.appWindowBecomesVisible
+import com.android.wm.shell.flicker.utils.layerBecomesVisible
+import com.android.wm.shell.flicker.utils.layerIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesVisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -40,13 +40,13 @@ import org.junit.runners.Parameterized
/**
* Test enter split screen from Overview.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenFromOverview`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenFromOverview`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenFromOverview(override val flicker: FlickerTest) :
+class EnterSplitScreenFromOverview(override val flicker: LegacyFlickerTest) :
EnterSplitScreenFromOverviewBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -106,8 +106,6 @@ class EnterSplitScreenFromOverview(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OWNERS
new file mode 100644
index 000000000000..3ab6a1ee061d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OWNERS
@@ -0,0 +1,2 @@
+# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > WM Shell > Split Screen
+# Bug component: 928697
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index 03b8a75a1f32..fac97c8cc8c4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -16,25 +16,21 @@
package com.android.wm.shell.flicker.splitscreen
-import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
-import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.layerKeepVisible
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchAppByDoubleTapDividerBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.layerIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.layerKeepVisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,13 +40,13 @@ import org.junit.runners.Parameterized
/**
* Test double tap the divider bar to switch the two apps.
*
- * To run this test: `atest WMShellFlickerTests:SwitchAppByDoubleTapDivider`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchAppByDoubleTapDivider`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchAppByDoubleTapDivider(override val flicker: FlickerTest) :
+class SwitchAppByDoubleTapDivider(override val flicker: LegacyFlickerTest) :
SwitchAppByDoubleTapDividerBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -59,19 +55,6 @@ class SwitchAppByDoubleTapDivider(override val flicker: FlickerTest) :
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- override fun cujCompleted() {
- flicker.appWindowIsVisibleAtStart(primaryApp)
- flicker.appWindowIsVisibleAtStart(secondaryApp)
- flicker.splitScreenDividerIsVisibleAtStart()
-
- flicker.appWindowIsVisibleAtEnd(primaryApp)
- flicker.appWindowIsVisibleAtEnd(secondaryApp)
- flicker.splitScreenDividerIsVisibleAtEnd()
- }
-
@Presubmit
@Test
fun splitScreenDividerKeepVisible() = flicker.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
@@ -120,11 +103,10 @@ class SwitchAppByDoubleTapDivider(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
index 078d95de1dd0..88bbc0e7880b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
@@ -21,15 +21,15 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.appWindowBecomesVisible
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromAnotherAppBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.appWindowBecomesVisible
+import com.android.wm.shell.flicker.utils.layerBecomesVisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -39,13 +39,13 @@ import org.junit.runners.Parameterized
/**
* Test quick switch to split pair from another app.
*
- * To run this test: `atest WMShellFlickerTests:SwitchBackToSplitFromAnotherApp`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchBackToSplitFromAnotherApp`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromAnotherApp(override val flicker: FlickerTest) :
+class SwitchBackToSplitFromAnotherApp(override val flicker: LegacyFlickerTest) :
SwitchBackToSplitFromAnotherAppBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -149,11 +149,10 @@ class SwitchBackToSplitFromAnotherApp(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
index 7c84243e00d7..e85dc24a7781 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
@@ -21,15 +21,15 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.appWindowBecomesVisible
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromHomeBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.appWindowBecomesVisible
+import com.android.wm.shell.flicker.utils.layerBecomesVisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -39,13 +39,13 @@ import org.junit.runners.Parameterized
/**
* Test quick switch to split pair from home.
*
- * To run this test: `atest WMShellFlickerTests:SwitchBackToSplitFromHome`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchBackToSplitFromHome`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromHome(override val flicker: FlickerTest) :
+class SwitchBackToSplitFromHome(override val flicker: LegacyFlickerTest) :
SwitchBackToSplitFromHomeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -149,11 +149,10 @@ class SwitchBackToSplitFromHome(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
index 7c46d3e099a2..f7a9ed073002 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
@@ -21,15 +21,15 @@ import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.appWindowBecomesVisible
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromRecentBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.appWindowBecomesVisible
+import com.android.wm.shell.flicker.utils.layerBecomesVisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -39,13 +39,13 @@ import org.junit.runners.Parameterized
/**
* Test switch back to split pair from recent.
*
- * To run this test: `atest WMShellFlickerTests:SwitchBackToSplitFromRecent`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchBackToSplitFromRecent`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromRecent(override val flicker: FlickerTest) :
+class SwitchBackToSplitFromRecent(override val flicker: LegacyFlickerTest) :
SwitchBackToSplitFromRecentBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -149,11 +149,10 @@ class SwitchBackToSplitFromRecent(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
index 674ba40f6a1f..66f9b85ea572 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
@@ -17,27 +17,21 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowBecomesInvisible
-import com.android.wm.shell.flicker.appWindowBecomesVisible
-import com.android.wm.shell.flicker.appWindowIsInvisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
-import com.android.wm.shell.flicker.layerBecomesInvisible
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsSnapToDivider
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBetweenSplitPairsBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.utils.appWindowBecomesInvisible
+import com.android.wm.shell.flicker.utils.appWindowBecomesVisible
+import com.android.wm.shell.flicker.utils.layerBecomesInvisible
+import com.android.wm.shell.flicker.utils.layerBecomesVisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsSnapToDivider
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -47,13 +41,13 @@ import org.junit.runners.Parameterized
/**
* Test quick switch between two split pairs.
*
- * To run this test: `atest WMShellFlickerTests:SwitchBetweenSplitPairs`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchBetweenSplitPairs`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBetweenSplitPairs(override val flicker: FlickerTest) :
+class SwitchBetweenSplitPairs(override val flicker: LegacyFlickerTest) :
SwitchBetweenSplitPairsBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -62,21 +56,6 @@ class SwitchBetweenSplitPairs(override val flicker: FlickerTest) :
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- override fun cujCompleted() {
- flicker.appWindowIsVisibleAtStart(thirdApp)
- flicker.appWindowIsVisibleAtStart(fourthApp)
- flicker.splitScreenDividerIsVisibleAtStart()
-
- flicker.appWindowIsVisibleAtEnd(primaryApp)
- flicker.appWindowIsVisibleAtEnd(secondaryApp)
- flicker.appWindowIsInvisibleAtEnd(thirdApp)
- flicker.appWindowIsInvisibleAtEnd(fourthApp)
- flicker.splitScreenDividerIsVisibleAtEnd()
- }
-
@Presubmit
@Test
fun splitScreenDividerInvisibleAtMiddle() =
@@ -223,8 +202,6 @@ class SwitchBetweenSplitPairs(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
new file mode 100644
index 000000000000..e59ed6491eca
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.wm.shell.flicker.splitscreen.benchmark.SplitScreenBase
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.layerBecomesInvisible
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsSnapToDivider
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switch between two split pairs.
+ *
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchBetweenSplitPairsNoPip`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class SwitchBetweenSplitPairsNoPip(override val flicker: LegacyFlickerTest) :
+ SplitScreenBase(flicker) {
+
+ val thirdApp = SplitScreenUtils.getSendNotification(instrumentation)
+ val pipApp = PipAppHelper(instrumentation)
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ tapl.goHome()
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, thirdApp, pipApp)
+ pipApp.enableAutoEnterForPipActivity()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, thirdApp, pipApp)
+ }
+ transitions {
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ teardown {
+ pipApp.exit(wmHelper)
+ thirdApp.exit(wmHelper)
+ }
+ }
+
+ /** Checks that [pipApp] window won't enter pip */
+ @Presubmit
+ @Test
+ fun notEnterPip() {
+ flicker.assertWm { isNotPinned(pipApp) }
+ }
+
+ /** Checks the [pipApp] task did not reshow during transition. */
+ @Presubmit
+ @Test
+ fun app1WindowIsVisibleOnceApp2WindowIsInvisible() {
+ flicker.assertLayers {
+ this.isVisible(pipApp)
+ .then()
+ .isVisible(ComponentNameMatcher.LAUNCHER, isOptional = true)
+ .then()
+ .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
+ .then()
+ .isInvisible(pipApp)
+ .isVisible(secondaryApp)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun primaryAppBoundsIsVisibleAtEnd() =
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ primaryApp,
+ landscapePosLeft = tapl.isTablet,
+ portraitPosTop = false
+ )
+
+ @Presubmit
+ @Test
+ fun secondaryAppBoundsIsVisibleAtEnd() =
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ secondaryApp,
+ landscapePosLeft = !tapl.isTablet,
+ portraitPosTop = true
+ )
+
+ /** Checks the [pipApp] task become invisible after transition finish. */
+ @Presubmit @Test fun pipAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(pipApp)
+
+ /** Checks the [pipApp] task is in split screen bounds when transition start. */
+ @Presubmit
+ @Test
+ fun pipAppBoundsIsVisibleAtBegin() =
+ flicker.assertLayersStart {
+ this.splitAppLayerBoundsSnapToDivider(
+ pipApp,
+ landscapePosLeft = !tapl.isTablet,
+ portraitPosTop = true,
+ flicker.scenario.startRotation
+ )
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
index 676c150815ad..4c4402803ae2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
@@ -16,20 +16,24 @@
package com.android.wm.shell.flicker.splitscreen
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
+import android.tools.common.flicker.subject.layers.LayersTraceSubject
import android.tools.common.flicker.subject.region.RegionSubject
+import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.ICommonAssertions
-import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitscreen.benchmark.UnlockKeyguardToSplitScreenBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.layerIsVisibleAtEnd
+import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,26 +41,42 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test unlocking insecure keyguard to back to split screen tasks and verify the transition behavior.
+ * Test unlocking insecure keyguard to back to split screen tasks and verify the transition
+ * behavior.
*
- * To run this test: `atest WMShellFlickerTests:UnlockKeyguardToSplitScreen`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:UnlockKeyguardToSplitScreen`
*/
@RequiresDevice
@Postsubmit
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class UnlockKeyguardToSplitScreen(override val flicker: FlickerTest) :
- UnlockKeyguardToSplitScreenBenchmark(flicker), ICommonAssertions {
+class UnlockKeyguardToSplitScreen(override val flicker: LegacyFlickerTest) :
+ UnlockKeyguardToSplitScreenBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
- defaultSetup(this)
defaultTeardown(this)
thisTransition(this)
}
@Test
+ @FlakyTest(bugId = 293578017)
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ // TODO(b/293578017) remove once that bug is resolve
+ @Test
+ @Presubmit
+ fun visibleLayersShownMoreThanOneConsecutiveEntry_withoutWallpaper() =
+ flicker.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +
+ listOf(WALLPAPER_BBQ_WRAPPER)
+ )
+ }
+
+ @Test
fun splitScreenDividerIsVisibleAtEnd() {
flicker.assertLayersEnd { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
@@ -65,33 +85,35 @@ class UnlockKeyguardToSplitScreen(override val flicker: FlickerTest) :
@Test
fun primaryAppBoundsIsVisibleAtEnd() =
- flicker.splitAppLayerBoundsIsVisibleAtEnd(
- primaryApp,
- landscapePosLeft = false,
- portraitPosTop = false
- )
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ primaryApp,
+ landscapePosLeft = false,
+ portraitPosTop = false
+ )
@Test
fun secondaryAppBoundsIsVisibleAtEnd() =
- flicker.splitAppLayerBoundsIsVisibleAtEnd(
- secondaryApp,
- landscapePosLeft = true,
- portraitPosTop = true
- )
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ secondaryApp,
+ landscapePosLeft = true,
+ portraitPosTop = true
+ )
- @Test
- fun primaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(primaryApp)
+ @Test fun primaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(primaryApp)
- @Test
- fun secondaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(secondaryApp)
+ @Test fun secondaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(secondaryApp)
@Test
fun notOverlapsForPrimaryAndSecondaryAppLayers() {
flicker.assertLayers {
this.invoke("notOverlapsForPrimaryAndSecondaryLayers") {
- val primaryAppRegions = it.subjects.filter { subject ->
- subject.name.contains(primaryApp.toLayerName()) && subject.isVisible
- }.mapNotNull { primaryApp -> primaryApp.layer.visibleRegion }.toTypedArray()
+ val primaryAppRegions =
+ it.subjects
+ .filter { subject ->
+ subject.name.contains(primaryApp.toLayerName()) && subject.isVisible
+ }
+ .mapNotNull { primaryApp -> primaryApp.layer.visibleRegion }
+ .toTypedArray()
val primaryAppRegionArea = RegionSubject(primaryAppRegions, it.timestamp)
it.visibleRegion(secondaryApp).notOverlaps(primaryAppRegionArea.region)
@@ -102,10 +124,9 @@ class UnlockKeyguardToSplitScreen(override val flicker: FlickerTest) :
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
index c3c5f88eaa29..4d9007093cea 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
@@ -16,18 +16,14 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -36,7 +32,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CopyContentInSplitBenchmark(override val flicker: FlickerTest) :
+abstract class CopyContentInSplitBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val textEditApp = SplitScreenUtils.getIme(instrumentation)
protected val magnifierLayer = ComponentNameMatcher("", "magnifier surface bbq wrapper#")
@@ -54,26 +50,9 @@ open class CopyContentInSplitBenchmark(override val flicker: FlickerTest) :
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- open fun cujCompleted() {
- // The validation of copied text is already done in SplitScreenUtils.copyContentInSplit()
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
index 37cd18fad521..8360e94a6c3e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
@@ -16,18 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenDismissed
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -36,7 +31,8 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class DismissSplitScreenByDividerBenchmark(flicker: FlickerTest) : SplitScreenBase(flicker) {
+abstract class DismissSplitScreenByDividerBenchmark(override val flicker: LegacyFlickerTest) :
+ SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
@@ -60,24 +56,9 @@ open class DismissSplitScreenByDividerBenchmark(flicker: FlickerTest) : SplitScr
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = false)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
index 0ec6dc96bcd9..e74587843a72 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
@@ -16,18 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenDismissed
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -36,7 +31,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class DismissSplitScreenByGoHomeBenchmark(override val flicker: FlickerTest) :
+abstract class DismissSplitScreenByGoHomeBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -47,24 +42,9 @@ open class DismissSplitScreenByGoHomeBenchmark(override val flicker: FlickerTest
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
index 190e2e765bcc..c3beb366cc66 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
@@ -16,19 +16,15 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -37,7 +33,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class DragDividerToResizeBenchmark(override val flicker: FlickerTest) :
+abstract class DragDividerToResizeBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -45,32 +41,14 @@ open class DragDividerToResizeBenchmark(override val flicker: FlickerTest) :
transitions { SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper) }
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet || !flicker.scenario.isLandscapeOrSeascapeAtStart)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- open fun cujCompleted() {
- // TODO(b/246490534): Add validation for resized app after withAppTransitionIdle is
- // robust enough to get the correct end state.
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
index 3a1d1a4415c3..394864ad9d4d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
@@ -16,21 +16,16 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,7 +34,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: FlickerTest) :
+abstract class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
@@ -52,43 +47,23 @@ open class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: Flic
tapl.launchedAppState.taskbar
.openAllApps()
.getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
index 2033b7d64416..cd3fbab1497b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
@@ -16,21 +16,16 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,8 +34,9 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromNotificationBenchmark(override val flicker: FlickerTest) :
- SplitScreenBase(flicker) {
+abstract class EnterSplitScreenByDragFromNotificationBenchmark(
+ override val flicker: LegacyFlickerTest
+) : SplitScreenBase(flicker) {
protected val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -58,21 +54,6 @@ open class EnterSplitScreenByDragFromNotificationBenchmark(override val flicker:
teardown { sendNotificationApp.exit(wmHelper) }
}
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(primaryApp, sendNotificationApp, fromOtherApp = false)
-
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet)
@@ -81,11 +62,10 @@ open class EnterSplitScreenByDragFromNotificationBenchmark(override val flicker:
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
index b7a7110afe25..3b3be84f9841 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
@@ -16,21 +16,16 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,8 +34,9 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromShortcutBenchmark(flicker: FlickerTest) :
- SplitScreenBase(flicker) {
+abstract class EnterSplitScreenByDragFromShortcutBenchmark(
+ override val flicker: LegacyFlickerTest
+) : SplitScreenBase(flicker) {
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet)
@@ -57,38 +53,18 @@ open class EnterSplitScreenByDragFromShortcutBenchmark(flicker: FlickerTest) :
.getAppIcon(secondaryApp.appName)
.openDeepShortcutMenu()
.getMenuItem("Split Screen Secondary Activity")
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
index b1ce62f99e6c..eff355987cc0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
@@ -16,21 +16,16 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,7 +34,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: FlickerTest) :
+abstract class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -51,31 +46,11 @@ open class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: Flic
transitions {
tapl.launchedAppState.taskbar
.getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ .dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
}
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet)
@@ -84,10 +59,9 @@ open class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: Flic
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
index 14f07453b7d1..be507d833986 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
@@ -16,18 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -36,7 +31,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenFromOverviewBenchmark(override val flicker: FlickerTest) :
+abstract class EnterSplitScreenFromOverviewBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -56,24 +51,9 @@ open class EnterSplitScreenFromOverviewBenchmark(override val flicker: FlickerTe
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
index 195b73a14a72..a0e437c25aa7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
@@ -14,15 +14,16 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.splitscreen
+package com.android.wm.shell.flicker.splitscreen.benchmark
import android.content.Context
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.helpers.setRotation
import com.android.wm.shell.flicker.BaseBenchmarkTest
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
-abstract class SplitScreenBase(flicker: FlickerTest) : BaseBenchmarkTest(flicker) {
+abstract class SplitScreenBase(flicker: LegacyFlickerTest) : BaseBenchmarkTest(flicker) {
protected val context: Context = instrumentation.context
protected val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
protected val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
@@ -32,7 +33,10 @@ abstract class SplitScreenBase(flicker: FlickerTest) : BaseBenchmarkTest(flicker
tapl.setEnableRotation(true)
setRotation(flicker.scenario.startRotation)
tapl.setExpectedRotation(flicker.scenario.startRotation.value)
- tapl.workspace.switchToOverview().dismissAllTasks()
+ val overview = tapl.workspace.switchToOverview()
+ if (overview.hasTasks()) {
+ overview.dismissAllTasks()
+ }
}
}
@@ -42,11 +46,4 @@ abstract class SplitScreenBase(flicker: FlickerTest) : BaseBenchmarkTest(flicker
secondaryApp.exit(wmHelper)
}
}
-
- protected open val withoutTracing: FlickerBuilder.() -> Unit = {
- withoutLayerTracing()
- withoutWindowManagerTracing()
- withoutTransitionTracing()
- withoutTransactionsTracing()
- }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
index 65fb1358a9b0..ed0debd01408 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
@@ -16,21 +16,17 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import android.tools.device.traces.parsers.WindowManagerStateHelper
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,7 +35,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchAppByDoubleTapDividerBenchmark(override val flicker: FlickerTest) :
+abstract class SwitchAppByDoubleTapDividerBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -53,14 +49,6 @@ open class SwitchAppByDoubleTapDividerBenchmark(override val flicker: FlickerTes
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
private fun waitForWindowsToSwitch(wmHelper: WindowManagerStateHelper) {
wmHelper
.StateSyncBuilder()
@@ -134,22 +122,13 @@ open class SwitchAppByDoubleTapDividerBenchmark(override val flicker: FlickerTes
return displayBounds.width > displayBounds.height
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- open fun cujCompleted() {
- // TODO(b/246490534): Add validation for switched app after withAppTransitionIdle is
- // robust enough to get the correct end state.
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
index b333aba447a2..9b7939a3a006 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
@@ -16,19 +16,14 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -37,7 +32,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: FlickerTest) :
+abstract class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
private val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
@@ -55,27 +50,13 @@ open class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: Flicke
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
index a27540efdad7..9326ef3024a4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
@@ -16,19 +16,14 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -37,7 +32,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBackToSplitFromHomeBenchmark(override val flicker: FlickerTest) :
+abstract class SwitchBackToSplitFromHomeBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -53,27 +48,13 @@ open class SwitchBackToSplitFromHomeBenchmark(override val flicker: FlickerTest)
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
index 18bf4ff054e0..b928e40108bf 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
@@ -16,19 +16,14 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -37,7 +32,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBackToSplitFromRecentBenchmark(override val flicker: FlickerTest) :
+abstract class SwitchBackToSplitFromRecentBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -53,27 +48,13 @@ open class SwitchBackToSplitFromRecentBenchmark(override val flicker: FlickerTes
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
index c5fe61e26733..f314995fa947 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
@@ -16,17 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -35,7 +31,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBetweenSplitPairsBenchmark(override val flicker: FlickerTest) :
+abstract class SwitchBetweenSplitPairsBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thirdApp = SplitScreenUtils.getIme(instrumentation)
protected val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
@@ -64,14 +60,9 @@ open class SwitchBetweenSplitPairsBenchmark(override val flicker: FlickerTest) :
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit @Test open fun cujCompleted() {}
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
index 5f16e5b4d65e..e71834de7123 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
@@ -19,11 +19,10 @@ package com.android.wm.shell.flicker.splitscreen.benchmark
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -33,11 +32,11 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class UnlockKeyguardToSplitScreenBenchmark(override val flicker: FlickerTest) :
- SplitScreenBase(flicker) {
+abstract class UnlockKeyguardToSplitScreenBenchmark(override val flicker: LegacyFlickerTest) :
+ SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ setup { SplitScreenUtils.enterSplitViaIntent(wmHelper, primaryApp, secondaryApp) }
transitions {
device.sleep()
wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
@@ -47,21 +46,12 @@ open class UnlockKeyguardToSplitScreenBenchmark(override val flicker: FlickerTes
}
}
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
index 798cc95c020f..f1cb37ee1293 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
@@ -16,25 +16,25 @@
@file:JvmName("CommonAssertions")
-package com.android.wm.shell.flicker
+package com.android.wm.shell.flicker.utils
import android.tools.common.Rotation
import android.tools.common.datatypes.Region
import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
import android.tools.common.flicker.subject.layers.LayersTraceSubject
import android.tools.common.traces.component.IComponentMatcher
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.helpers.WindowUtils
-fun FlickerTest.appPairsDividerIsVisibleAtEnd() {
+fun LegacyFlickerTest.appPairsDividerIsVisibleAtEnd() {
assertLayersEnd { this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
}
-fun FlickerTest.appPairsDividerIsInvisibleAtEnd() {
+fun LegacyFlickerTest.appPairsDividerIsInvisibleAtEnd() {
assertLayersEnd { this.notContains(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
}
-fun FlickerTest.appPairsDividerBecomesVisible() {
+fun LegacyFlickerTest.appPairsDividerBecomesVisible() {
assertLayers {
this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
.then()
@@ -42,7 +42,7 @@ fun FlickerTest.appPairsDividerBecomesVisible() {
}
}
-fun FlickerTest.splitScreenEntered(
+fun LegacyFlickerTest.splitScreenEntered(
component1: IComponentMatcher,
component2: IComponentMatcher,
fromOtherApp: Boolean,
@@ -69,7 +69,7 @@ fun FlickerTest.splitScreenEntered(
splitScreenDividerIsVisibleAtEnd()
}
-fun FlickerTest.splitScreenDismissed(
+fun LegacyFlickerTest.splitScreenDismissed(
component1: IComponentMatcher,
component2: IComponentMatcher,
toHome: Boolean
@@ -87,27 +87,27 @@ fun FlickerTest.splitScreenDismissed(
splitScreenDividerIsInvisibleAtEnd()
}
-fun FlickerTest.splitScreenDividerIsVisibleAtStart() {
+fun LegacyFlickerTest.splitScreenDividerIsVisibleAtStart() {
assertLayersStart { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
-fun FlickerTest.splitScreenDividerIsVisibleAtEnd() {
+fun LegacyFlickerTest.splitScreenDividerIsVisibleAtEnd() {
assertLayersEnd { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
-fun FlickerTest.splitScreenDividerIsInvisibleAtStart() {
+fun LegacyFlickerTest.splitScreenDividerIsInvisibleAtStart() {
assertLayersStart { this.isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
-fun FlickerTest.splitScreenDividerIsInvisibleAtEnd() {
+fun LegacyFlickerTest.splitScreenDividerIsInvisibleAtEnd() {
assertLayersEnd { this.isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
-fun FlickerTest.splitScreenDividerBecomesVisible() {
+fun LegacyFlickerTest.splitScreenDividerBecomesVisible() {
layerBecomesVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
}
-fun FlickerTest.splitScreenDividerBecomesInvisible() {
+fun LegacyFlickerTest.splitScreenDividerBecomesInvisible() {
assertLayers {
this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
.then()
@@ -115,23 +115,23 @@ fun FlickerTest.splitScreenDividerBecomesInvisible() {
}
}
-fun FlickerTest.layerBecomesVisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.layerBecomesVisible(component: IComponentMatcher) {
assertLayers { this.isInvisible(component).then().isVisible(component) }
}
-fun FlickerTest.layerBecomesInvisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.layerBecomesInvisible(component: IComponentMatcher) {
assertLayers { this.isVisible(component).then().isInvisible(component) }
}
-fun FlickerTest.layerIsVisibleAtEnd(component: IComponentMatcher) {
+fun LegacyFlickerTest.layerIsVisibleAtEnd(component: IComponentMatcher) {
assertLayersEnd { this.isVisible(component) }
}
-fun FlickerTest.layerKeepVisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.layerKeepVisible(component: IComponentMatcher) {
assertLayers { this.isVisible(component) }
}
-fun FlickerTest.splitAppLayerBoundsBecomesVisible(
+fun LegacyFlickerTest.splitAppLayerBoundsBecomesVisible(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -150,7 +150,7 @@ fun FlickerTest.splitAppLayerBoundsBecomesVisible(
}
}
-fun FlickerTest.splitAppLayerBoundsBecomesVisibleByDrag(component: IComponentMatcher) {
+fun LegacyFlickerTest.splitAppLayerBoundsBecomesVisibleByDrag(component: IComponentMatcher) {
assertLayers {
this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component), isOptional = true)
.then()
@@ -161,7 +161,7 @@ fun FlickerTest.splitAppLayerBoundsBecomesVisibleByDrag(component: IComponentMat
}
}
-fun FlickerTest.splitAppLayerBoundsBecomesInvisible(
+fun LegacyFlickerTest.splitAppLayerBoundsBecomesInvisible(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -180,7 +180,7 @@ fun FlickerTest.splitAppLayerBoundsBecomesInvisible(
}
}
-fun FlickerTest.splitAppLayerBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.splitAppLayerBoundsIsVisibleAtEnd(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -195,7 +195,7 @@ fun FlickerTest.splitAppLayerBoundsIsVisibleAtEnd(
}
}
-fun FlickerTest.splitAppLayerBoundsKeepVisible(
+fun LegacyFlickerTest.splitAppLayerBoundsKeepVisible(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -210,7 +210,7 @@ fun FlickerTest.splitAppLayerBoundsKeepVisible(
}
}
-fun FlickerTest.splitAppLayerBoundsChanges(
+fun LegacyFlickerTest.splitAppLayerBoundsChanges(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -265,6 +265,7 @@ fun LayerTraceEntrySubject.splitAppLayerBoundsSnapToDivider(
val dividerRegion =
layer(SPLIT_SCREEN_DIVIDER_COMPONENT)?.visibleRegion?.region
?: error("$SPLIT_SCREEN_DIVIDER_COMPONENT component not found")
+ visibleRegion(component).isNotEmpty()
visibleRegion(component)
.coversAtMost(
if (displayBounds.width > displayBounds.height) {
@@ -304,7 +305,7 @@ fun LayerTraceEntrySubject.splitAppLayerBoundsSnapToDivider(
}
}
-fun FlickerTest.appWindowBecomesVisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowBecomesVisible(component: IComponentMatcher) {
assertWm {
this.isAppWindowInvisible(component)
.then()
@@ -316,39 +317,39 @@ fun FlickerTest.appWindowBecomesVisible(component: IComponentMatcher) {
}
}
-fun FlickerTest.appWindowBecomesInvisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowBecomesInvisible(component: IComponentMatcher) {
assertWm { this.isAppWindowVisible(component).then().isAppWindowInvisible(component) }
}
-fun FlickerTest.appWindowIsVisibleAtStart(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsVisibleAtStart(component: IComponentMatcher) {
assertWmStart { this.isAppWindowVisible(component) }
}
-fun FlickerTest.appWindowIsVisibleAtEnd(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsVisibleAtEnd(component: IComponentMatcher) {
assertWmEnd { this.isAppWindowVisible(component) }
}
-fun FlickerTest.appWindowIsInvisibleAtStart(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsInvisibleAtStart(component: IComponentMatcher) {
assertWmStart { this.isAppWindowInvisible(component) }
}
-fun FlickerTest.appWindowIsInvisibleAtEnd(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsInvisibleAtEnd(component: IComponentMatcher) {
assertWmEnd { this.isAppWindowInvisible(component) }
}
-fun FlickerTest.appWindowIsNotContainAtStart(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsNotContainAtStart(component: IComponentMatcher) {
assertWmStart { this.notContains(component) }
}
-fun FlickerTest.appWindowKeepVisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowKeepVisible(component: IComponentMatcher) {
assertWm { this.isAppWindowVisible(component) }
}
-fun FlickerTest.dockedStackDividerIsVisibleAtEnd() {
+fun LegacyFlickerTest.dockedStackDividerIsVisibleAtEnd() {
assertLayersEnd { this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) }
}
-fun FlickerTest.dockedStackDividerBecomesVisible() {
+fun LegacyFlickerTest.dockedStackDividerBecomesVisible() {
assertLayers {
this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
.then()
@@ -356,7 +357,7 @@ fun FlickerTest.dockedStackDividerBecomesVisible() {
}
}
-fun FlickerTest.dockedStackDividerBecomesInvisible() {
+fun LegacyFlickerTest.dockedStackDividerBecomesInvisible() {
assertLayers {
this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
.then()
@@ -364,11 +365,11 @@ fun FlickerTest.dockedStackDividerBecomesInvisible() {
}
}
-fun FlickerTest.dockedStackDividerNotExistsAtEnd() {
+fun LegacyFlickerTest.dockedStackDividerNotExistsAtEnd() {
assertLayersEnd { this.notContains(DOCKED_STACK_DIVIDER_COMPONENT) }
}
-fun FlickerTest.appPairsPrimaryBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.appPairsPrimaryBoundsIsVisibleAtEnd(
rotation: Rotation,
primaryComponent: IComponentMatcher
) {
@@ -380,7 +381,7 @@ fun FlickerTest.appPairsPrimaryBoundsIsVisibleAtEnd(
}
}
-fun FlickerTest.dockedStackPrimaryBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.dockedStackPrimaryBoundsIsVisibleAtEnd(
rotation: Rotation,
primaryComponent: IComponentMatcher
) {
@@ -392,7 +393,7 @@ fun FlickerTest.dockedStackPrimaryBoundsIsVisibleAtEnd(
}
}
-fun FlickerTest.appPairsSecondaryBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.appPairsSecondaryBoundsIsVisibleAtEnd(
rotation: Rotation,
secondaryComponent: IComponentMatcher
) {
@@ -404,7 +405,7 @@ fun FlickerTest.appPairsSecondaryBoundsIsVisibleAtEnd(
}
}
-fun FlickerTest.dockedStackSecondaryBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.dockedStackSecondaryBoundsIsVisibleAtEnd(
rotation: Rotation,
secondaryComponent: IComponentMatcher
) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt
index 3bc1e2acd015..3b66d6addacd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt
@@ -16,7 +16,7 @@
@file:JvmName("CommonConstants")
-package com.android.wm.shell.flicker
+package com.android.wm.shell.flicker.utils
import android.tools.common.traces.component.ComponentNameMatcher
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
index 02d9a056afbf..7f58cedce63d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker
+package com.android.wm.shell.flicker.utils
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
@@ -32,7 +32,7 @@ import org.junit.Assume
import org.junit.Test
interface ICommonAssertions {
- val flicker: FlickerTest
+ val flicker: LegacyFlickerTest
/** Checks that all parts of the screen are covered during the transition */
@Presubmit @Test fun entireScreenCovered() = flicker.entireScreenCovered()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/MultiWindowUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MultiWindowUtils.kt
index 87b94ff8668b..9b3a480c06b1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/MultiWindowUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MultiWindowUtils.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker
+package com.android.wm.shell.flicker.utils
import android.app.Instrumentation
import android.content.Context
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/NotificationListener.kt
index e0ef92457f58..529c1254a64c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/NotificationListener.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker
+package com.android.wm.shell.flicker.utils
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
index 1063dfd8d737..3f8a1ae6bd79 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.splitscreen
+package com.android.wm.shell.flicker.utils
import android.app.Instrumentation
import android.graphics.Point
@@ -39,11 +39,10 @@ import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.NotificationAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
-import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
-import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import com.android.server.wm.flicker.testapp.ActivityOptions.SplitScreen.Primary
import org.junit.Assert.assertNotNull
-internal object SplitScreenUtils {
+object SplitScreenUtils {
private const val TIMEOUT_MS = 3_000L
private const val DRAG_DURATION_MS = 1_000L
private const val NOTIFICATION_SCROLLER = "notification_stack_scroller"
@@ -112,6 +111,16 @@ internal object SplitScreenUtils {
waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
+ fun enterSplitViaIntent(
+ wmHelper: WindowManagerStateHelper,
+ primaryApp: StandardAppHelper,
+ secondaryApp: StandardAppHelper
+ ) {
+ val stringExtras = mapOf(Primary.EXTRA_LAUNCH_ADJACENT to "true")
+ primaryApp.launchViaIntent(wmHelper, null, null, stringExtras)
+ waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
fun splitFromOverview(tapl: LauncherInstrumentation, device: UiDevice) {
// Note: The initial split position in landscape is different between tablet and phone.
// In landscape, tablet will let the first app split to right side, and phone will
@@ -314,14 +323,14 @@ internal object SplitScreenUtils {
dividerBar.drag(
Point(
if (dragToRight) {
- displayBounds.width * 4 / 5
+ displayBounds.right
} else {
- displayBounds.width * 1 / 5
+ displayBounds.left
},
if (dragToBottom) {
- displayBounds.height * 4 / 5
+ displayBounds.bottom
} else {
- displayBounds.height * 1 / 5
+ displayBounds.top
}
)
)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/WaitUtils.kt
index 556cb06f3ca1..cf2df4e17cb7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/WaitUtils.kt
@@ -16,7 +16,7 @@
@file:JvmName("WaitUtils")
-package com.android.wm.shell.flicker
+package com.android.wm.shell.flicker.utils
import android.os.SystemClock
diff --git a/libs/WindowManager/Shell/tests/flicker/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/flicker/trace_config/trace_config.textproto
new file mode 100644
index 000000000000..406ada97a07d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/trace_config/trace_config.textproto
@@ -0,0 +1,75 @@
+# Copyright (C) 2023 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.
+
+# proto-message: TraceConfig
+
+# Enable periodic flushing of the trace buffer into the output file.
+write_into_file: true
+
+# Writes the userspace buffer into the file every 1s.
+file_write_period_ms: 2500
+
+# See b/126487238 - we need to guarantee ordering of events.
+flush_period_ms: 30000
+
+# The trace buffers needs to be big enough to hold |file_write_period_ms| of
+# trace data. The trace buffer sizing depends on the number of trace categories
+# enabled and the device activity.
+
+# RSS events
+buffers: {
+ size_kb: 63488
+ fill_policy: RING_BUFFER
+}
+
+data_sources {
+ config {
+ name: "linux.process_stats"
+ target_buffer: 0
+ # polled per-process memory counters and process/thread names.
+ # If you don't want the polled counters, remove the "process_stats_config"
+ # section, but keep the data source itself as it still provides on-demand
+ # thread/process naming for ftrace data below.
+ process_stats_config {
+ scan_all_processes_on_start: true
+ }
+ }
+}
+
+data_sources: {
+ config {
+ name: "linux.ftrace"
+ ftrace_config {
+ ftrace_events: "ftrace/print"
+ ftrace_events: "task/task_newtask"
+ ftrace_events: "task/task_rename"
+ atrace_categories: "ss"
+ atrace_categories: "wm"
+ atrace_categories: "am"
+ atrace_categories: "aidl"
+ atrace_categories: "input"
+ atrace_categories: "binder_driver"
+ atrace_categories: "sched_process_exit"
+ atrace_apps: "com.android.server.wm.flicker.testapp"
+ atrace_apps: "com.android.systemui"
+ atrace_apps: "com.android.wm.shell.flicker"
+ atrace_apps: "com.android.wm.shell.flicker.other"
+ atrace_apps: "com.android.wm.shell.flicker.bubbles"
+ atrace_apps: "com.android.wm.shell.flicker.pip"
+ atrace_apps: "com.android.wm.shell.flicker.splitscreen"
+ atrace_apps: "com.google.android.apps.nexuslauncher"
+ }
+ }
+}
+
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index ad4d97f6fe40..38e9f390835c 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -61,7 +61,7 @@ android_test {
"libstaticjvmtiagent",
],
- kotlincflags: ["-Xjvm-default=enable"],
+ kotlincflags: ["-Xjvm-default=all"],
plugins: ["dagger2-compiler"],
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java
index 8278c67a9b4f..0dc16f44340f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java
@@ -64,18 +64,27 @@ public class BubbleOverflowTest extends ShellTestCase {
}
@Test
- public void test_initialize() {
+ public void test_initialize_forStack() {
assertThat(mOverflow.getExpandedView()).isNull();
- mOverflow.initialize(mBubbleController);
+ mOverflow.initialize(mBubbleController, /* forBubbleBar= */ false);
assertThat(mOverflow.getExpandedView()).isNotNull();
assertThat(mOverflow.getExpandedView().getBubbleKey()).isEqualTo(BubbleOverflow.KEY);
+ assertThat(mOverflow.getBubbleBarExpandedView()).isNull();
+ }
+
+ @Test
+ public void test_initialize_forBubbleBar() {
+ mOverflow.initialize(mBubbleController, /* forBubbleBar= */ true);
+
+ assertThat(mOverflow.getBubbleBarExpandedView()).isNotNull();
+ assertThat(mOverflow.getExpandedView()).isNull();
}
@Test
public void test_cleanUpExpandedState() {
- mOverflow.createExpandedView();
+ mOverflow.initialize(mBubbleController, /* forBubbleBar= */ false);
assertThat(mOverflow.getExpandedView()).isNotNull();
mOverflow.cleanUpExpandedState();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/MockToken.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockToken.java
index 09d474d1f97c..a97c19f17412 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/MockToken.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockToken.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.desktopmode;
+package com.android.wm.shell;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -25,16 +25,16 @@ import android.window.WindowContainerToken;
/**
* {@link WindowContainerToken} wrapper that supports a mock binder
*/
-class MockToken {
+public class MockToken {
private final WindowContainerToken mToken;
- MockToken() {
+ public MockToken() {
mToken = mock(WindowContainerToken.class);
IBinder binder = mock(IBinder.class);
when(mToken.asBinder()).thenReturn(binder);
}
- WindowContainerToken token() {
+ public WindowContainerToken token() {
return mToken;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
index 4fca8b46a069..2d9304705738 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
@@ -92,7 +92,7 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim
.build();
final Animator animator = mAnimRunner.createAnimator(
info, mStartTransaction, mFinishTransaction,
- () -> mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */),
+ () -> mFinishCallback.onTransitionFinished(null /* wct */),
new ArrayList());
// The animation should be empty when it is behind starting window.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
index ab1ccd4599a2..0b2265d4ce9c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
@@ -75,7 +75,7 @@ abstract class ActivityEmbeddingAnimationTestBase extends ShellTestCase {
assertNotNull(mAnimRunner);
mAnimSpec = mAnimRunner.mAnimationSpec;
assertNotNull(mAnimSpec);
- mFinishCallback = (wct, wctCB) -> {};
+ mFinishCallback = (wct) -> {};
spyOn(mController);
spyOn(mAnimRunner);
spyOn(mAnimSpec);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
index ba34f1f74cd3..270dbc49835f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
@@ -217,12 +217,10 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
doReturn(animator).when(mAnimRunner).createAnimator(any(), any(), any(), any(), any());
mController.startAnimation(mTransition, info, mStartTransaction,
mFinishTransaction, mFinishCallback);
- verify(mFinishCallback, never()).onTransitionFinished(any(), any());
+ verify(mFinishCallback, never()).onTransitionFinished(any());
mController.mergeAnimation(mTransition, info, new SurfaceControl.Transaction(),
- mTransition,
- (wct, cb) -> {
- });
- verify(mFinishCallback).onTransitionFinished(any(), any());
+ mTransition, (wct) -> {});
+ verify(mFinishCallback).onTransitionFinished(any());
}
@Test
@@ -238,9 +236,9 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
mController.startAnimation(mTransition, info, mStartTransaction,
mFinishTransaction, mFinishCallback);
- verify(mFinishCallback, never()).onTransitionFinished(any(), any());
+ verify(mFinishCallback, never()).onTransitionFinished(any());
mController.onAnimationFinished(mTransition);
- verify(mFinishCallback).onTransitionFinished(any(), any());
+ verify(mFinishCallback).onTransitionFinished(any());
// Should not call finish when the finish has already been called.
assertThrows(IllegalStateException.class,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataRepositoryTest.kt
new file mode 100644
index 000000000000..0e05e01a8da3
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataRepositoryTest.kt
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2023 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.bubbles
+
+import android.app.ActivityTaskManager
+import android.content.pm.LauncherApps
+import android.os.Handler
+import android.os.Looper
+import android.util.SparseArray
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.bubbles.storage.BubbleEntity
+import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
+import com.android.wm.shell.common.HandlerExecutor
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+
+class BubbleDataRepositoryTest : ShellTestCase() {
+
+ private val user0BubbleEntities = listOf(
+ BubbleEntity(
+ userId = 0,
+ packageName = "com.example.messenger",
+ shortcutId = "shortcut-1",
+ key = "0k1",
+ desiredHeight = 120,
+ desiredHeightResId = 0,
+ title = null,
+ taskId = 1,
+ locus = null,
+ isDismissable = true
+ ),
+ BubbleEntity(
+ userId = 10,
+ packageName = "com.example.chat",
+ shortcutId = "alice and bob",
+ key = "0k2",
+ desiredHeight = 0,
+ desiredHeightResId = 16537428,
+ title = "title",
+ taskId = 2,
+ locus = null
+ ),
+ BubbleEntity(
+ userId = 0,
+ packageName = "com.example.messenger",
+ shortcutId = "shortcut-2",
+ key = "0k3",
+ desiredHeight = 120,
+ desiredHeightResId = 0,
+ title = null,
+ taskId = ActivityTaskManager.INVALID_TASK_ID,
+ locus = null
+ )
+ )
+
+ private val user1BubbleEntities = listOf(
+ BubbleEntity(
+ userId = 1,
+ packageName = "com.example.messenger",
+ shortcutId = "shortcut-1",
+ key = "1k1",
+ desiredHeight = 120,
+ desiredHeightResId = 0,
+ title = null,
+ taskId = 3,
+ locus = null,
+ isDismissable = true
+ ),
+ BubbleEntity(
+ userId = 12,
+ packageName = "com.example.chat",
+ shortcutId = "alice and bob",
+ key = "1k2",
+ desiredHeight = 0,
+ desiredHeightResId = 16537428,
+ title = "title",
+ taskId = 4,
+ locus = null
+ ),
+ BubbleEntity(
+ userId = 1,
+ packageName = "com.example.messenger",
+ shortcutId = "shortcut-2",
+ key = "1k3",
+ desiredHeight = 120,
+ desiredHeightResId = 0,
+ title = null,
+ taskId = ActivityTaskManager.INVALID_TASK_ID,
+ locus = null
+ ),
+ BubbleEntity(
+ userId = 12,
+ packageName = "com.example.chat",
+ shortcutId = "alice",
+ key = "1k4",
+ desiredHeight = 0,
+ desiredHeightResId = 16537428,
+ title = "title",
+ taskId = 5,
+ locus = null
+ )
+ )
+
+ private val testHandler = Handler(Looper.getMainLooper())
+ private val mainExecutor = HandlerExecutor(testHandler)
+ private val launcherApps = mock(LauncherApps::class.java)
+
+ private val persistedBubbles = SparseArray<List<BubbleEntity>>()
+
+ private lateinit var dataRepository: BubbleDataRepository
+ private lateinit var persistentRepository: BubblePersistentRepository
+
+ @Before
+ fun setup() {
+ persistentRepository = BubblePersistentRepository(mContext)
+ dataRepository = spy(BubbleDataRepository(launcherApps, mainExecutor, persistentRepository))
+
+ persistedBubbles.put(0, user0BubbleEntities)
+ persistedBubbles.put(1, user1BubbleEntities)
+ }
+
+ @After
+ fun teardown() {
+ // Clean up any persisted bubbles for the next run
+ persistentRepository.persistsToDisk(SparseArray())
+ }
+
+ @Test
+ fun testFilterForActiveUsersAndPersist_allValid() {
+ // Matches all the users in user0BubbleEntities & user1BubbleEntities
+ val activeUserIds = listOf(0, 10, 1, 12)
+
+ val validEntitiesByUser = dataRepository.filterForActiveUsersAndPersist(
+ activeUserIds, persistedBubbles)
+
+ // No invalid users, so no changes
+ assertThat(persistedBubbles).isEqualTo(validEntitiesByUser)
+
+ // No invalid users, so no persist to disk happened
+ verify(dataRepository, never()).persistToDisk(
+ any(SparseArray<List<BubbleEntity>>()::class.java))
+ }
+
+ @Test
+ fun testFilterForActiveUsersAndPersist_invalidParent() {
+ // When we start, we do have user 0 bubbles.
+ assertThat(persistedBubbles.get(0)).isNotEmpty()
+
+ val activeUserIds = listOf(10, 1, 12) // Missing user 0
+ val validEntitiesByUser = dataRepository.filterForActiveUsersAndPersist(
+ activeUserIds, persistedBubbles)
+
+ // We no longer have any user 0 bubbles.
+ assertThat(validEntitiesByUser.get(0)).isNull()
+ // User 1 bubbles should be the same.
+ assertThat(validEntitiesByUser.get(1)).isEqualTo(user1BubbleEntities)
+
+ // Verify that persist to disk happened with the new valid entities list.
+ verify(dataRepository).persistToDisk(validEntitiesByUser)
+ }
+
+ @Test
+ fun testFilterForActiveUsersAndPersist_invalidChild() {
+ // Build a list to compare against (remove all user 12 bubbles)
+ val (user1EntitiesWithUser12, user1EntitiesWithoutUser12) =
+ user1BubbleEntities.partition { it.userId == 12 }
+
+ // Verify we start with user 12 bubbles
+ assertThat(persistedBubbles.get(1).containsAll(user1EntitiesWithUser12)).isTrue()
+
+ val activeUserIds = listOf(0, 10, 1) // Missing user 1's child user 12
+ val validEntitiesByUser = dataRepository.filterForActiveUsersAndPersist(
+ activeUserIds, persistedBubbles)
+
+ // We no longer have any user 12 bubbles.
+ assertThat(validEntitiesByUser.get(1)).isEqualTo(user1EntitiesWithoutUser12)
+
+ // Verify that persist to disk happened with the new valid entities list.
+ verify(dataRepository).persistToDisk(validEntitiesByUser)
+ }
+
+ fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
new file mode 100644
index 000000000000..139724f709c7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2023 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.bubbles;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.View.LAYOUT_DIRECTION_LTR;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Configuration;
+import android.graphics.Insets;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests operations and the resulting state managed by {@link BubblePositioner}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class BubblePositionerTest extends ShellTestCase {
+
+ private static final int MIN_WIDTH_FOR_TABLET = 600;
+
+ private BubblePositioner mPositioner;
+ private Configuration mConfiguration;
+
+ @Mock
+ private WindowManager mWindowManager;
+ @Mock
+ private WindowMetrics mWindowMetrics;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mConfiguration = spy(new Configuration());
+ TestableResources testableResources = mContext.getOrCreateTestableResources();
+ testableResources.overrideConfiguration(mConfiguration);
+
+ mPositioner = new BubblePositioner(mContext, mWindowManager);
+ }
+
+ @Test
+ public void testUpdate() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1000, 1200);
+ Rect availableRect = new Rect(screenBounds);
+ availableRect.inset(insets);
+
+ new WindowManagerConfig()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .setUpConfig();
+ mPositioner.update();
+
+ assertThat(mPositioner.getAvailableRect()).isEqualTo(availableRect);
+ assertThat(mPositioner.isLandscape()).isFalse();
+ assertThat(mPositioner.isLargeScreen()).isFalse();
+ assertThat(mPositioner.getInsets()).isEqualTo(insets);
+ }
+
+ @Test
+ public void testShowBubblesVertically_phonePortrait() {
+ new WindowManagerConfig().setOrientation(ORIENTATION_PORTRAIT).setUpConfig();
+ mPositioner.update();
+
+ assertThat(mPositioner.showBubblesVertically()).isFalse();
+ }
+
+ @Test
+ public void testShowBubblesVertically_phoneLandscape() {
+ new WindowManagerConfig().setOrientation(ORIENTATION_LANDSCAPE).setUpConfig();
+ mPositioner.update();
+
+ assertThat(mPositioner.isLandscape()).isTrue();
+ assertThat(mPositioner.showBubblesVertically()).isTrue();
+ }
+
+ @Test
+ public void testShowBubblesVertically_tablet() {
+ new WindowManagerConfig().setLargeScreen().setUpConfig();
+ mPositioner.update();
+
+ assertThat(mPositioner.showBubblesVertically()).isTrue();
+ }
+
+ /** If a resting position hasn't been set, calling it will return the default position. */
+ @Test
+ public void testGetRestingPosition_returnsDefaultPosition() {
+ new WindowManagerConfig().setUpConfig();
+ mPositioner.update();
+
+ PointF restingPosition = mPositioner.getRestingPosition();
+ PointF defaultPosition = mPositioner.getDefaultStartPosition();
+
+ assertThat(restingPosition).isEqualTo(defaultPosition);
+ }
+
+ /** If a resting position has been set, it'll return that instead of the default position. */
+ @Test
+ public void testGetRestingPosition_returnsRestingPosition() {
+ new WindowManagerConfig().setUpConfig();
+ mPositioner.update();
+
+ PointF restingPosition = new PointF(100, 100);
+ mPositioner.setRestingPosition(restingPosition);
+
+ assertThat(mPositioner.getRestingPosition()).isEqualTo(restingPosition);
+ }
+
+ /** Test that the default resting position on phone is in upper left. */
+ @Test
+ public void testGetRestingPosition_bubble_onPhone() {
+ new WindowManagerConfig().setUpConfig();
+ mPositioner.update();
+
+ RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ PointF restingPosition = mPositioner.getRestingPosition();
+
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left);
+ assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
+ }
+
+ @Test
+ public void testGetRestingPosition_bubble_onPhone_RTL() {
+ new WindowManagerConfig().setLayoutDirection(LAYOUT_DIRECTION_RTL).setUpConfig();
+ mPositioner.update();
+
+ RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ PointF restingPosition = mPositioner.getRestingPosition();
+
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right);
+ assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
+ }
+
+ /** Test that the default resting position on tablet is middle left. */
+ @Test
+ public void testGetRestingPosition_chatBubble_onTablet() {
+ new WindowManagerConfig().setLargeScreen().setUpConfig();
+ mPositioner.update();
+
+ RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ PointF restingPosition = mPositioner.getRestingPosition();
+
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left);
+ assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
+ }
+
+ @Test
+ public void testGetRestingPosition_chatBubble_onTablet_RTL() {
+ new WindowManagerConfig().setLargeScreen().setLayoutDirection(
+ LAYOUT_DIRECTION_RTL).setUpConfig();
+ mPositioner.update();
+
+ RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ PointF restingPosition = mPositioner.getRestingPosition();
+
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right);
+ assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
+ }
+
+ /**
+ * Calculates the Y position bubbles should be placed based on the config. Based on
+ * the calculations in {@link BubblePositioner#getDefaultStartPosition()} and
+ * {@link BubbleStackView.RelativeStackPosition}.
+ */
+ private float getDefaultYPosition() {
+ final boolean isTablet = mPositioner.isLargeScreen();
+
+ // On tablet the position is centered, on phone it is an offset from the top.
+ final float desiredY = isTablet
+ ? mPositioner.getScreenRect().height() / 2f - (mPositioner.getBubbleSize() / 2f)
+ : mContext.getResources().getDimensionPixelOffset(
+ R.dimen.bubble_stack_starting_offset_y);
+ // Since we're visually centering the bubbles on tablet, use total screen height rather
+ // than the available height.
+ final float height = isTablet
+ ? mPositioner.getScreenRect().height()
+ : mPositioner.getAvailableRect().height();
+ float offsetPercent = desiredY / height;
+ offsetPercent = Math.max(0f, Math.min(1f, offsetPercent));
+ final RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent;
+ }
+
+ /**
+ * Sets up window manager to return config values based on what you need for the test.
+ * By default it sets up a portrait phone without any insets.
+ */
+ private class WindowManagerConfig {
+ private Rect mScreenBounds = new Rect(0, 0, 1000, 2000);
+ private boolean mIsLargeScreen = false;
+ private int mOrientation = ORIENTATION_PORTRAIT;
+ private int mLayoutDirection = LAYOUT_DIRECTION_LTR;
+ private Insets mInsets = Insets.of(0, 0, 0, 0);
+
+ public WindowManagerConfig setScreenBounds(Rect screenBounds) {
+ mScreenBounds = screenBounds;
+ return this;
+ }
+
+ public WindowManagerConfig setLargeScreen() {
+ mIsLargeScreen = true;
+ return this;
+ }
+
+ public WindowManagerConfig setOrientation(int orientation) {
+ mOrientation = orientation;
+ return this;
+ }
+
+ public WindowManagerConfig setLayoutDirection(int layoutDirection) {
+ mLayoutDirection = layoutDirection;
+ return this;
+ }
+
+ public WindowManagerConfig setInsets(Insets insets) {
+ mInsets = insets;
+ return this;
+ }
+
+ public void setUpConfig() {
+ mConfiguration.smallestScreenWidthDp = mIsLargeScreen
+ ? MIN_WIDTH_FOR_TABLET
+ : MIN_WIDTH_FOR_TABLET - 1;
+ mConfiguration.orientation = mOrientation;
+
+ when(mConfiguration.getLayoutDirection()).thenReturn(mLayoutDirection);
+ WindowInsets windowInsets = mock(WindowInsets.class);
+ when(windowInsets.getInsetsIgnoringVisibility(anyInt())).thenReturn(mInsets);
+ when(mWindowMetrics.getWindowInsets()).thenReturn(windowInsets);
+ when(mWindowMetrics.getBounds()).thenReturn(mScreenBounds);
+ when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java
new file mode 100644
index 000000000000..d38b848fbb4d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 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.bubbles.bar;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.drawable.ColorDrawable;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.core.content.ContextCompat;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class BubbleBarHandleViewTest extends ShellTestCase {
+ private BubbleBarHandleView mHandleView;
+
+ @Before
+ public void setup() {
+ mHandleView = new BubbleBarHandleView(mContext);
+ }
+
+ @Test
+ public void testUpdateHandleColor_lightBg() {
+ mHandleView.updateHandleColor(false /* isRegionDark */, false /* animated */);
+
+ assertTrue(mHandleView.getClipToOutline());
+ assertTrue(mHandleView.getBackground() instanceof ColorDrawable);
+ ColorDrawable bgDrawable = (ColorDrawable) mHandleView.getBackground();
+ assertEquals(bgDrawable.getColor(),
+ ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_handle_dark));
+ }
+
+ @Test
+ public void testUpdateHandleColor_darkBg() {
+ mHandleView.updateHandleColor(true /* isRegionDark */, false /* animated */);
+
+ assertTrue(mHandleView.getClipToOutline());
+ assertTrue(mHandleView.getBackground() instanceof ColorDrawable);
+ ColorDrawable bgDrawable = (ColorDrawable) mHandleView.getBackground();
+ assertEquals(bgDrawable.getColor(),
+ ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_handle_light));
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/LaunchAdjacentControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/LaunchAdjacentControllerTest.kt
new file mode 100644
index 000000000000..9dc816b65d2e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/LaunchAdjacentControllerTest.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2023 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.common
+
+import android.os.IBinder
+import android.testing.AndroidTestingRunner
+import android.window.WindowContainerTransaction
+import android.window.WindowContainerTransaction.HierarchyOp
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.MockToken
+import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class LaunchAdjacentControllerTest : ShellTestCase() {
+
+ private lateinit var controller: LaunchAdjacentController
+
+ @Mock private lateinit var syncQueue: SyncTransactionQueue
+
+ @Before
+ fun setUp() {
+ controller = LaunchAdjacentController(syncQueue)
+ }
+
+ @Test
+ fun newInstance_enabledByDefault() {
+ assertThat(controller.launchAdjacentEnabled).isTrue()
+ }
+
+ @Test
+ fun setLaunchAdjacentRoot_launchAdjacentEnabled_setsFlagRoot() {
+ val token = MockToken().token()
+ controller.setLaunchAdjacentRoot(token)
+ val wct = getLatestTransactionOrFail()
+ assertThat(wct.getSetLaunchAdjacentFlagRootContainer()).isEqualTo(token.asBinder())
+ }
+
+ @Test
+ fun setLaunchAdjacentRoot_launchAdjacentDisabled_doesNotUpdateFlagRoot() {
+ val token = MockToken().token()
+ controller.launchAdjacentEnabled = false
+ controller.setLaunchAdjacentRoot(token)
+ verify(syncQueue, never()).queue(any())
+ }
+
+ @Test
+ fun clearLaunchAdjacentRoot_launchAdjacentEnabled_clearsFlagRoot() {
+ val token = MockToken().token()
+ controller.setLaunchAdjacentRoot(token)
+ controller.clearLaunchAdjacentRoot()
+ val wct = getLatestTransactionOrFail()
+ assertThat(wct.getClearLaunchAdjacentFlagRootContainer()).isEqualTo(token.asBinder())
+ }
+
+ @Test
+ fun clearLaunchAdjacentRoot_launchAdjacentDisabled_clearsFlagRoot() {
+ val token = MockToken().token()
+ controller.setLaunchAdjacentRoot(token)
+ controller.launchAdjacentEnabled = false
+ clearInvocations(syncQueue)
+
+ controller.clearLaunchAdjacentRoot()
+ val wct = getLatestTransactionOrFail()
+ assertThat(wct.getClearLaunchAdjacentFlagRootContainer()).isEqualTo(token.asBinder())
+ }
+
+ @Test
+ fun setLaunchAdjacentEnabled_wasDisabledWithContainerSet_setsFlagRoot() {
+ val token = MockToken().token()
+ controller.setLaunchAdjacentRoot(token)
+ controller.launchAdjacentEnabled = false
+ clearInvocations(syncQueue)
+
+ controller.launchAdjacentEnabled = true
+ val wct = getLatestTransactionOrFail()
+ assertThat(wct.getSetLaunchAdjacentFlagRootContainer()).isEqualTo(token.asBinder())
+ }
+
+ @Test
+ fun setLaunchAdjacentEnabled_containerNotSet_doesNotUpdateFlagRoot() {
+ controller.launchAdjacentEnabled = false
+ controller.launchAdjacentEnabled = true
+ verify(syncQueue, never()).queue(any())
+ }
+
+ @Test
+ fun setLaunchAdjacentEnabled_multipleTimes_setsFlagRootOnce() {
+ val token = MockToken().token()
+ controller.setLaunchAdjacentRoot(token)
+ controller.launchAdjacentEnabled = true
+ controller.launchAdjacentEnabled = true
+ // Only execute once
+ verify(syncQueue).queue(any())
+ }
+
+ @Test
+ fun setLaunchAdjacentDisabled_containerSet_clearsFlagRoot() {
+ val token = MockToken().token()
+ controller.setLaunchAdjacentRoot(token)
+ controller.launchAdjacentEnabled = false
+ val wct = getLatestTransactionOrFail()
+ assertThat(wct.getClearLaunchAdjacentFlagRootContainer()).isEqualTo(token.asBinder())
+ }
+
+ @Test
+ fun setLaunchAdjacentDisabled_containerNotSet_doesNotUpdateFlagRoot() {
+ controller.launchAdjacentEnabled = false
+ verify(syncQueue, never()).queue(any())
+ }
+
+ @Test
+ fun setLaunchAdjacentDisabled_multipleTimes_setsFlagRootOnce() {
+ val token = MockToken().token()
+ controller.setLaunchAdjacentRoot(token)
+ clearInvocations(syncQueue)
+ controller.launchAdjacentEnabled = false
+ controller.launchAdjacentEnabled = false
+ // Only execute once
+ verify(syncQueue).queue(any())
+ }
+
+ private fun getLatestTransactionOrFail(): WindowContainerTransaction {
+ val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ verify(syncQueue, atLeastOnce()).queue(arg.capture())
+ return arg.allValues.last().also { assertThat(it).isNotNull() }
+ }
+}
+
+private fun WindowContainerTransaction.getSetLaunchAdjacentFlagRootContainer(): IBinder {
+ return hierarchyOps
+ // Find the operation with the correct type
+ .filter { op -> op.type == HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT }
+ // For set flag root operation, toTop is false
+ .filter { op -> !op.toTop }
+ .map { it.container }
+ .first()
+}
+
+private fun WindowContainerTransaction.getClearLaunchAdjacentFlagRootContainer(): IBinder {
+ return hierarchyOps
+ // Find the operation with the correct type
+ .filter { op -> op.type == HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT }
+ // For clear flag root operation, toTop is true
+ .filter { op -> op.toTop }
+ .map { it.container }
+ .first()
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
new file mode 100644
index 000000000000..145c8f0ab8af
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2023 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.common.split;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CURSOR_HOVER_STATES_ENABLED;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
+import android.view.InputDevice;
+import android.view.InsetsState;
+import android.view.MotionEvent;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link DividerView} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DividerViewTest extends ShellTestCase {
+ private @Mock SplitWindowManager.ParentContainerCallbacks mCallbacks;
+ private @Mock SplitLayout.SplitLayoutHandler mSplitLayoutHandler;
+ private @Mock DisplayController mDisplayController;
+ private @Mock DisplayImeController mDisplayImeController;
+ private @Mock ShellTaskOrganizer mTaskOrganizer;
+ private SplitLayout mSplitLayout;
+ private DividerView mDividerView;
+
+ @Before
+ @UiThreadTest
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ Configuration configuration = getConfiguration();
+ mSplitLayout = new SplitLayout("TestSplitLayout", mContext, configuration,
+ mSplitLayoutHandler, mCallbacks, mDisplayController, mDisplayImeController,
+ mTaskOrganizer, SplitLayout.PARALLAX_NONE);
+ SplitWindowManager splitWindowManager = new SplitWindowManager("TestSplitWindowManager",
+ mContext,
+ configuration, mCallbacks);
+ splitWindowManager.init(mSplitLayout, new InsetsState());
+ mDividerView = spy((DividerView) splitWindowManager.getDividerView());
+ }
+
+ @Test
+ @UiThreadTest
+ public void testHoverDividerView() {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CURSOR_HOVER_STATES_ENABLED,
+ "true", false);
+
+ Rect dividerBounds = mSplitLayout.getDividerBounds();
+ int x = dividerBounds.centerX();
+ int y = dividerBounds.centerY();
+ long downTime = SystemClock.uptimeMillis();
+ mDividerView.onHoverEvent(getMotionEvent(downTime, MotionEvent.ACTION_HOVER_ENTER, x, y));
+
+ verify(mDividerView, times(1)).setHovering();
+
+ mDividerView.onHoverEvent(getMotionEvent(downTime, MotionEvent.ACTION_HOVER_EXIT, x, y));
+
+ verify(mDividerView, times(1)).releaseHovering();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CURSOR_HOVER_STATES_ENABLED,
+ "false", false);
+ }
+
+ private static MotionEvent getMotionEvent(long eventTime, int action, float x, float y) {
+ MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
+ properties.id = 0;
+ properties.toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
+
+ MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
+ coords.pressure = 1;
+ coords.size = 1;
+ coords.x = x;
+ coords.y = y;
+
+ return MotionEvent.obtain(eventTime, eventTime, action, 1,
+ new MotionEvent.PointerProperties[]{properties},
+ new MotionEvent.PointerCoords[]{coords}, 0, 0, 1.0f, 1.0f, 0, 0,
+ InputDevice.SOURCE_TOUCHSCREEN, 0);
+ }
+
+ private static Configuration getConfiguration() {
+ final Configuration configuration = new Configuration();
+ configuration.unset();
+ configuration.orientation = ORIENTATION_LANDSCAPE;
+ configuration.windowConfiguration.setRotation(0);
+ configuration.windowConfiguration.setBounds(new Rect(0, 0, 1080, 2160));
+ return configuration;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
index d6387ee5ae13..605a762a395f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -59,6 +59,7 @@ import android.window.WindowContainerTransaction.HierarchyOp;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.wm.shell.MockToken;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
index 3bc2f0e8674e..3fe78efdf2b1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -129,6 +129,18 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() {
}
@Test
+ fun addListener_notifiesStashed() {
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+ executor.flushAll()
+
+ assertThat(listener.stashedOnDefaultDisplay).isTrue()
+ assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(1)
+ }
+
+ @Test
fun addListener_tasksOnDifferentDisplay_doesNotNotify() {
repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 1, visible = true)
val listener = TestVisibilityListener()
@@ -313,6 +325,65 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() {
assertThat(tasks.first()).isEqualTo(6)
}
+ @Test
+ fun setStashed_stateIsUpdatedForTheDisplay() {
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ assertThat(repo.isStashed(DEFAULT_DISPLAY)).isTrue()
+ assertThat(repo.isStashed(SECOND_DISPLAY)).isFalse()
+
+ repo.setStashed(DEFAULT_DISPLAY, false)
+ assertThat(repo.isStashed(DEFAULT_DISPLAY)).isFalse()
+ }
+
+ @Test
+ fun setStashed_notifyListener() {
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isTrue()
+ assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(1)
+
+ repo.setStashed(DEFAULT_DISPLAY, false)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isFalse()
+ assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(2)
+ }
+
+ @Test
+ fun setStashed_secondCallDoesNotNotify() {
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ executor.flushAll()
+ assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(1)
+ }
+
+ @Test
+ fun setStashed_tracksPerDisplay() {
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isTrue()
+ assertThat(listener.stashedOnSecondaryDisplay).isFalse()
+
+ repo.setStashed(SECOND_DISPLAY, true)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isTrue()
+ assertThat(listener.stashedOnSecondaryDisplay).isTrue()
+
+ repo.setStashed(DEFAULT_DISPLAY, false)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isFalse()
+ assertThat(listener.stashedOnSecondaryDisplay).isTrue()
+ }
+
class TestListener : DesktopModeTaskRepository.ActiveTasksListener {
var activeChangesOnDefaultDisplay = 0
var activeChangesOnSecondaryDisplay = 0
@@ -332,6 +403,12 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() {
var visibleChangesOnDefaultDisplay = 0
var visibleChangesOnSecondaryDisplay = 0
+ var stashedOnDefaultDisplay = false
+ var stashedOnSecondaryDisplay = false
+
+ var stashedChangesOnDefaultDisplay = 0
+ var stashedChangesOnSecondaryDisplay = 0
+
override fun onVisibilityChanged(displayId: Int, hasVisibleFreeformTasks: Boolean) {
when (displayId) {
DEFAULT_DISPLAY -> {
@@ -345,6 +422,20 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() {
else -> fail("Visible task listener received unexpected display id: $displayId")
}
}
+
+ override fun onStashedChanged(displayId: Int, stashed: Boolean) {
+ when (displayId) {
+ DEFAULT_DISPLAY -> {
+ stashedOnDefaultDisplay = stashed
+ stashedChangesOnDefaultDisplay++
+ }
+ SECOND_DISPLAY -> {
+ stashedOnSecondaryDisplay = stashed
+ stashedChangesOnDefaultDisplay++
+ }
+ else -> fail("Visible task listener received unexpected display id: $displayId")
+ }
+ }
}
companion object {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 1335ebf105a6..5d87cf8b25a6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -39,21 +39,25 @@ import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.dx.mockito.inline.extended.ExtendedMockito.never
import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.wm.shell.MockToken
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestRunningTaskInfoBuilder
import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.LaunchAdjacentController
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
+import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.After
@@ -77,6 +81,7 @@ import org.mockito.Mockito.`when` as whenever
class DesktopTasksControllerTest : ShellTestCase() {
@Mock lateinit var testExecutor: ShellExecutor
+ @Mock lateinit var shellCommandHandler: ShellCommandHandler
@Mock lateinit var shellController: ShellController
@Mock lateinit var displayController: DisplayController
@Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer
@@ -85,12 +90,17 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Mock lateinit var transitions: Transitions
@Mock lateinit var exitDesktopTransitionHandler: ExitDesktopTaskTransitionHandler
@Mock lateinit var enterDesktopTransitionHandler: EnterDesktopTaskTransitionHandler
+ @Mock lateinit var mToggleResizeDesktopTaskTransitionHandler:
+ ToggleResizeDesktopTaskTransitionHandler
+ @Mock lateinit var launchAdjacentController: LaunchAdjacentController
+ @Mock lateinit var desktopModeWindowDecoration: DesktopModeWindowDecoration
private lateinit var mockitoSession: StaticMockitoSession
private lateinit var controller: DesktopTasksController
private lateinit var shellInit: ShellInit
private lateinit var desktopModeTaskRepository: DesktopModeTaskRepository
+ private val shellExecutor = TestShellExecutor()
// Mock running tasks are registered here so we can get the list from mock shell task organizer
private val runningTasks = mutableListOf<RunningTaskInfo>()
@@ -114,6 +124,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
return DesktopTasksController(
context,
shellInit,
+ shellCommandHandler,
shellController,
displayController,
shellTaskOrganizer,
@@ -122,8 +133,10 @@ class DesktopTasksControllerTest : ShellTestCase() {
transitions,
enterDesktopTransitionHandler,
exitDesktopTransitionHandler,
+ mToggleResizeDesktopTaskTransitionHandler,
desktopModeTaskRepository,
- TestShellExecutor()
+ launchAdjacentController,
+ shellExecutor
)
}
@@ -262,17 +275,28 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
- fun moveToDesktop() {
+ fun moveToDesktop_displayFullscreen_windowingModeSetToFreeform() {
val task = setUpFullscreenTask()
- controller.moveToDesktop(task)
- val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
+ task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FULLSCREEN
+ controller.moveToDesktop(desktopModeWindowDecoration, task)
+ val wct = getLatestMoveToDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_FREEFORM)
}
@Test
+ fun moveToDesktop_displayFreeform_windowingModeSetToUndefined() {
+ val task = setUpFullscreenTask()
+ task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FREEFORM
+ controller.moveToDesktop(desktopModeWindowDecoration, task)
+ val wct = getLatestMoveToDesktopWct()
+ assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED)
+ }
+
+ @Test
fun moveToDesktop_nonExistentTask_doesNothing() {
- controller.moveToDesktop(999)
+ controller.moveToDesktop(desktopModeWindowDecoration, 999)
verifyWCTNotExecuted()
}
@@ -283,9 +307,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val fullscreenTask = setUpFullscreenTask()
markTaskHidden(freeformTask)
- controller.moveToDesktop(fullscreenTask)
+ controller.moveToDesktop(desktopModeWindowDecoration, fullscreenTask)
- with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
+ with(getLatestMoveToDesktopWct()) {
// Operations should include home task, freeform task
assertThat(hierarchyOps).hasSize(3)
assertReorderSequence(homeTask, freeformTask, fullscreenTask)
@@ -305,9 +329,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val freeformTaskSecond = setUpFreeformTask(displayId = SECOND_DISPLAY)
markTaskHidden(freeformTaskSecond)
- controller.moveToDesktop(fullscreenTaskDefault)
+ controller.moveToDesktop(desktopModeWindowDecoration, fullscreenTaskDefault)
- with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
+ with(getLatestMoveToDesktopWct()) {
// Check that hierarchy operations do not include tasks from second display
assertThat(hierarchyOps.map { it.container })
.doesNotContain(homeTaskSecond.token.asBinder())
@@ -317,12 +341,23 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
- fun moveToFullscreen() {
+ fun moveToFullscreen_displayFullscreen_windowingModeSetToUndefined() {
val task = setUpFreeformTask()
+ task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FULLSCREEN
controller.moveToFullscreen(task)
val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
- .isEqualTo(WINDOWING_MODE_FULLSCREEN)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED)
+ }
+
+ @Test
+ fun moveToFullscreen_displayFreeform_windowingModeSetToFullscreen() {
+ val task = setUpFreeformTask()
+ task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FREEFORM
+ controller.moveToFullscreen(task)
+ val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
+ assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_FULLSCREEN)
}
@Test
@@ -345,6 +380,18 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun moveTaskToFront_postsWctWithReorderOp() {
+ val task1 = setUpFreeformTask()
+ setUpFreeformTask()
+
+ controller.moveTaskToFront(task1)
+
+ val wct = getLatestWct(expectTransition = TRANSIT_TO_FRONT)
+ assertThat(wct.hierarchyOps).hasSize(1)
+ wct.assertReorderAt(index = 0, task1)
+ }
+
+ @Test
fun moveToNextDisplay_noOtherDisplays() {
whenever(rootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(DEFAULT_DISPLAY))
val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
@@ -451,6 +498,28 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun handleRequest_fullscreenTask_desktopStashed_returnWCTWithAllAppsBroughtToFront() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
+
+ val stashedFreeformTask = setUpFreeformTask(DEFAULT_DISPLAY)
+ markTaskHidden(stashedFreeformTask)
+
+ val fullscreenTask = createFullscreenTask(DEFAULT_DISPLAY)
+
+ controller.stashDesktopApps(DEFAULT_DISPLAY)
+
+ val result = controller.handleRequest(Binder(), createTransition(fullscreenTask))
+ assertThat(result).isNotNull()
+ result!!.assertReorderSequence(stashedFreeformTask, fullscreenTask)
+ assertThat(result.changes[fullscreenTask.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_FREEFORM)
+
+ // Stashed state should be cleared
+ assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isFalse()
+ }
+
+ @Test
fun handleRequest_freeformTask_freeformVisible_returnNull() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -501,6 +570,26 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun handleRequest_freeformTask_desktopStashed_returnWCTWithAllAppsBroughtToFront() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
+
+ val stashedFreeformTask = setUpFreeformTask(DEFAULT_DISPLAY)
+ markTaskHidden(stashedFreeformTask)
+
+ val freeformTask = createFreeformTask(DEFAULT_DISPLAY)
+
+ controller.stashDesktopApps(DEFAULT_DISPLAY)
+
+ val result = controller.handleRequest(Binder(), createTransition(freeformTask))
+ assertThat(result).isNotNull()
+ result?.assertReorderSequence(stashedFreeformTask, freeformTask)
+
+ // Stashed state should be cleared
+ assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isFalse()
+ }
+
+ @Test
fun handleRequest_notOpenOrToFrontTransition_returnNull() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -539,6 +628,50 @@ class DesktopTasksControllerTest : ShellTestCase() {
assertThat(controller.handleRequest(Binder(), createTransition(task))).isNull()
}
+ @Test
+ fun stashDesktopApps_stateUpdates() {
+ whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
+
+ controller.stashDesktopApps(DEFAULT_DISPLAY)
+
+ assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isTrue()
+ assertThat(desktopModeTaskRepository.isStashed(SECOND_DISPLAY)).isFalse()
+ }
+
+ @Test
+ fun hideStashedDesktopApps_stateUpdates() {
+ whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
+
+ desktopModeTaskRepository.setStashed(DEFAULT_DISPLAY, true)
+ desktopModeTaskRepository.setStashed(SECOND_DISPLAY, true)
+ controller.hideStashedDesktopApps(DEFAULT_DISPLAY)
+
+ assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isFalse()
+ // Check that second display is not affected
+ assertThat(desktopModeTaskRepository.isStashed(SECOND_DISPLAY)).isTrue()
+ }
+
+ @Test
+ fun desktopTasksVisibilityChange_visible_setLaunchAdjacentDisabled() {
+ val task = setUpFreeformTask()
+ clearInvocations(launchAdjacentController)
+
+ markTaskVisible(task)
+ shellExecutor.flushAll()
+ verify(launchAdjacentController).launchAdjacentEnabled = false
+ }
+
+ @Test
+ fun desktopTasksVisibilityChange_invisible_setLaunchAdjacentEnabled() {
+ val task = setUpFreeformTask()
+ markTaskVisible(task)
+ clearInvocations(launchAdjacentController)
+
+ markTaskHidden(task)
+ shellExecutor.flushAll()
+ verify(launchAdjacentController).launchAdjacentEnabled = true
+ }
+
private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
val task = createFreeformTask(displayId)
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
@@ -590,6 +723,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
return arg.value
}
+ private fun getLatestMoveToDesktopWct(): WindowContainerTransaction {
+ val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ if (ENABLE_SHELL_TRANSITIONS) {
+ verify(enterDesktopTransitionHandler).moveToDesktop(arg.capture(), any())
+ } else {
+ verify(shellTaskOrganizer).applyTransaction(arg.capture())
+ }
+ return arg.value
+ }
+
private fun verifyWCTNotExecuted() {
if (ENABLE_SHELL_TRANSITIONS) {
verify(transitions, never()).startTransition(anyInt(), any(), isNull())
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
index cf1ff3214d87..29a757c19d98 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
@@ -22,6 +22,7 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.view.Display.DEFAULT_DISPLAY
+import com.android.wm.shell.MockToken
import com.android.wm.shell.TestRunningTaskInfoBuilder
class DesktopTestHelpers {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
index 8592dea19289..772d97d8eb32 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.SurfaceControl;
@@ -41,6 +42,7 @@ import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.MoveToDesktopAnimator;
import junit.framework.AssertionFailedError;
@@ -73,6 +75,10 @@ public class EnterDesktopTaskTransitionHandlerTest {
ShellExecutor mExecutor;
@Mock
SurfaceControl mSurfaceControl;
+ @Mock
+ MoveToDesktopAnimator mMoveToDesktopAnimator;
+ @Mock
+ PointF mPosition;
private EnterDesktopTaskTransitionHandler mEnterDesktopTaskTransitionHandler;
@@ -82,6 +88,7 @@ public class EnterDesktopTaskTransitionHandlerTest {
doReturn(mExecutor).when(mTransitions).getMainExecutor();
doReturn(mAnimationT).when(mTransactionFactory).get();
+ doReturn(mPosition).when(mMoveToDesktopAnimator).getPosition();
mEnterDesktopTaskTransitionHandler = new EnterDesktopTaskTransitionHandler(mTransitions,
mTransactionFactory);
@@ -89,16 +96,20 @@ public class EnterDesktopTaskTransitionHandlerTest {
@Test
public void testEnterFreeformAnimation() {
- final int transitionType = Transitions.TRANSIT_ENTER_FREEFORM;
final int taskId = 1;
WindowContainerTransaction wct = new WindowContainerTransaction();
doReturn(mToken).when(mTransitions)
- .startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
- mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
+ .startTransition(Transitions.TRANSIT_START_DRAG_TO_DESKTOP_MODE, wct,
+ mEnterDesktopTaskTransitionHandler);
+ doReturn(taskId).when(mMoveToDesktopAnimator).getTaskId();
+
+ mEnterDesktopTaskTransitionHandler.startMoveToDesktop(wct,
+ mMoveToDesktopAnimator, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
- TransitionInfo info = createTransitionInfo(Transitions.TRANSIT_ENTER_FREEFORM, change);
+ TransitionInfo info = createTransitionInfo(Transitions.TRANSIT_START_DRAG_TO_DESKTOP_MODE,
+ change);
assertTrue(mEnterDesktopTaskTransitionHandler
@@ -110,17 +121,18 @@ public class EnterDesktopTaskTransitionHandlerTest {
@Test
public void testTransitEnterDesktopModeAnimation() throws Throwable {
- final int transitionType = Transitions.TRANSIT_ENTER_DESKTOP_MODE;
+ final int transitionType = Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE;
final int taskId = 1;
WindowContainerTransaction wct = new WindowContainerTransaction();
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
- mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
+ mEnterDesktopTaskTransitionHandler.finalizeMoveToDesktop(wct, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
change.setEndAbsBounds(new Rect(0, 0, 1, 1));
- TransitionInfo info = createTransitionInfo(Transitions.TRANSIT_ENTER_DESKTOP_MODE, change);
+ TransitionInfo info = createTransitionInfo(
+ Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE, change);
runOnUiThread(() -> {
try {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 7c1da35888b8..527dc0149716 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -133,8 +133,7 @@ public class DragAndDropPolicyTest extends ShellTestCase {
mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
mInsets = Insets.of(0, 0, 0, 0);
- mPolicy = spy(new DragAndDropPolicy(
- mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter));
+ mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mSplitScreenStarter));
mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
setClipDataResizeable(mNonResizeableActivityClipData, false);
@@ -206,7 +205,10 @@ public class DragAndDropPolicyTest extends ShellTestCase {
@Test
public void testDragAppOverFullscreenHome_expectOnlyFullscreenTarget() {
setRunningTask(mHomeTask);
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
+ mLandscapeDisplayLayout, mActivityClipData);
+ dragSession.update();
+ mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
@@ -218,7 +220,10 @@ public class DragAndDropPolicyTest extends ShellTestCase {
@Test
public void testDragAppOverFullscreenApp_expectSplitScreenTargets() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
+ mLandscapeDisplayLayout, mActivityClipData);
+ dragSession.update();
+ mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
@@ -235,7 +240,10 @@ public class DragAndDropPolicyTest extends ShellTestCase {
@Test
public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mPortraitDisplayLayout, mActivityClipData, mLoggerSessionId);
+ DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
+ mPortraitDisplayLayout, mActivityClipData);
+ dragSession.update();
+ mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
@@ -252,7 +260,10 @@ public class DragAndDropPolicyTest extends ShellTestCase {
@Test
public void testTargetHitRects() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
+ mLandscapeDisplayLayout, mActivityClipData);
+ dragSession.update();
+ mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = mPolicy.getTargets(mInsets);
for (Target t : targets) {
assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.left, t.hitRegion.top) == t);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
index 1379aedc2284..528c23cd8115 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
@@ -110,17 +110,17 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
sExpectedDefaultSizes.put(16f / 9, new Size(600, 338));
sExpectedMinSizes.put(16f / 9, new Size(501, 282));
- sExpectedMaxSizes.put(4f / 3, new Size(892, 669));
- sExpectedDefaultSizes.put(4f / 3, new Size(535, 401));
+ sExpectedMaxSizes.put(4f / 3, new Size(893, 670));
+ sExpectedDefaultSizes.put(4f / 3, new Size(536, 402));
sExpectedMinSizes.put(4f / 3, new Size(447, 335));
- sExpectedMaxSizes.put(3f / 4, new Size(669, 892));
- sExpectedDefaultSizes.put(3f / 4, new Size(401, 535));
+ sExpectedMaxSizes.put(3f / 4, new Size(670, 893));
+ sExpectedDefaultSizes.put(3f / 4, new Size(402, 536));
sExpectedMinSizes.put(3f / 4, new Size(335, 447));
- sExpectedMaxSizes.put(9f / 16, new Size(562, 999));
- sExpectedDefaultSizes.put(9f / 16, new Size(337, 599));
- sExpectedMinSizes.put(9f / 16, new Size(281, 500));
+ sExpectedMaxSizes.put(9f / 16, new Size(563, 1001));
+ sExpectedDefaultSizes.put(9f / 16, new Size(338, 601));
+ sExpectedMinSizes.put(9f / 16, new Size(282, 501));
}
private void forEveryTestCaseCheck(Map<Float, Size> expectedSizes,
@@ -192,7 +192,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
// an initial size with 16:9 aspect ratio
Size initSize = new Size(600, 337);
- Size expectedSize = new Size(337, 599);
+ Size expectedSize = new Size(338, 601);
Size actualSize = mPipSizeSpecHandler.getSizeForAspectRatio(initSize, 9f / 16);
Assert.assertEquals(expectedSize, actualSize);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
index 02e6b8c71663..ec84d7e20714 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
@@ -23,7 +23,9 @@ import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_EXPAND_COLLAPSE;
import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_FULLSCREEN;
import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_MOVE;
-import static org.junit.Assert.assertTrue;
+import static java.util.Collections.EMPTY_LIST;
+
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -34,7 +36,6 @@ import android.graphics.drawable.Icon;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.util.Log;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.pip.PipMediaController;
@@ -46,7 +47,9 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Unit tests for {@link TvPipActionsProvider}
@@ -69,35 +72,38 @@ public class TvPipActionProviderTest extends ShellTestCase {
@Mock
private PendingIntent mMockPendingIntent;
- private RemoteAction createRemoteAction(int identifier) {
+ private int mNumberOfRemoteActionsCreated = 0;
+
+ private RemoteAction createRemoteAction() {
+ final int identifier = mNumberOfRemoteActionsCreated++;
return new RemoteAction(mMockIcon, "" + identifier, "" + identifier, mMockPendingIntent);
}
private List<RemoteAction> createRemoteActions(int numberOfActions) {
List<RemoteAction> actions = new ArrayList<>();
for (int i = 0; i < numberOfActions; i++) {
- actions.add(createRemoteAction(i));
+ actions.add(createRemoteAction());
}
return actions;
}
- private boolean checkActionsMatch(List<TvPipAction> actions, int[] actionTypes) {
- for (int i = 0; i < actions.size(); i++) {
- int type = actions.get(i).getActionType();
- if (type != actionTypes[i]) {
- Log.e(TAG, "Action at index " + i + ": found " + type
- + ", expected " + actionTypes[i]);
- return false;
- }
- }
- return true;
+ private void assertActionTypes(List<Integer> expected, List<Integer> actual) {
+ assertEquals(getActionTypesStrings(expected), getActionTypesStrings(actual));
+ }
+
+ private static List<String> getActionTypesStrings(List<Integer> actionTypes) {
+ return actionTypes.stream().map(a -> TvPipAction.getActionTypeString(a))
+ .collect(Collectors.toList());
+ }
+
+ private List<Integer> getActionsTypes() {
+ return mActionsProvider.getActionsList().stream().map(a -> a.getActionType())
+ .collect(Collectors.toList());
}
@Before
public void setUp() {
- if (!isTelevision()) {
- return;
- }
+ assumeTelevision();
MockitoAnnotations.initMocks(this);
mActionsProvider = new TvPipActionsProvider(mContext, mMockPipMediaController,
mMockSystemActionsHandler);
@@ -105,57 +111,51 @@ public class TvPipActionProviderTest extends ShellTestCase {
@Test
public void defaultSystemActions_regularPip() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE}));
+ assertActionTypes(Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE),
+ getActionsTypes());
}
@Test
public void defaultSystemActions_expandedPip() {
- assumeTelevision();
mActionsProvider.updateExpansionEnabled(true);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE),
+ getActionsTypes());
}
@Test
public void expandedPip_enableExpansion_enable() {
- assumeTelevision();
// PiP has expanded PiP disabled.
- mActionsProvider.updateExpansionEnabled(false);
-
mActionsProvider.addListener(mMockListener);
mActionsProvider.updateExpansionEnabled(true);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE),
+ getActionsTypes());
verify(mMockListener).onActionsChanged(/* added= */ 1, /* updated= */ 0, /* index= */ 3);
}
@Test
public void expandedPip_enableExpansion_disable() {
- assumeTelevision();
mActionsProvider.updateExpansionEnabled(true);
mActionsProvider.addListener(mMockListener);
mActionsProvider.updateExpansionEnabled(false);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE),
+ getActionsTypes());
verify(mMockListener).onActionsChanged(/* added= */ -1, /* updated= */ 0, /* index= */ 3);
}
@Test
public void expandedPip_enableExpansion_AlreadyEnabled() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(true);
-
mActionsProvider.addListener(mMockListener);
mActionsProvider.updateExpansionEnabled(true);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE),
+ getActionsTypes());
}
private void check_expandedPip_updateExpansionState(
@@ -167,8 +167,9 @@ public class TvPipActionProviderTest extends ShellTestCase {
mActionsProvider.addListener(mMockListener);
mActionsProvider.updatePipExpansionState(endExpansion);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE),
+ getActionsTypes());
if (updateExpected) {
verify(mMockListener).onActionsChanged(0, 1, 3);
@@ -180,7 +181,6 @@ public class TvPipActionProviderTest extends ShellTestCase {
@Test
public void expandedPip_toggleExpansion_collapse() {
- assumeTelevision();
check_expandedPip_updateExpansionState(
/* startExpansion= */ true,
/* endExpansion= */ false,
@@ -189,7 +189,6 @@ public class TvPipActionProviderTest extends ShellTestCase {
@Test
public void expandedPip_toggleExpansion_expand() {
- assumeTelevision();
check_expandedPip_updateExpansionState(
/* startExpansion= */ false,
/* endExpansion= */ true,
@@ -198,7 +197,6 @@ public class TvPipActionProviderTest extends ShellTestCase {
@Test
public void expandedPiP_updateExpansionState_alreadyExpanded() {
- assumeTelevision();
check_expandedPip_updateExpansionState(
/* startExpansion= */ true,
/* endExpansion= */ true,
@@ -207,7 +205,6 @@ public class TvPipActionProviderTest extends ShellTestCase {
@Test
public void expandedPiP_updateExpansionState_alreadyCollapsed() {
- assumeTelevision();
check_expandedPip_updateExpansionState(
/* startExpansion= */ false,
/* endExpansion= */ false,
@@ -216,8 +213,6 @@ public class TvPipActionProviderTest extends ShellTestCase {
@Test
public void regularPiP_updateExpansionState_setCollapsed() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
mActionsProvider.updatePipExpansionState(/* expanded= */ false);
mActionsProvider.addListener(mMockListener);
@@ -229,153 +224,207 @@ public class TvPipActionProviderTest extends ShellTestCase {
@Test
public void customActions_added() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
mActionsProvider.addListener(mMockListener);
mActionsProvider.setAppActions(createRemoteActions(2), null);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
- ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_MOVE),
+ getActionsTypes());
verify(mMockListener).onActionsChanged(/* added= */ 2, /* updated= */ 0, /* index= */ 2);
}
@Test
public void customActions_replacedMore() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
mActionsProvider.setAppActions(createRemoteActions(2), null);
mActionsProvider.addListener(mMockListener);
mActionsProvider.setAppActions(createRemoteActions(3), null);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
- ACTION_CUSTOM, ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_CUSTOM, ACTION_MOVE),
+ getActionsTypes());
verify(mMockListener).onActionsChanged(/* added= */ 1, /* updated= */ 2, /* index= */ 2);
}
@Test
public void customActions_replacedLess() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
mActionsProvider.setAppActions(createRemoteActions(2), null);
mActionsProvider.addListener(mMockListener);
- mActionsProvider.setAppActions(createRemoteActions(0), null);
+ mActionsProvider.setAppActions(EMPTY_LIST, null);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE),
+ getActionsTypes());
verify(mMockListener).onActionsChanged(/* added= */ -2, /* updated= */ 0, /* index= */ 2);
}
@Test
public void customCloseAdded() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
-
List<RemoteAction> customActions = new ArrayList<>();
mActionsProvider.setAppActions(customActions, null);
mActionsProvider.addListener(mMockListener);
- mActionsProvider.setAppActions(customActions, createRemoteAction(0));
+ mActionsProvider.setAppActions(customActions, createRemoteAction());
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CUSTOM_CLOSE, ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CUSTOM_CLOSE, ACTION_MOVE),
+ getActionsTypes());
verify(mMockListener).onActionsChanged(/* added= */ 0, /* updated= */ 1, /* index= */ 1);
}
@Test
public void customClose_matchesOtherCustomAction() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
-
List<RemoteAction> customActions = createRemoteActions(2);
- RemoteAction customClose = createRemoteAction(/* id= */ 10);
+ RemoteAction customClose = createRemoteAction();
customActions.add(customClose);
mActionsProvider.addListener(mMockListener);
mActionsProvider.setAppActions(customActions, customClose);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CUSTOM_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
- ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CUSTOM_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_MOVE),
+ getActionsTypes());
verify(mMockListener).onActionsChanged(/* added= */ 0, /* updated= */ 1, /* index= */ 1);
verify(mMockListener).onActionsChanged(/* added= */ 2, /* updated= */ 0, /* index= */ 2);
}
@Test
public void mediaActions_added_whileCustomActionsExist() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
mActionsProvider.setAppActions(createRemoteActions(2), null);
mActionsProvider.addListener(mMockListener);
mActionsProvider.onMediaActionsChanged(createRemoteActions(3));
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
- ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_MOVE),
+ getActionsTypes());
verify(mMockListener, times(0)).onActionsChanged(anyInt(), anyInt(), anyInt());
}
@Test
public void customActions_removed_whileMediaActionsExist() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
mActionsProvider.onMediaActionsChanged(createRemoteActions(2));
mActionsProvider.setAppActions(createRemoteActions(3), null);
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_CUSTOM, ACTION_MOVE),
+ getActionsTypes());
+
mActionsProvider.addListener(mMockListener);
- mActionsProvider.setAppActions(createRemoteActions(0), null);
+ mActionsProvider.setAppActions(EMPTY_LIST, null);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
- ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_MOVE),
+ getActionsTypes());
verify(mMockListener).onActionsChanged(/* added= */ -1, /* updated= */ 2, /* index= */ 2);
}
@Test
public void customCloseOnly_mediaActionsShowing() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
mActionsProvider.onMediaActionsChanged(createRemoteActions(2));
mActionsProvider.addListener(mMockListener);
- mActionsProvider.setAppActions(createRemoteActions(0), createRemoteAction(5));
+ mActionsProvider.setAppActions(EMPTY_LIST, createRemoteAction());
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CUSTOM_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
- ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CUSTOM_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_MOVE),
+ getActionsTypes());
verify(mMockListener).onActionsChanged(/* added= */ 0, /* updated= */ 1, /* index= */ 1);
}
@Test
public void customActions_showDisabledActions() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
-
List<RemoteAction> customActions = createRemoteActions(2);
customActions.get(0).setEnabled(false);
mActionsProvider.setAppActions(customActions, null);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
- ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_MOVE),
+ getActionsTypes());
}
@Test
public void mediaActions_hideDisabledActions() {
- assumeTelevision();
- mActionsProvider.updateExpansionEnabled(false);
+ List<RemoteAction> customActions = createRemoteActions(2);
+ customActions.get(0).setEnabled(false);
+ mActionsProvider.onMediaActionsChanged(customActions);
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_MOVE),
+ getActionsTypes());
+ }
+
+ @Test
+ public void reset_mediaActions() {
List<RemoteAction> customActions = createRemoteActions(2);
customActions.get(0).setEnabled(false);
mActionsProvider.onMediaActionsChanged(customActions);
- assertTrue(checkActionsMatch(mActionsProvider.getActionsList(),
- new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_MOVE}));
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_MOVE),
+ getActionsTypes());
+
+ mActionsProvider.reset();
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE),
+ getActionsTypes());
+ }
+
+ @Test
+ public void reset_customActions() {
+ List<RemoteAction> customActions = createRemoteActions(2);
+ customActions.get(0).setEnabled(false);
+ mActionsProvider.setAppActions(customActions, null);
+
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_MOVE),
+ getActionsTypes());
+
+ mActionsProvider.reset();
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE),
+ getActionsTypes());
+ }
+
+ @Test
+ public void reset_customClose() {
+ mActionsProvider.setAppActions(EMPTY_LIST, createRemoteAction());
+
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CUSTOM_CLOSE, ACTION_MOVE),
+ getActionsTypes());
+
+ mActionsProvider.reset();
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE),
+ getActionsTypes());
+ }
+
+ @Test
+ public void reset_All() {
+ mActionsProvider.setAppActions(createRemoteActions(2), createRemoteAction());
+ mActionsProvider.onMediaActionsChanged(createRemoteActions(3));
+
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CUSTOM_CLOSE, ACTION_CUSTOM, ACTION_CUSTOM,
+ ACTION_MOVE),
+ getActionsTypes());
+
+ mActionsProvider.reset();
+ assertActionTypes(
+ Arrays.asList(ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE),
+ getActionsTypes());
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java
index f9b772345b14..91ff3cbf3a63 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java
@@ -52,9 +52,8 @@ public class TvPipGravityTest extends ShellTestCase {
@Before
public void setUp() {
- if (!isTelevision()) {
- return;
- }
+ assumeTelevision();
+
MockitoAnnotations.initMocks(this);
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
@@ -100,20 +99,22 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void regularPip_defaultGravity() {
- assumeTelevision();
checkGravity(mTvPipBoundsState.getDefaultGravity(), Gravity.RIGHT | Gravity.BOTTOM);
}
@Test
+ public void regularPip_defaultTvPipGravity() {
+ checkGravity(mTvPipBoundsState.getTvPipGravity(), Gravity.RIGHT | Gravity.BOTTOM);
+ }
+
+ @Test
public void regularPip_defaultGravity_RTL() {
- assumeTelevision();
setRTL(true);
checkGravity(mTvPipBoundsState.getDefaultGravity(), Gravity.LEFT | Gravity.BOTTOM);
}
@Test
public void updateGravity_expand_vertical() {
- assumeTelevision();
// Vertical expanded PiP.
mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true);
@@ -129,7 +130,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void updateGravity_expand_horizontal() {
- assumeTelevision();
// Horizontal expanded PiP.
mTvPipBoundsState.setDesiredTvExpandedAspectRatio(HORIZONTAL_EXPANDED_ASPECT_RATIO, true);
@@ -145,7 +145,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void updateGravity_collapse() {
- assumeTelevision();
// Vertical expansion
mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true);
assertGravityAfterCollapse(Gravity.CENTER_VERTICAL | Gravity.RIGHT,
@@ -163,7 +162,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void updateGravity_collapse_RTL() {
- assumeTelevision();
setRTL(true);
// Horizontal expansion
@@ -176,7 +174,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void updateGravity_expand_collapse() {
- assumeTelevision();
// Vertical expanded PiP.
mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true);
@@ -196,7 +193,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void updateGravity_expand_move_collapse() {
- assumeTelevision();
// Vertical expanded PiP.
mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true);
expandMoveCollapseCheck(Gravity.TOP | Gravity.RIGHT, KEYCODE_DPAD_LEFT,
@@ -229,7 +225,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void updateGravity_move_regular_valid() {
- assumeTelevision();
mTvPipBoundsState.setTvPipGravity(Gravity.BOTTOM | Gravity.RIGHT);
// clockwise
moveAndCheckGravity(KEYCODE_DPAD_LEFT, Gravity.BOTTOM | Gravity.LEFT, true);
@@ -245,7 +240,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void updateGravity_move_expanded_valid() {
- assumeTelevision();
mTvPipBoundsState.setTvPipExpanded(true);
// Vertical expanded PiP.
@@ -263,7 +257,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void updateGravity_move_regular_invalid() {
- assumeTelevision();
int gravity = Gravity.BOTTOM | Gravity.RIGHT;
mTvPipBoundsState.setTvPipGravity(gravity);
moveAndCheckGravity(KEYCODE_DPAD_DOWN, gravity, false);
@@ -287,7 +280,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void updateGravity_move_expanded_invalid() {
- assumeTelevision();
mTvPipBoundsState.setTvPipExpanded(true);
// Vertical expanded PiP.
@@ -317,7 +309,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void previousCollapsedGravity_defaultValue() {
- assumeTelevision();
assertEquals(mTvPipBoundsState.getTvPipPreviousCollapsedGravity(),
mTvPipBoundsState.getDefaultGravity());
setRTL(true);
@@ -327,7 +318,6 @@ public class TvPipGravityTest extends ShellTestCase {
@Test
public void previousCollapsedGravity_changes_on_RTL() {
- assumeTelevision();
mTvPipBoundsState.setTvPipPreviousCollapsedGravity(Gravity.TOP | Gravity.LEFT);
setRTL(true);
assertEquals(mTvPipBoundsState.getTvPipPreviousCollapsedGravity(),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
index 68cb57c14d8c..b1befc46f383 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
@@ -41,6 +41,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
/** Tests for {@link MainStage} */
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -61,7 +63,7 @@ public class MainStageTests extends ShellTestCase {
MockitoAnnotations.initMocks(this);
mRootTaskInfo = new TestRunningTaskInfoBuilder().build();
mMainStage = new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks,
- mSyncQueue, mSurfaceSession, mIconProvider);
+ mSyncQueue, mSurfaceSession, mIconProvider, Optional.empty());
mMainStage.onTaskAppeared(mRootTaskInfo, mRootLeash);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
index 3b42a48b5a40..549bd3fcabfb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
@@ -46,6 +46,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import java.util.Optional;
+
/** Tests for {@link SideStage} */
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -66,7 +68,7 @@ public class SideStageTests extends ShellTestCase {
MockitoAnnotations.initMocks(this);
mRootTask = new TestRunningTaskInfoBuilder().build();
mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks,
- mSyncQueue, mSurfaceSession, mIconProvider);
+ mSyncQueue, mSurfaceSession, mIconProvider, Optional.empty());
mSideStage.onTaskAppeared(mRootTask, mRootLeash);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index fb17d8799bda..e8a1e91acd4d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -61,6 +61,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
@@ -71,6 +72,7 @@ import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.sysui.ShellSharedConstants;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import org.junit.Before;
import org.junit.Test;
@@ -102,6 +104,8 @@ public class SplitScreenControllerTests extends ShellTestCase {
@Mock IconProvider mIconProvider;
@Mock StageCoordinator mStageCoordinator;
@Mock RecentTasksController mRecentTasks;
+ @Mock LaunchAdjacentController mLaunchAdjacentController;
+ @Mock WindowDecorViewModel mWindowDecorViewModel;
@Captor ArgumentCaptor<Intent> mIntentCaptor;
private ShellController mShellController;
@@ -117,7 +121,8 @@ public class SplitScreenControllerTests extends ShellTestCase {
mShellCommandHandler, mShellController, mTaskOrganizer, mSyncQueue,
mRootTDAOrganizer, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mDragAndDropController, mTransitions, mTransactionPool,
- mIconProvider, mRecentTasks, mMainExecutor, mStageCoordinator));
+ mIconProvider, mRecentTasks, mLaunchAdjacentController, mWindowDecorViewModel,
+ mMainExecutor, mStageCoordinator));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index 4e446c684d86..a3009a55198f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -31,12 +31,14 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.util.Optional;
@@ -76,10 +78,13 @@ public class SplitTestUtils {
DisplayInsetsController insetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
ShellExecutor mainExecutor,
- Optional<RecentTasksController> recentTasks) {
+ Optional<RecentTasksController> recentTasks,
+ LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
super(context, displayId, syncQueue, taskOrganizer, mainStage,
sideStage, displayController, imeController, insetsController, splitLayout,
- transitions, transactionPool, mainExecutor, recentTasks);
+ transitions, transactionPool, mainExecutor, recentTasks,
+ launchAdjacentController, windowDecorViewModel);
// Prepare root task for testing.
mRootTask = new TestRunningTaskInfoBuilder().build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 44c76de945b0..5efd9ad97a3e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -70,6 +70,7 @@ import com.android.wm.shell.TransitionInfoBuilder;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
@@ -77,6 +78,7 @@ import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.transition.DefaultMixedHandler;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import org.junit.Before;
import org.junit.Test;
@@ -101,7 +103,9 @@ public class SplitTransitionTests extends ShellTestCase {
@Mock private Transitions mTransitions;
@Mock private SurfaceSession mSurfaceSession;
@Mock private IconProvider mIconProvider;
+ @Mock private WindowDecorViewModel mWindowDecorViewModel;
@Mock private ShellExecutor mMainExecutor;
+ @Mock private LaunchAdjacentController mLaunchAdjacentController;
@Mock private DefaultMixedHandler mMixedHandler;
private SplitLayout mSplitLayout;
private MainStage mMainStage;
@@ -123,16 +127,17 @@ public class SplitTransitionTests extends ShellTestCase {
mSplitLayout = SplitTestUtils.createMockSplitLayout();
mMainStage = spy(new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
- mIconProvider));
+ mIconProvider, Optional.of(mWindowDecorViewModel)));
mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mSideStage = spy(new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
- mIconProvider));
+ mIconProvider, Optional.of(mWindowDecorViewModel)));
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
- mTransactionPool, mMainExecutor, Optional.empty());
+ mTransactionPool, mMainExecutor, Optional.empty(),
+ mLaunchAdjacentController, Optional.empty());
mStageCoordinator.setMixedHandler(mMixedHandler);
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 2dcdc74e8ae7..cc4db22e772c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -65,6 +65,7 @@ import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
@@ -107,6 +108,8 @@ public class StageCoordinatorTests extends ShellTestCase {
private DisplayInsetsController mDisplayInsetsController;
@Mock
private TransactionPool mTransactionPool;
+ @Mock
+ private LaunchAdjacentController mLaunchAdjacentController;
private final Rect mBounds1 = new Rect(10, 20, 30, 40);
private final Rect mBounds2 = new Rect(5, 10, 15, 20);
@@ -130,7 +133,7 @@ public class StageCoordinatorTests extends ShellTestCase {
mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool,
- mMainExecutor, Optional.empty()));
+ mMainExecutor, Optional.empty(), mLaunchAdjacentController, Optional.empty()));
mDividerLeash = new SurfaceControl.Builder(mSurfaceSession).setName("fakeDivider").build();
when(mSplitLayout.getBounds1()).thenReturn(mBounds1);
@@ -344,13 +347,20 @@ public class StageCoordinatorTests extends ShellTestCase {
}
@Test
- public void testExitSplitScreenAfterFolded() {
- when(mMainStage.isActive()).thenReturn(true);
+ public void testExitSplitScreenAfterFoldedAndWakeUp() {
when(mMainStage.isFocused()).thenReturn(true);
when(mMainStage.getTopVisibleChildTaskId()).thenReturn(INVALID_TASK_ID);
+ mSideStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().setVisible(true).build();
+ mMainStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().setVisible(true).build();
+ when(mStageCoordinator.isSplitActive()).thenReturn(true);
+ when(mStageCoordinator.isSplitScreenVisible()).thenReturn(true);
mStageCoordinator.onFoldedStateChanged(true);
+ assertEquals(mStageCoordinator.mTopStageAfterFoldDismiss, STAGE_TYPE_MAIN);
+
+ mStageCoordinator.onFinishedWakingUp();
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
verify(mTaskOrganizer).startNewTransition(eq(TRANSIT_SPLIT_DISMISS), notNull());
} else {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 1a1bebd28aef..946a7ef7d8c3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -43,6 +43,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import org.junit.Before;
import org.junit.Test;
@@ -52,6 +53,8 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
/**
* Tests for {@link StageTaskListener}
* Build/Install/Run:
@@ -71,6 +74,8 @@ public final class StageTaskListenerTests extends ShellTestCase {
private SyncTransactionQueue mSyncQueue;
@Mock
private IconProvider mIconProvider;
+ @Mock
+ private WindowDecorViewModel mWindowDecorViewModel;
@Captor
private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor;
private SurfaceSession mSurfaceSession = new SurfaceSession();
@@ -89,7 +94,8 @@ public final class StageTaskListenerTests extends ShellTestCase {
mCallbacks,
mSyncQueue,
mSurfaceSession,
- mIconProvider);
+ mIconProvider,
+ Optional.of(mWindowDecorViewModel));
mRootTask = new TestRunningTaskInfoBuilder().build();
mRootTask.parentTaskId = INVALID_TASK_ID;
mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession).setName("test").build();
@@ -155,7 +161,7 @@ public final class StageTaskListenerTests extends ShellTestCase {
childTask.supportsMultiWindow = false;
mStageTaskListener.onTaskInfoChanged(childTask);
- verify(mCallbacks).onNoLongerSupportMultiWindow();
+ verify(mCallbacks).onNoLongerSupportMultiWindow(childTask);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
index 1b389565c066..d098d332a376 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
@@ -40,6 +40,7 @@ import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.Context;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.testing.AndroidTestingRunner;
@@ -563,4 +564,72 @@ public class TaskViewTest extends ShellTestCase {
mTaskViewTaskController.onTaskAppeared(mTaskInfo, mLeash);
verify(mTaskViewTaskController, never()).cleanUpPendingTask();
}
+
+ @Test
+ public void testSetCaptionInsets_noTaskInitially() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ Rect insets = new Rect(0, 400, 0, 0);
+ mTaskView.setCaptionInsets(Insets.of(insets));
+ mTaskView.onComputeInternalInsets(new ViewTreeObserver.InternalInsetsInfo());
+
+ verify(mTaskViewTaskController).applyCaptionInsetsIfNeeded();
+ verify(mOrganizer, never()).applyTransaction(any());
+
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ reset(mOrganizer);
+ reset(mTaskViewTaskController);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskViewTaskController.prepareOpenAnimation(true /* newTask */,
+ new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo,
+ mLeash, wct);
+ mTaskView.onComputeInternalInsets(new ViewTreeObserver.InternalInsetsInfo());
+
+ verify(mTaskViewTaskController).applyCaptionInsetsIfNeeded();
+ verify(mOrganizer).applyTransaction(any());
+ }
+
+ @Test
+ public void testSetCaptionInsets_withTask() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskViewTaskController.prepareOpenAnimation(true /* newTask */,
+ new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo,
+ mLeash, wct);
+ reset(mTaskViewTaskController);
+ reset(mOrganizer);
+
+ Rect insets = new Rect(0, 400, 0, 0);
+ mTaskView.setCaptionInsets(Insets.of(insets));
+ mTaskView.onComputeInternalInsets(new ViewTreeObserver.InternalInsetsInfo());
+ verify(mTaskViewTaskController).applyCaptionInsetsIfNeeded();
+ verify(mOrganizer).applyTransaction(any());
+ }
+
+ @Test
+ public void testReleaseInOnTaskRemoval_noNPE() {
+ mTaskViewTaskController = spy(new TaskViewTaskController(mContext, mOrganizer,
+ mTaskViewTransitions, mSyncQueue));
+ mTaskView = new TaskView(mContext, mTaskViewTaskController);
+ mTaskView.setListener(mExecutor, new TaskView.Listener() {
+ @Override
+ public void onTaskRemovalStarted(int taskId) {
+ mTaskView.release();
+ }
+ });
+
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskViewTaskController.prepareOpenAnimation(true /* newTask */,
+ new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo,
+ mLeash, wct);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+
+ assertThat(mTaskViewTaskController.getTaskInfo()).isEqualTo(mTaskInfo);
+
+ mTaskViewTaskController.prepareCloseAnimation();
+
+ assertThat(mTaskViewTaskController.getTaskInfo()).isNull();
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
index 03ed18c86608..050443914355 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
@@ -65,12 +65,6 @@ public class TaskViewTransitionsTest extends ShellTestCase {
ActivityManager.RunningTaskInfo mTaskInfo;
@Mock
WindowContainerToken mToken;
- @Mock
- TaskViewTaskController mTaskViewTaskController2;
- @Mock
- ActivityManager.RunningTaskInfo mTaskInfo2;
- @Mock
- WindowContainerToken mToken2;
TaskViewTransitions mTaskViewTransitions;
@@ -86,16 +80,10 @@ public class TaskViewTransitionsTest extends ShellTestCase {
mTaskInfo.token = mToken;
mTaskInfo.taskId = 314;
mTaskInfo.taskDescription = mock(ActivityManager.TaskDescription.class);
- when(mTaskViewTaskController.getTaskInfo()).thenReturn(mTaskInfo);
-
- mTaskInfo2 = new ActivityManager.RunningTaskInfo();
- mTaskInfo2.token = mToken2;
- mTaskInfo2.taskId = 315;
- mTaskInfo2.taskDescription = mock(ActivityManager.TaskDescription.class);
- when(mTaskViewTaskController2.getTaskInfo()).thenReturn(mTaskInfo2);
mTaskViewTransitions = spy(new TaskViewTransitions(mTransitions));
mTaskViewTransitions.addTaskView(mTaskViewTaskController);
+ when(mTaskViewTaskController.getTaskInfo()).thenReturn(mTaskInfo);
}
@Test
@@ -138,7 +126,7 @@ public class TaskViewTransitionsTest extends ShellTestCase {
}
@Test
- public void testSetTaskBounds_taskVisibleWithPendingOpen_noTransaction() {
+ public void testSetTaskBounds_taskVisibleWithPending_noTransaction() {
assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, true);
@@ -154,43 +142,6 @@ public class TaskViewTransitionsTest extends ShellTestCase {
}
@Test
- public void testSetTaskBounds_taskVisibleWithPendingChange_transition() {
- assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
-
- mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, true);
-
- // Consume the pending transition from visibility change
- TaskViewTransitions.PendingTransition pending =
- mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
- assertThat(pending).isNotNull();
- mTaskViewTransitions.startAnimation(pending.mClaimed,
- mock(TransitionInfo.class),
- new SurfaceControl.Transaction(),
- new SurfaceControl.Transaction(),
- mock(Transitions.TransitionFinishCallback.class));
- // Verify it was consumed
- TaskViewTransitions.PendingTransition checkPending =
- mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
- assertThat(checkPending).isNull();
-
- // Test that set bounds creates a new transition
- mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
- new Rect(0, 0, 100, 100));
- assertThat(mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE))
- .isNotNull();
-
- // Test that set bounds again (with different bounds) creates another transition
- mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
- new Rect(0, 0, 300, 200));
- List<TaskViewTransitions.PendingTransition> pendingList =
- mTaskViewTransitions.findAllPending(mTaskViewTaskController)
- .stream()
- .filter(pendingTransition -> pendingTransition.mType == TRANSIT_CHANGE)
- .toList();
- assertThat(pendingList.size()).isEqualTo(2);
- }
-
- @Test
public void testSetTaskBounds_sameBounds_noTransaction() {
assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
@@ -217,16 +168,6 @@ public class TaskViewTransitionsTest extends ShellTestCase {
mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE);
assertThat(pendingBounds).isNotNull();
- // Test that setting same bounds with in-flight transition doesn't cause another one
- mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
- new Rect(0, 0, 100, 100));
- List<TaskViewTransitions.PendingTransition> pendingList =
- mTaskViewTransitions.findAllPending(mTaskViewTaskController)
- .stream()
- .filter(pendingTransition -> pendingTransition.mType == TRANSIT_CHANGE)
- .toList();
- assertThat(pendingList.size()).isEqualTo(1);
-
// Consume the pending bounds transaction
mTaskViewTransitions.startAnimation(pendingBounds.mClaimed,
mock(TransitionInfo.class),
@@ -246,42 +187,6 @@ public class TaskViewTransitionsTest extends ShellTestCase {
assertThat(pendingBounds2).isNull();
}
-
- @Test
- public void testSetTaskBounds_taskVisibleWithDifferentTaskViewPendingChange_transition() {
- assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
-
- mTaskViewTransitions.addTaskView(mTaskViewTaskController2);
-
- mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, true);
-
- // Consume the pending transition from visibility change
- TaskViewTransitions.PendingTransition pending =
- mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
- assertThat(pending).isNotNull();
- mTaskViewTransitions.startAnimation(pending.mClaimed,
- mock(TransitionInfo.class),
- new SurfaceControl.Transaction(),
- new SurfaceControl.Transaction(),
- mock(Transitions.TransitionFinishCallback.class));
- // Verify it was consumed
- TaskViewTransitions.PendingTransition checkPending =
- mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
- assertThat(checkPending).isNull();
-
- // Set the second taskview as visible & check that it has a pending transition
- mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController2, true);
- TaskViewTransitions.PendingTransition pending2 =
- mTaskViewTransitions.findPending(mTaskViewTaskController2, TRANSIT_TO_FRONT);
- assertThat(pending2).isNotNull();
-
- // Test that set bounds on the first taskview will create a new transition
- mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
- new Rect(0, 0, 100, 100));
- assertThat(mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE))
- .isNotNull();
- }
-
@Test
public void testSetTaskVisibility_taskRemoved_noNPE() {
mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index ff380e92322d..99a1ac663286 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -176,7 +176,7 @@ public class ShellTransitionTests extends ShellTestCase {
assertEquals(1, mDefaultHandler.activeCount());
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any());
}
@Test
@@ -299,7 +299,7 @@ public class ShellTransitionTests extends ShellTestCase {
assertTrue(remoteCalled[0]);
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken), eq(remoteFinishWCT), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken), eq(remoteFinishWCT));
}
@Test
@@ -449,7 +449,7 @@ public class ShellTransitionTests extends ShellTestCase {
assertTrue(remoteCalled[0]);
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any());
}
@Test
@@ -524,20 +524,20 @@ public class ShellTransitionTests extends ShellTestCase {
// default handler doesn't merge by default, so it shouldn't increment active count.
assertEquals(1, mDefaultHandler.activeCount());
assertEquals(0, mDefaultHandler.mergeCount());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken1), any(), any());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken1), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any());
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
// first transition finished
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any());
// But now the "queued" transition is running
assertEquals(1, mDefaultHandler.activeCount());
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any());
}
@Test
@@ -565,15 +565,15 @@ public class ShellTransitionTests extends ShellTestCase {
// it should still only have 1 active, but then show 1 merged
assertEquals(1, mDefaultHandler.activeCount());
assertEquals(1, mDefaultHandler.mergeCount());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken1), any(), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken1), any());
// We don't tell organizer it is finished yet (since we still want to maintain ordering)
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any());
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
// transition + merged all finished.
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any());
// Make sure nothing was queued
assertEquals(0, mDefaultHandler.activeCount());
}
@@ -599,8 +599,7 @@ public class ShellTransitionTests extends ShellTestCase {
requestStartTransition(transitions, transitTokenNotReady);
mDefaultHandler.setSimulateMerge(true);
- mDefaultHandler.mFinishes.get(0).second.onTransitionFinished(
- null /* wct */, null /* wctCB */);
+ mDefaultHandler.mFinishes.get(0).second.onTransitionFinished(null /* wct */);
// Make sure that the non-ready transition is not merged.
assertEquals(0, mDefaultHandler.mergeCount());
@@ -823,8 +822,8 @@ public class ShellTransitionTests extends ShellTestCase {
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
// first transition finished
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any());
// But now the "queued" transition is running
assertEquals(1, mDefaultHandler.activeCount());
@@ -835,7 +834,7 @@ public class ShellTransitionTests extends ShellTestCase {
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any());
// runnable2 and runnable3 are executed after the second transition finishes because there
// are no other active transitions, runnable1 isn't executed again.
@@ -1449,13 +1448,13 @@ public class ShellTransitionTests extends ShellTestCase {
if (mFinishOnSync && info.getType() == TRANSIT_SLEEP) {
for (int i = 0; i < mFinishes.size(); ++i) {
if (mFinishes.get(i).first != mergeTarget) continue;
- mFinishes.remove(i).second.onTransitionFinished(null, null);
+ mFinishes.remove(i).second.onTransitionFinished(null);
return;
}
}
if (!(mSimulateMerge || mShouldMerge.contains(transition))) return;
mMerged.add(transition);
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
}
@Nullable
@@ -1478,7 +1477,7 @@ public class ShellTransitionTests extends ShellTestCase {
mFinishes;
mFinishes = new ArrayList<>();
for (int i = finishes.size() - 1; i >= 0; --i) {
- finishes.get(i).second.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishes.get(i).second.onTransitionFinished(null /* wct */);
}
mShouldMerge.clear();
}
@@ -1486,7 +1485,7 @@ public class ShellTransitionTests extends ShellTestCase {
void finishOne() {
Pair<IBinder, Transitions.TransitionFinishCallback> fin = mFinishes.remove(0);
mMerged.clear();
- fin.second.onTransitionFinished(null /* wct */, null /* wctCB */);
+ fin.second.onTransitionFinished(null /* wct */);
}
int activeCount() {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
index 41bab95b7dd4..596d6dd3a3d2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
@@ -18,12 +18,15 @@ package com.android.wm.shell.windowdecor;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -53,7 +56,8 @@ import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopTasksController;
-import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -82,7 +86,6 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private DisplayController mDisplayController;
@Mock private DisplayLayout mDisplayLayout;
- @Mock private SplitScreenController mSplitScreenController;
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private DesktopModeController mDesktopModeController;
@Mock private DesktopTasksController mDesktopTasksController;
@@ -92,6 +95,11 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
@Mock private DesktopModeWindowDecorViewModel.InputMonitorFactory mMockInputMonitorFactory;
@Mock private Supplier<SurfaceControl.Transaction> mTransactionFactory;
@Mock private SurfaceControl.Transaction mTransaction;
+ @Mock private Display mDisplay;
+ @Mock private ShellController mShellController;
+ @Mock private ShellInit mShellInit;
+ @Mock private DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
+ mDesktopModeKeyguardChangeListener;
private final List<InputManager> mMockInputManagers = new ArrayList<>();
private DesktopModeWindowDecorViewModel mDesktopModeWindowDecorViewModel;
@@ -105,16 +113,18 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
mContext,
mMainHandler,
mMainChoreographer,
+ mShellInit,
mTaskOrganizer,
mDisplayController,
+ mShellController,
mSyncQueue,
mTransitions,
Optional.of(mDesktopModeController),
Optional.of(mDesktopTasksController),
- Optional.of(mSplitScreenController),
mDesktopModeWindowDecorFactory,
mMockInputMonitorFactory,
- mTransactionFactory
+ mTransactionFactory,
+ mDesktopModeKeyguardChangeListener
);
doReturn(mDesktopModeWindowDecoration)
@@ -123,12 +133,16 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
doReturn(mTransaction).when(mTransactionFactory).get();
doReturn(mDisplayLayout).when(mDisplayController).getDisplayLayout(anyInt());
doReturn(STABLE_INSETS).when(mDisplayLayout).stableInsets();
+ doNothing().when(mShellController).addKeyguardChangeListener(any());
when(mMockInputMonitorFactory.create(any(), any())).thenReturn(mInputMonitor);
// InputChannel cannot be mocked because it passes to InputEventReceiver.
final InputChannel[] inputChannels = InputChannel.openInputChannelPair(TAG);
inputChannels[0].dispose();
when(mInputMonitor.getInputChannel()).thenReturn(inputChannels[1]);
+
+ mDesktopModeWindowDecoration.mDisplay = mDisplay;
+ doReturn(Display.DEFAULT_DISPLAY).when(mDisplay).getDisplayId();
}
@Test
@@ -254,6 +268,32 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
verify(mInputMonitor, times(1)).dispose();
}
+ @Test
+ public void testCaptionIsNotCreatedWhenKeyguardIsVisible() throws Exception {
+ doReturn(true).when(
+ mDesktopModeKeyguardChangeListener).isKeyguardVisibleAndOccluded();
+
+ final int taskId = 1;
+ final ActivityManager.RunningTaskInfo taskInfo =
+ createTaskInfo(taskId, Display.DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN);
+ taskInfo.isFocused = true;
+ SurfaceControl surfaceControl = mock(SurfaceControl.class);
+ runOnMainThread(() -> {
+ final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
+ final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
+
+ mDesktopModeWindowDecorViewModel.onTaskOpening(
+ taskInfo, surfaceControl, startT, finishT);
+
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
+ mDesktopModeWindowDecorViewModel.onTaskChanging(
+ taskInfo, surfaceControl, startT, finishT);
+ });
+ verify(mDesktopModeWindowDecorFactory, never())
+ .create(any(), any(), any(), any(), any(), any(), any(), any());
+ }
+
private void runOnMainThread(Runnable r) throws Exception {
final Handler mainHandler = new Handler(Looper.getMainLooper());
final CountDownLatch latch = new CountDownLatch(1);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
index 8f84008e8d2d..3fbab0f9e2bb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
@@ -55,7 +55,7 @@ class DragDetectorTest {
fun setUp() {
MockitoAnnotations.initMocks(this)
- `when`(eventHandler.handleMotionEvent(any())).thenReturn(true)
+ `when`(eventHandler.handleMotionEvent(any(), any())).thenReturn(true)
dragDetector = DragDetector(eventHandler)
dragDetector.setTouchSlop(SLOP)
@@ -72,13 +72,13 @@ class DragDetectorTest {
@Test
fun testNoMove_passesDownAndUp() {
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_UP)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_UP && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
@@ -86,12 +86,12 @@ class DragDetectorTest {
@Test
fun testMoveInSlop_touch_passesDownAndUp() {
- `when`(eventHandler.handleMotionEvent(argThat {
+ `when`(eventHandler.handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN
})).thenReturn(false)
assertFalse(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
@@ -99,12 +99,12 @@ class DragDetectorTest {
val newX = X + SLOP - 1
assertFalse(
dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_MOVE, newX, Y)))
- verify(eventHandler, never()).handleMotionEvent(argThat {
+ verify(eventHandler, never()).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_MOVE
})
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_UP, newX, Y)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_UP && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
@@ -112,13 +112,13 @@ class DragDetectorTest {
@Test
fun testMoveInSlop_mouse_passesDownMoveAndUp() {
- `when`(eventHandler.handleMotionEvent(argThat {
+ `when`(eventHandler.handleMotionEvent(any(), argThat {
it.action == MotionEvent.ACTION_DOWN
})).thenReturn(false)
assertFalse(dragDetector.onMotionEvent(
createMotionEvent(MotionEvent.ACTION_DOWN, isTouch = false)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_MOUSE
})
@@ -126,14 +126,14 @@ class DragDetectorTest {
val newX = X + SLOP - 1
assertTrue(dragDetector.onMotionEvent(
createMotionEvent(MotionEvent.ACTION_MOVE, newX, Y, isTouch = false)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_MOVE && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_MOUSE
})
assertTrue(dragDetector.onMotionEvent(
createMotionEvent(MotionEvent.ACTION_UP, newX, Y, isTouch = false)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_UP && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_MOUSE
})
@@ -141,25 +141,25 @@ class DragDetectorTest {
@Test
fun testMoveBeyondSlop_passesDownMoveAndUp() {
- `when`(eventHandler.handleMotionEvent(argThat {
+ `when`(eventHandler.handleMotionEvent(any(), argThat {
it.action == MotionEvent.ACTION_DOWN
})).thenReturn(false)
assertFalse(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
val newX = X + SLOP + 1
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_MOVE, newX, Y)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_MOVE && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_UP, newX, Y)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_UP && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
@@ -167,12 +167,12 @@ class DragDetectorTest {
@Test
fun testPassesHoverEnter() {
- `when`(eventHandler.handleMotionEvent(argThat {
+ `when`(eventHandler.handleMotionEvent(any(), argThat {
it.action == MotionEvent.ACTION_HOVER_ENTER
})).thenReturn(false)
assertFalse(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_HOVER_ENTER)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_HOVER_ENTER && it.x == X && it.y == Y
})
}
@@ -180,7 +180,7 @@ class DragDetectorTest {
@Test
fun testPassesHoverMove() {
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_HOVER_MOVE)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_HOVER_MOVE && it.x == X && it.y == Y
})
}
@@ -188,7 +188,7 @@ class DragDetectorTest {
@Test
fun testPassesHoverExit() {
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_HOVER_EXIT)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_HOVER_EXIT && it.x == X && it.y == Y
})
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 69604ddf0af1..6f0599aa8243 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -22,6 +22,7 @@ import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFI
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
@@ -71,16 +72,6 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
- taskPositioner =
- FluidResizeTaskPositioner(
- mockShellTaskOrganizer,
- mockWindowDecoration,
- mockDisplayController,
- DISALLOWED_AREA_FOR_END_BOUNDS,
- mockDragStartListener,
- mockTransactionFactory
- )
-
whenever(taskToken.asBinder()).thenReturn(taskBinder)
whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
@@ -101,6 +92,15 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
}
mockWindowDecoration.mDisplay = mockDisplay
whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+
+ taskPositioner = FluidResizeTaskPositioner(
+ mockShellTaskOrganizer,
+ mockWindowDecoration,
+ mockDisplayController,
+ mockDragStartListener,
+ mockTransactionFactory,
+ DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT
+ )
}
@Test
@@ -544,7 +544,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
)
val newX = STARTING_BOUNDS.right.toFloat() + 5
- val newY = STARTING_BOUNDS.top.toFloat() + 5
+ val newY = DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT.toFloat() - 1
taskPositioner.onDragPositioningMove(
newX,
newY
@@ -614,6 +614,38 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
})
}
+ @Test
+ fun testDragResize_drag_taskPositionedInStableBounds() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ val newX = STARTING_BOUNDS.left.toFloat()
+ val newY = STABLE_BOUNDS.top.toFloat() - 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+ verify(mockTransaction).setPosition(any(), eq(newX), eq(newY))
+
+ taskPositioner.onDragPositioningEnd(
+ newX,
+ newY
+ )
+ // Verify task's top bound is set to stable bounds top since dragged outside stable bounds
+ // but not in disallowed end bounds area.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
+ change.configuration.windowConfiguration.bounds.top ==
+ STABLE_BOUNDS.top
+ }
+ })
+ }
+
companion object {
private const val TASK_ID = 5
private const val MIN_WIDTH = 10
@@ -622,10 +654,11 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
private const val DEFAULT_MIN = 40
private const val DISPLAY_ID = 1
private const val NAVBAR_HEIGHT = 50
+ private const val CAPTION_HEIGHT = 50
+ private const val DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT = 10
private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
- private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val STARTING_BOUNDS = Rect(100, 100, 200, 200)
private val STABLE_INSETS = Rect(0, 50, 0, 0)
- private val DISALLOWED_AREA_FOR_END_BOUNDS = Rect(0, 0, 300, 300)
private val DISALLOWED_RESIZE_AREA = Rect(
DISPLAY_BOUNDS.left,
DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
@@ -633,7 +666,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
DISPLAY_BOUNDS.bottom)
private val STABLE_BOUNDS = Rect(
DISPLAY_BOUNDS.left,
- DISPLAY_BOUNDS.top,
+ DISPLAY_BOUNDS.top + CAPTION_HEIGHT,
DISPLAY_BOUNDS.right,
DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 4147dd8e6152..3465ddd9d101 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -89,17 +89,6 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
- taskPositioner =
- VeiledResizeTaskPositioner(
- mockShellTaskOrganizer,
- mockDesktopWindowDecoration,
- mockDisplayController,
- DISALLOWED_AREA_FOR_END_BOUNDS,
- mockDragStartListener,
- mockTransactionFactory,
- mockTransitions
- )
-
whenever(taskToken.asBinder()).thenReturn(taskBinder)
whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
@@ -119,6 +108,17 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
}
mockDesktopWindowDecoration.mDisplay = mockDisplay
whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+
+ taskPositioner =
+ VeiledResizeTaskPositioner(
+ mockShellTaskOrganizer,
+ mockDesktopWindowDecoration,
+ mockDisplayController,
+ mockDragStartListener,
+ mockTransactionFactory,
+ mockTransitions,
+ DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT
+ )
}
@Test
@@ -269,7 +269,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
)
val newX = STARTING_BOUNDS.left.toFloat() + 5
- val newY = STARTING_BOUNDS.top.toFloat() + 5
+ val newY = DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT.toFloat() - 1
taskPositioner.onDragPositioningMove(
newX,
newY
@@ -334,6 +334,38 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
})
}
+ @Test
+ fun testDragResize_drag_taskPositionedInStableBounds() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ val newX = STARTING_BOUNDS.left.toFloat()
+ val newY = STABLE_BOUNDS.top.toFloat() - 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+ verify(mockTransaction).setPosition(any(), eq(newX), eq(newY))
+
+ taskPositioner.onDragPositioningEnd(
+ newX,
+ newY
+ )
+ // Verify task's top bound is set to stable bounds top since dragged outside stable bounds
+ // but not in disallowed end bounds area.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
+ change.configuration.windowConfiguration.bounds.top ==
+ STABLE_BOUNDS.top
+ }
+ })
+ }
+
companion object {
private const val TASK_ID = 5
private const val MIN_WIDTH = 10
@@ -342,12 +374,13 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
private const val DEFAULT_MIN = 40
private const val DISPLAY_ID = 1
private const val NAVBAR_HEIGHT = 50
+ private const val CAPTION_HEIGHT = 50
+ private const val DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT = 10
private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
- private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
- private val DISALLOWED_AREA_FOR_END_BOUNDS = Rect(0, 0, 50, 50)
+ private val STARTING_BOUNDS = Rect(100, 100, 200, 200)
private val STABLE_BOUNDS = Rect(
DISPLAY_BOUNDS.left,
- DISPLAY_BOUNDS.top,
+ DISPLAY_BOUNDS.top + CAPTION_HEIGHT,
DISPLAY_BOUNDS.right,
DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 5a2326b9c393..7fc1c99bb44e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -57,7 +57,6 @@ import android.window.SurfaceSyncGroup;
import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
@@ -316,7 +315,8 @@ public class WindowDecorationTests extends ShellTestCase {
releaseOrder.verify(t).remove(captionContainerSurface);
releaseOrder.verify(t).remove(decorContainerSurface);
releaseOrder.verify(t).apply();
- verify(mMockWindowContainerTransaction)
+ // Expect to remove two insets sources, the caption insets and the mandatory gesture insets.
+ verify(mMockWindowContainerTransaction, Mockito.times(2))
.removeInsetsSource(eq(taskInfo.token), any(), anyInt(), anyInt());
}
@@ -410,15 +410,17 @@ public class WindowDecorationTests extends ShellTestCase {
verify(additionalWindowSurfaceBuilder).build();
verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 0, 0);
final int width = WindowDecoration.loadDimensionPixelSize(
- mContext.getResources(), mCaptionMenuWidthId);
+ windowDecor.mDecorWindowContext.getResources(), mCaptionMenuWidthId);
final int height = WindowDecoration.loadDimensionPixelSize(
- mContext.getResources(), mRelayoutParams.mCaptionHeightId);
+ windowDecor.mDecorWindowContext.getResources(), mRelayoutParams.mCaptionHeightId);
verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height);
- final int shadowRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(),
+ final int shadowRadius = WindowDecoration.loadDimensionPixelSize(
+ windowDecor.mDecorWindowContext.getResources(),
mCaptionMenuShadowRadiusId);
verify(mMockSurfaceControlAddWindowT)
.setShadowRadius(additionalWindowSurface, shadowRadius);
- final int cornerRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(),
+ final int cornerRadius = WindowDecoration.loadDimensionPixelSize(
+ windowDecor.mDecorWindowContext.getResources(),
mCaptionMenuCornerRadiusId);
verify(mMockSurfaceControlAddWindowT)
.setCornerRadius(additionalWindowSurface, cornerRadius);
@@ -513,8 +515,7 @@ public class WindowDecorationTests extends ShellTestCase {
private TestWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
- return new TestWindowDecoration(InstrumentationRegistry.getInstrumentation().getContext(),
- mMockDisplayController, mMockShellTaskOrganizer,
+ return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
taskInfo, testSurface,
new MockObjectSupplier<>(mMockSurfaceControlBuilders,
() -> createMockSurfaceControlBuilder(mock(SurfaceControl.class))),
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 28bda72bccdd..fa9447afbeab 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -232,6 +232,7 @@ cc_benchmark {
"tests/AssetManager2_bench.cpp",
"tests/AttributeResolution_bench.cpp",
"tests/CursorWindow_bench.cpp",
+ "tests/Generic_bench.cpp",
"tests/SparseEntry_bench.cpp",
"tests/Theme_bench.cpp",
],
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 15aaae25f754..f0c639574a9f 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -27,39 +27,34 @@ using base::unique_fd;
constexpr const char* kResourcesArsc = "resources.arsc";
-ApkAssets::ApkAssets(std::unique_ptr<Asset> resources_asset,
+ApkAssets::ApkAssets(PrivateConstructorUtil, std::unique_ptr<Asset> resources_asset,
std::unique_ptr<LoadedArsc> loaded_arsc,
- std::unique_ptr<AssetsProvider> assets,
- package_property_t property_flags,
- std::unique_ptr<Asset> idmap_asset,
- std::unique_ptr<LoadedIdmap> loaded_idmap)
+ std::unique_ptr<AssetsProvider> assets, package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset, std::unique_ptr<LoadedIdmap> loaded_idmap)
: resources_asset_(std::move(resources_asset)),
loaded_arsc_(std::move(loaded_arsc)),
assets_provider_(std::move(assets)),
property_flags_(property_flags),
idmap_asset_(std::move(idmap_asset)),
- loaded_idmap_(std::move(loaded_idmap)) {}
+ loaded_idmap_(std::move(loaded_idmap)) {
+}
-std::unique_ptr<ApkAssets> ApkAssets::Load(const std::string& path, package_property_t flags) {
+ApkAssetsPtr ApkAssets::Load(const std::string& path, package_property_t flags) {
return Load(ZipAssetsProvider::Create(path, flags), flags);
}
-std::unique_ptr<ApkAssets> ApkAssets::LoadFromFd(base::unique_fd fd,
- const std::string& debug_name,
- package_property_t flags,
- off64_t offset,
- off64_t len) {
+ApkAssetsPtr ApkAssets::LoadFromFd(base::unique_fd fd, const std::string& debug_name,
+ package_property_t flags, off64_t offset, off64_t len) {
return Load(ZipAssetsProvider::Create(std::move(fd), debug_name, offset, len), flags);
}
-std::unique_ptr<ApkAssets> ApkAssets::Load(std::unique_ptr<AssetsProvider> assets,
- package_property_t flags) {
+ApkAssetsPtr ApkAssets::Load(std::unique_ptr<AssetsProvider> assets, package_property_t flags) {
return LoadImpl(std::move(assets), flags, nullptr /* idmap_asset */, nullptr /* loaded_idmap */);
}
-std::unique_ptr<ApkAssets> ApkAssets::LoadTable(std::unique_ptr<Asset> resources_asset,
- std::unique_ptr<AssetsProvider> assets,
- package_property_t flags) {
+ApkAssetsPtr ApkAssets::LoadTable(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t flags) {
if (resources_asset == nullptr) {
return {};
}
@@ -67,8 +62,7 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadTable(std::unique_ptr<Asset> resources
nullptr /* loaded_idmap */);
}
-std::unique_ptr<ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
- package_property_t flags) {
+ApkAssetsPtr ApkAssets::LoadOverlay(const std::string& idmap_path, package_property_t flags) {
CHECK((flags & PROPERTY_LOADER) == 0U) << "Cannot load RROs through loaders";
auto idmap_asset = AssetsProvider::CreateAssetFromFile(idmap_path);
if (idmap_asset == nullptr) {
@@ -103,10 +97,10 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
std::move(loaded_idmap));
}
-std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<AssetsProvider> assets,
- package_property_t property_flags,
- std::unique_ptr<Asset> idmap_asset,
- std::unique_ptr<LoadedIdmap> loaded_idmap) {
+ApkAssetsPtr ApkAssets::LoadImpl(std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap) {
if (assets == nullptr) {
return {};
}
@@ -125,11 +119,11 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<AssetsProvider> a
std::move(idmap_asset), std::move(loaded_idmap));
}
-std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<Asset> resources_asset,
- std::unique_ptr<AssetsProvider> assets,
- package_property_t property_flags,
- std::unique_ptr<Asset> idmap_asset,
- std::unique_ptr<LoadedIdmap> loaded_idmap) {
+ApkAssetsPtr ApkAssets::LoadImpl(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap) {
if (assets == nullptr ) {
return {};
}
@@ -155,10 +149,9 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<Asset> resources_
return {};
}
- return std::unique_ptr<ApkAssets>(new ApkAssets(std::move(resources_asset),
- std::move(loaded_arsc), std::move(assets),
- property_flags, std::move(idmap_asset),
- std::move(loaded_idmap)));
+ return ApkAssetsPtr::make(PrivateConstructorUtil{}, std::move(resources_asset),
+ std::move(loaded_arsc), std::move(assets), property_flags,
+ std::move(idmap_asset), std::move(loaded_idmap));
}
std::optional<std::string_view> ApkAssets::GetPath() const {
@@ -174,4 +167,5 @@ bool ApkAssets::IsUpToDate() const {
return IsLoader() || ((!loaded_idmap_ || loaded_idmap_->IsUpToDate())
&& assets_provider_->IsUpToDate());
}
+
} // namespace android
diff --git a/libs/androidfw/ApkParsing.cpp b/libs/androidfw/ApkParsing.cpp
index 32d2c5b05acb..7eedfdb5c921 100644
--- a/libs/androidfw/ApkParsing.cpp
+++ b/libs/androidfw/ApkParsing.cpp
@@ -56,6 +56,11 @@ const char* ValidLibraryPathLastSlash(const char* fileName, bool suppress64Bit,
return nullptr;
}
+ // Make sure file starts with 'lib/' prefix.
+ if (strncmp(fileName, APK_LIB.data(), APK_LIB_LEN) != 0) {
+ return nullptr;
+ }
+
// Make sure there aren't subdirectories by checking if the next / after lib/ is the last slash
if (memchr(fileName + APK_LIB_LEN, '/', fileNameLen - APK_LIB_LEN) != lastSlash) {
return nullptr;
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 68f5e4a88c7e..5ffec34be397 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -91,13 +91,19 @@ struct FindEntryResult {
StringPoolRef entry_string_ref;
};
+AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration) {
+ configurations_.push_back(configuration);
+
+ // Don't invalidate caches here as there's nothing cached yet.
+ SetApkAssets(apk_assets, false);
+}
+
AssetManager2::AssetManager2() {
- memset(&configuration_, 0, sizeof(configuration_));
+ configurations_.resize(1);
}
-bool AssetManager2::SetApkAssets(std::vector<const ApkAssets*> apk_assets, bool invalidate_caches) {
- apk_assets_ = std::move(apk_assets);
- BuildDynamicRefTable();
+bool AssetManager2::SetApkAssets(ApkAssetsList apk_assets, bool invalidate_caches) {
+ BuildDynamicRefTable(apk_assets);
RebuildFilterList();
if (invalidate_caches) {
InvalidateCaches(static_cast<uint32_t>(-1));
@@ -105,7 +111,21 @@ bool AssetManager2::SetApkAssets(std::vector<const ApkAssets*> apk_assets, bool
return true;
}
-void AssetManager2::BuildDynamicRefTable() {
+bool AssetManager2::SetApkAssets(std::initializer_list<ApkAssetsPtr> apk_assets,
+ bool invalidate_caches) {
+ return SetApkAssets(ApkAssetsList(apk_assets.begin(), apk_assets.size()), invalidate_caches);
+}
+
+void AssetManager2::BuildDynamicRefTable(ApkAssetsList apk_assets) {
+ auto op = StartOperation();
+
+ apk_assets_.resize(apk_assets.size());
+ for (size_t i = 0; i != apk_assets.size(); ++i) {
+ apk_assets_[i].first = apk_assets[i];
+ // Let's populate the locked assets right away as we're going to need them here later.
+ apk_assets_[i].second = apk_assets[i];
+ }
+
package_groups_.clear();
package_ids_.fill(0xff);
@@ -116,16 +136,19 @@ void AssetManager2::BuildDynamicRefTable() {
// Overlay resources are not directly referenced by an application so their resource ids
// can change throughout the application's lifetime. Assign overlay package ids last.
- std::vector<const ApkAssets*> sorted_apk_assets(apk_assets_);
- std::stable_partition(sorted_apk_assets.begin(), sorted_apk_assets.end(), [](const ApkAssets* a) {
- return !a->IsOverlay();
- });
+ std::vector<const ApkAssets*> sorted_apk_assets;
+ sorted_apk_assets.reserve(apk_assets.size());
+ for (auto& asset : apk_assets) {
+ sorted_apk_assets.push_back(asset.get());
+ }
+ std::stable_partition(sorted_apk_assets.begin(), sorted_apk_assets.end(),
+ [](auto a) { return !a->IsOverlay(); });
// The assets cookie must map to the position of the apk assets in the unsorted apk assets list.
std::unordered_map<const ApkAssets*, ApkAssetsCookie> apk_assets_cookies;
- apk_assets_cookies.reserve(apk_assets_.size());
- for (size_t i = 0, n = apk_assets_.size(); i < n; i++) {
- apk_assets_cookies[apk_assets_[i]] = static_cast<ApkAssetsCookie>(i);
+ apk_assets_cookies.reserve(apk_assets.size());
+ for (size_t i = 0, n = apk_assets.size(); i < n; i++) {
+ apk_assets_cookies[apk_assets[i].get()] = static_cast<ApkAssetsCookie>(i);
}
// 0x01 is reserved for the android package.
@@ -240,9 +263,11 @@ void AssetManager2::BuildDynamicRefTable() {
void AssetManager2::DumpToLog() const {
LOG(INFO) << base::StringPrintf("AssetManager2(this=%p)", this);
+ auto op = StartOperation();
std::string list;
- for (const auto& apk_assets : apk_assets_) {
- base::StringAppendF(&list, "%s,", apk_assets->GetDebugName().c_str());
+ for (size_t i = 0, s = apk_assets_.size(); i < s; ++i) {
+ const auto& assets = GetApkAssets(i);
+ base::StringAppendF(&list, "%s,", assets ? assets->GetDebugName().c_str() : "nullptr");
}
LOG(INFO) << "ApkAssets: " << list;
@@ -279,7 +304,9 @@ const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cooki
if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
return nullptr;
}
- return apk_assets_[cookie]->GetLoadedArsc()->GetStringPool();
+ auto op = StartOperation();
+ const auto& assets = GetApkAssets(cookie);
+ return assets ? assets->GetLoadedArsc()->GetStringPool() : nullptr;
}
const DynamicRefTable* AssetManager2::GetDynamicRefTableForPackage(uint32_t package_id) const {
@@ -329,9 +356,14 @@ const std::unordered_map<std::string, std::string>*
bool AssetManager2::GetOverlayablesToString(android::StringPiece package_name,
std::string* out) const {
+ auto op = StartOperation();
uint8_t package_id = 0U;
- for (const auto& apk_assets : apk_assets_) {
- const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc();
+ for (size_t i = 0, s = apk_assets_.size(); i != s; ++i) {
+ const auto& assets = GetApkAssets(i);
+ if (!assets) {
+ continue;
+ }
+ const LoadedArsc* loaded_arsc = assets->GetLoadedArsc();
if (loaded_arsc == nullptr) {
continue;
}
@@ -384,13 +416,26 @@ bool AssetManager2::GetOverlayablesToString(android::StringPiece package_name,
}
bool AssetManager2::ContainsAllocatedTable() const {
- return std::find_if(apk_assets_.begin(), apk_assets_.end(),
- std::mem_fn(&ApkAssets::IsTableAllocated)) != apk_assets_.end();
+ auto op = StartOperation();
+ for (size_t i = 0, s = apk_assets_.size(); i != s; ++i) {
+ const auto& assets = GetApkAssets(i);
+ if (assets && assets->IsTableAllocated()) {
+ return true;
+ }
+ }
+ return false;
}
-void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
- const int diff = configuration_.diff(configuration);
- configuration_ = configuration;
+void AssetManager2::SetConfigurations(std::vector<ResTable_config> configurations) {
+ int diff = 0;
+ if (configurations_.size() != configurations.size()) {
+ diff = -1;
+ } else {
+ for (int i = 0; i < configurations_.size(); i++) {
+ diff |= configurations_[i].diff(configurations[i]);
+ }
+ }
+ configurations_ = std::move(configurations);
if (diff) {
RebuildFilterList();
@@ -398,8 +443,8 @@ void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
}
}
-std::set<const ApkAssets*> AssetManager2::GetNonSystemOverlays() const {
- std::set<const ApkAssets*> non_system_overlays;
+std::set<AssetManager2::ApkAssetsPtr> AssetManager2::GetNonSystemOverlays() const {
+ std::set<ApkAssetsPtr> non_system_overlays;
for (const PackageGroup& package_group : package_groups_) {
bool found_system_package = false;
for (const ConfiguredPackage& package : package_group.packages_) {
@@ -410,8 +455,11 @@ std::set<const ApkAssets*> AssetManager2::GetNonSystemOverlays() const {
}
if (!found_system_package) {
+ auto op = StartOperation();
for (const ConfiguredOverlay& overlay : package_group.overlays_) {
- non_system_overlays.insert(apk_assets_[overlay.cookie]);
+ if (const auto& asset = GetApkAssets(overlay.cookie)) {
+ non_system_overlays.insert(std::move(asset));
+ }
}
}
}
@@ -422,22 +470,27 @@ std::set<const ApkAssets*> AssetManager2::GetNonSystemOverlays() const {
base::expected<std::set<ResTable_config>, IOError> AssetManager2::GetResourceConfigurations(
bool exclude_system, bool exclude_mipmap) const {
ATRACE_NAME("AssetManager::GetResourceConfigurations");
+ auto op = StartOperation();
+
const auto non_system_overlays =
- (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>();
+ exclude_system ? GetNonSystemOverlays() : std::set<ApkAssetsPtr>();
std::set<ResTable_config> configurations;
for (const PackageGroup& package_group : package_groups_) {
for (size_t i = 0; i < package_group.packages_.size(); i++) {
const ConfiguredPackage& package = package_group.packages_[i];
- if (exclude_system && package.loaded_package_->IsSystem()) {
- continue;
- }
-
- auto apk_assets = apk_assets_[package_group.cookies_[i]];
- if (exclude_system && apk_assets->IsOverlay() &&
- non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
- // Exclude overlays that target system resources.
- continue;
+ if (exclude_system) {
+ if (package.loaded_package_->IsSystem()) {
+ continue;
+ }
+ if (!non_system_overlays.empty()) {
+ // Exclude overlays that target only system resources.
+ const auto& apk_assets = GetApkAssets(package_group.cookies_[i]);
+ if (apk_assets && apk_assets->IsOverlay() &&
+ non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
+ continue;
+ }
+ }
}
auto result = package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
@@ -452,22 +505,27 @@ base::expected<std::set<ResTable_config>, IOError> AssetManager2::GetResourceCon
std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
bool merge_equivalent_languages) const {
ATRACE_NAME("AssetManager::GetResourceLocales");
+ auto op = StartOperation();
+
std::set<std::string> locales;
const auto non_system_overlays =
- (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>();
+ exclude_system ? GetNonSystemOverlays() : std::set<ApkAssetsPtr>();
for (const PackageGroup& package_group : package_groups_) {
for (size_t i = 0; i < package_group.packages_.size(); i++) {
const ConfiguredPackage& package = package_group.packages_[i];
- if (exclude_system && package.loaded_package_->IsSystem()) {
- continue;
- }
-
- auto apk_assets = apk_assets_[package_group.cookies_[i]];
- if (exclude_system && apk_assets->IsOverlay() &&
- non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
- // Exclude overlays that target system resources.
- continue;
+ if (exclude_system) {
+ if (package.loaded_package_->IsSystem()) {
+ continue;
+ }
+ if (!non_system_overlays.empty()) {
+ // Exclude overlays that target only system resources.
+ const auto& apk_assets = GetApkAssets(package_group.cookies_[i]);
+ if (apk_assets && apk_assets->IsOverlay() &&
+ non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
+ continue;
+ }
+ }
}
package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales);
@@ -490,15 +548,15 @@ std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAsset
std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) const {
ATRACE_NAME("AssetManager::OpenDir");
+ auto op = StartOperation();
std::string full_path = "assets/" + dirname;
- std::unique_ptr<SortedVector<AssetDir::FileInfo>> files =
- util::make_unique<SortedVector<AssetDir::FileInfo>>();
+ auto files = util::make_unique<SortedVector<AssetDir::FileInfo>>();
// Start from the back.
- for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) {
- const ApkAssets* apk_assets = *iter;
- if (apk_assets->IsOverlay()) {
+ for (size_t i = apk_assets_.size(); i > 0; --i) {
+ const auto& apk_assets = GetApkAssets(i - 1);
+ if (!apk_assets || apk_assets->IsOverlay()) {
continue;
}
@@ -526,15 +584,17 @@ std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) con
std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
Asset::AccessMode mode,
ApkAssetsCookie* out_cookie) const {
- for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
+ auto op = StartOperation();
+ for (size_t i = apk_assets_.size(); i > 0; i--) {
+ const auto& assets = GetApkAssets(i - 1);
// Prevent RRO from modifying assets and other entries accessed by file
// path. Explicitly asking for a path in a given package (denoted by a
// cookie) is still OK.
- if (apk_assets_[i]->IsOverlay()) {
+ if (!assets || assets->IsOverlay()) {
continue;
}
- std::unique_ptr<Asset> asset = apk_assets_[i]->GetAssetsProvider()->Open(filename, mode);
+ std::unique_ptr<Asset> asset = assets->GetAssetsProvider()->Open(filename, mode);
if (asset) {
if (out_cookie != nullptr) {
*out_cookie = i;
@@ -555,7 +615,9 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
return {};
}
- return apk_assets_[cookie]->GetAssetsProvider()->Open(filename, mode);
+ auto op = StartOperation();
+ const auto& assets = GetApkAssets(cookie);
+ return assets ? assets->GetAssetsProvider()->Open(filename, mode) : nullptr;
}
base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
@@ -568,16 +630,8 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
last_resolution_.resid = resid;
}
- // Might use this if density_override != 0.
- ResTable_config density_override_config;
+ auto op = StartOperation();
- // Select our configuration or generate a density override configuration.
- const ResTable_config* desired_config = &configuration_;
- if (density_override != 0 && density_override != configuration_.density) {
- density_override_config = configuration_;
- density_override_config.density = density_override;
- desired_config = &density_override_config;
- }
// Retrieve the package group from the package id of the resource id.
if (UNLIKELY(!is_valid_resid(resid))) {
@@ -596,112 +650,160 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
}
const PackageGroup& package_group = package_groups_[package_idx];
- auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
- stop_at_first_match, ignore_configuration);
- if (UNLIKELY(!result.has_value())) {
- return base::unexpected(result.error());
- }
+ std::optional<FindEntryResult> final_result;
+ bool final_has_locale = false;
+ bool final_overlaid = false;
+ for (auto & config : configurations_) {
+ // Might use this if density_override != 0.
+ ResTable_config density_override_config;
+
+ // Select our configuration or generate a density override configuration.
+ const ResTable_config* desired_config = &config;
+ if (density_override != 0 && density_override != config.density) {
+ density_override_config = config;
+ density_override_config.density = density_override;
+ desired_config = &density_override_config;
+ }
- bool overlaid = false;
- if (!stop_at_first_match && !ignore_configuration && !apk_assets_[result->cookie]->IsLoader()) {
- for (const auto& id_map : package_group.overlays_) {
- auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
- if (!overlay_entry) {
- // No id map entry exists for this target resource.
- continue;
+ auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
+ stop_at_first_match, ignore_configuration);
+ if (UNLIKELY(!result.has_value())) {
+ return base::unexpected(result.error());
+ }
+ bool overlaid = false;
+ if (!stop_at_first_match && !ignore_configuration) {
+ const auto& assets = GetApkAssets(result->cookie);
+ if (!assets) {
+ ALOGE("Found expired ApkAssets #%d for resource ID 0x%08x.", result->cookie, resid);
+ return base::unexpected(std::nullopt);
}
- if (overlay_entry.IsInlineValue()) {
- // The target resource is overlaid by an inline value not represented by a resource.
- ConfigDescription best_frro_config;
- Res_value best_frro_value;
- bool frro_found = false;
- for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
- if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
- && config.match(*desired_config)) {
- frro_found = true;
- best_frro_config = config;
- best_frro_value = value;
+ if (!assets->IsLoader()) {
+ for (const auto& id_map : package_group.overlays_) {
+ auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
+ if (!overlay_entry) {
+ // No id map entry exists for this target resource.
+ continue;
}
- }
- if (!frro_found) {
- continue;
- }
- result->entry = best_frro_value;
- result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
- result->cookie = id_map.cookie;
-
- if (UNLIKELY(logging_enabled)) {
- last_resolution_.steps.push_back(
- Resolution::Step{Resolution::Step::Type::OVERLAID_INLINE, String8(), result->cookie});
- if (auto path = apk_assets_[result->cookie]->GetPath()) {
- const std::string overlay_path = path->data();
- if (IsFabricatedOverlay(overlay_path)) {
- // FRRO don't have package name so we use the creating package here.
- String8 frro_name = String8("FRRO");
- // Get the first part of it since the expected one should be like
- // {overlayPackageName}-{overlayName}-{4 alphanumeric chars}.frro
- // under /data/resource-cache/.
- const std::string name = overlay_path.substr(overlay_path.rfind('/') + 1);
- const size_t end = name.find('-');
- if (frro_name.size() != overlay_path.size() && end != std::string::npos) {
- frro_name.append(base::StringPrintf(" created by %s",
- name.substr(0 /* pos */,
- end).c_str()).c_str());
+ if (overlay_entry.IsInlineValue()) {
+ // The target resource is overlaid by an inline value not represented by a resource.
+ ConfigDescription best_frro_config;
+ Res_value best_frro_value;
+ bool frro_found = false;
+ for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
+ if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
+ && config.match(*desired_config)) {
+ frro_found = true;
+ best_frro_config = config;
+ best_frro_value = value;
}
- last_resolution_.best_package_name = frro_name;
- } else {
- last_resolution_.best_package_name = result->package_name->c_str();
}
+ if (!frro_found) {
+ continue;
+ }
+ result->entry = best_frro_value;
+ result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+ result->cookie = id_map.cookie;
+
+ if (UNLIKELY(logging_enabled)) {
+ last_resolution_.steps.push_back(Resolution::Step{
+ Resolution::Step::Type::OVERLAID_INLINE, result->cookie, String8()});
+ if (auto path = assets->GetPath()) {
+ const std::string overlay_path = path->data();
+ if (IsFabricatedOverlay(overlay_path)) {
+ // FRRO don't have package name so we use the creating package here.
+ String8 frro_name = String8("FRRO");
+ // Get the first part of it since the expected one should be like
+ // {overlayPackageName}-{overlayName}-{4 alphanumeric chars}.frro
+ // under /data/resource-cache/.
+ const std::string name = overlay_path.substr(overlay_path.rfind('/') + 1);
+ const size_t end = name.find('-');
+ if (frro_name.size() != overlay_path.size() && end != std::string::npos) {
+ frro_name.append(base::StringPrintf(" created by %s",
+ name.substr(0 /* pos */,
+ end).c_str()).c_str());
+ }
+ last_resolution_.best_package_name = frro_name;
+ } else {
+ last_resolution_.best_package_name = result->package_name->c_str();
+ }
+ }
+ overlaid = true;
+ }
+ continue;
}
- overlaid = true;
- }
- continue;
- }
- auto overlay_result = FindEntry(overlay_entry.GetResourceId(), density_override,
- false /* stop_at_first_match */,
- false /* ignore_configuration */);
- if (UNLIKELY(IsIOError(overlay_result))) {
- return base::unexpected(overlay_result.error());
- }
- if (!overlay_result.has_value()) {
- continue;
- }
+ auto overlay_result = FindEntry(overlay_entry.GetResourceId(), density_override,
+ false /* stop_at_first_match */,
+ false /* ignore_configuration */);
+ if (UNLIKELY(IsIOError(overlay_result))) {
+ return base::unexpected(overlay_result.error());
+ }
+ if (!overlay_result.has_value()) {
+ continue;
+ }
- if (!overlay_result->config.isBetterThan(result->config, desired_config)
- && overlay_result->config.compare(result->config) != 0) {
- // The configuration of the entry for the overlay must be equal to or better than the target
- // configuration to be chosen as the better value.
- continue;
- }
+ if (!overlay_result->config.isBetterThan(result->config, desired_config)
+ && overlay_result->config.compare(result->config) != 0) {
+ // The configuration of the entry for the overlay must be equal to or better than the
+ // target configuration to be chosen as the better value.
+ continue;
+ }
- result->cookie = overlay_result->cookie;
- result->entry = overlay_result->entry;
- result->config = overlay_result->config;
- result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+ result->cookie = overlay_result->cookie;
+ result->entry = overlay_result->entry;
+ result->config = overlay_result->config;
+ result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+
+ if (UNLIKELY(logging_enabled)) {
+ last_resolution_.steps.push_back(
+ Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->cookie,
+ overlay_result->config.toString()});
+ last_resolution_.best_package_name =
+ overlay_result->package_name->c_str();
+ overlaid = true;
+ }
+ }
+ }
+ }
- if (UNLIKELY(logging_enabled)) {
- last_resolution_.steps.push_back(
- Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->config.toString(),
- overlay_result->cookie});
- last_resolution_.best_package_name =
- overlay_result->package_name->c_str();
- overlaid = true;
+ bool has_locale = false;
+ if (result->config.locale == 0) {
+ if (default_locale_ != 0) {
+ ResTable_config conf;
+ conf.locale = default_locale_;
+ // Since we know conf has a locale and only a locale, match will tell us if that locale
+ // matches
+ has_locale = conf.match(config);
}
+ } else {
+ has_locale = true;
+ }
+
+ // if we don't have a result yet
+ if (!final_result ||
+ // or this config is better before the locale than the existing result
+ result->config.isBetterThanBeforeLocale(final_result->config, desired_config) ||
+ // or the existing config isn't better before locale and this one specifies a locale
+ // whereas the existing one doesn't
+ (!final_result->config.isBetterThanBeforeLocale(result->config, desired_config)
+ && has_locale && !final_has_locale)) {
+ final_result = result.value();
+ final_overlaid = overlaid;
+ final_has_locale = has_locale;
}
}
if (UNLIKELY(logging_enabled)) {
- last_resolution_.cookie = result->cookie;
- last_resolution_.type_string_ref = result->type_string_ref;
- last_resolution_.entry_string_ref = result->entry_string_ref;
- last_resolution_.best_config_name = result->config.toString();
- if (!overlaid) {
- last_resolution_.best_package_name = result->package_name->c_str();
+ last_resolution_.cookie = final_result->cookie;
+ last_resolution_.type_string_ref = final_result->type_string_ref;
+ last_resolution_.entry_string_ref = final_result->entry_string_ref;
+ last_resolution_.best_config_name = final_result->config.toString();
+ if (!final_overlaid) {
+ last_resolution_.best_package_name = final_result->package_name->c_str();
}
}
- return result;
+ return *final_result;
}
base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
@@ -719,8 +821,10 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
// If `desired_config` is not the same as the set configuration or the caller will accept a value
// from any configuration, then we cannot use our filtered list of types since it only it contains
// types matched to the set configuration.
- const bool use_filtered = !ignore_configuration && &desired_config == &configuration_;
-
+ const bool use_filtered = !ignore_configuration && std::find_if(
+ configurations_.begin(), configurations_.end(),
+ [&desired_config](auto& value) { return &desired_config == &value; })
+ != configurations_.end();
const size_t package_count = package_group.packages_.size();
for (size_t pi = 0; pi < package_count; pi++) {
const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
@@ -769,8 +873,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
} else {
if (UNLIKELY(logging_enabled)) {
last_resolution_.steps.push_back(Resolution::Step{Resolution::Step::Type::SKIPPED,
- this_config.toString(),
- cookie});
+ cookie, this_config.toString()});
}
continue;
}
@@ -786,8 +889,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
if (!offset.has_value()) {
if (UNLIKELY(logging_enabled)) {
last_resolution_.steps.push_back(Resolution::Step{Resolution::Step::Type::NO_ENTRY,
- this_config.toString(),
- cookie});
+ cookie, this_config.toString()});
}
continue;
}
@@ -800,8 +902,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
if (UNLIKELY(logging_enabled)) {
last_resolution_.steps.push_back(Resolution::Step{resolution_type,
- this_config.toString(),
- cookie});
+ cookie, this_config.toString()});
}
// Any configuration will suffice, so break.
@@ -830,22 +931,16 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
.entry = *entry,
.config = *best_config,
.type_flags = type_flags,
+ .dynamic_ref_table = package_group.dynamic_ref_table.get(),
.package_name = &best_package->GetPackageName(),
.type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1),
.entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(),
(*best_entry_verified)->key()),
- .dynamic_ref_table = package_group.dynamic_ref_table.get(),
};
}
void AssetManager2::ResetResourceResolution() const {
- last_resolution_.cookie = kInvalidCookie;
- last_resolution_.resid = 0;
- last_resolution_.steps.clear();
- last_resolution_.type_string_ref = StringPoolRef();
- last_resolution_.entry_string_ref = StringPoolRef();
- last_resolution_.best_config_name.clear();
- last_resolution_.best_package_name.clear();
+ last_resolution_ = Resolution{};
}
void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) {
@@ -867,8 +962,12 @@ std::string AssetManager2::GetLastResourceResolution() const {
return {};
}
+ auto op = StartOperation();
+
const uint32_t resid = last_resolution_.resid;
- const auto package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
+ const auto& assets = GetApkAssets(cookie);
+ const auto package =
+ assets ? assets->GetLoadedArsc()->GetPackageById(get_package_id(resid)) : nullptr;
std::string resource_name_string;
if (package != nullptr) {
@@ -880,26 +979,40 @@ std::string AssetManager2::GetLastResourceResolution() const {
}
std::stringstream log_stream;
- log_stream << base::StringPrintf("Resolution for 0x%08x %s\n"
- "\tFor config - %s", resid, resource_name_string.c_str(),
- configuration_.toString().c_str());
-
+ if (configurations_.size() == 1) {
+ log_stream << base::StringPrintf("Resolution for 0x%08x %s\n"
+ "\tFor config - %s", resid, resource_name_string.c_str(),
+ configurations_[0].toString().c_str());
+ } else {
+ ResTable_config conf = configurations_[0];
+ conf.clearLocale();
+ log_stream << base::StringPrintf("Resolution for 0x%08x %s\n\tFor config - %s and locales",
+ resid, resource_name_string.c_str(), conf.toString().c_str());
+ char str[40];
+ str[0] = '\0';
+ for(auto iter = configurations_.begin(); iter < configurations_.end(); iter++) {
+ iter->getBcp47Locale(str);
+ log_stream << base::StringPrintf(" %s%s", str, iter < configurations_.end() ? "," : "");
+ }
+ }
for (const Resolution::Step& step : last_resolution_.steps) {
- const static std::unordered_map<Resolution::Step::Type, const char*> kStepStrings = {
- {Resolution::Step::Type::INITIAL, "Found initial"},
- {Resolution::Step::Type::BETTER_MATCH, "Found better"},
- {Resolution::Step::Type::OVERLAID, "Overlaid"},
- {Resolution::Step::Type::OVERLAID_INLINE, "Overlaid inline"},
- {Resolution::Step::Type::SKIPPED, "Skipped"},
- {Resolution::Step::Type::NO_ENTRY, "No entry"}
+ constexpr static std::array kStepStrings = {
+ "Found initial",
+ "Found better",
+ "Overlaid",
+ "Overlaid inline",
+ "Skipped",
+ "No entry"
};
- const auto prefix = kStepStrings.find(step.type);
- if (prefix == kStepStrings.end()) {
+ if (step.type < Resolution::Step::Type::INITIAL
+ || step.type > Resolution::Step::Type::NO_ENTRY) {
continue;
}
-
- log_stream << "\n\t" << prefix->second << ": " << apk_assets_[step.cookie]->GetDebugName();
+ const auto prefix = kStepStrings[int(step.type) - int(Resolution::Step::Type::INITIAL)];
+ const auto& assets = GetApkAssets(step.cookie);
+ log_stream << "\n\t" << prefix << ": " << (assets ? assets->GetDebugName() : "<null>")
+ << " #" << step.cookie;
if (!step.config_name.isEmpty()) {
log_stream << " - " << step.config_name;
}
@@ -1036,16 +1149,19 @@ base::expected<std::monostate, NullOrIOError> AssetManager2::ResolveReference(
}
}
-const std::vector<uint32_t> AssetManager2::GetBagResIdStack(uint32_t resid) const {
- auto cached_iter = cached_bag_resid_stacks_.find(resid);
- if (cached_iter != cached_bag_resid_stacks_.end()) {
- return cached_iter->second;
+base::expected<const std::vector<uint32_t>*, NullOrIOError> AssetManager2::GetBagResIdStack(
+ uint32_t resid) const {
+ auto it = cached_bag_resid_stacks_.find(resid);
+ if (it != cached_bag_resid_stacks_.end()) {
+ return &it->second;
+ }
+ std::vector<uint32_t> stacks;
+ if (auto maybe_bag = GetBag(resid, stacks); UNLIKELY(IsIOError(maybe_bag))) {
+ return base::unexpected(maybe_bag.error());
}
- std::vector<uint32_t> found_resids;
- GetBag(resid, found_resids);
- cached_bag_resid_stacks_.emplace(resid, found_resids);
- return found_resids;
+ it = cached_bag_resid_stacks_.emplace(resid, std::move(stacks)).first;
+ return &it->second;
}
base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::ResolveBag(
@@ -1062,9 +1178,15 @@ base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::ResolveBag(
}
base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
- std::vector<uint32_t> found_resids;
- const auto bag = GetBag(resid, found_resids);
- cached_bag_resid_stacks_.emplace(resid, std::move(found_resids));
+ auto resid_stacks_it = cached_bag_resid_stacks_.find(resid);
+ if (resid_stacks_it == cached_bag_resid_stacks_.end()) {
+ resid_stacks_it = cached_bag_resid_stacks_.emplace(resid, std::vector<uint32_t>{}).first;
+ }
+ const auto bag = GetBag(resid, resid_stacks_it->second);
+ if (UNLIKELY(IsIOError(bag))) {
+ cached_bag_resid_stacks_.erase(resid_stacks_it);
+ return base::unexpected(bag.error());
+ }
return bag;
}
@@ -1362,11 +1484,14 @@ void AssetManager2::RebuildFilterList() {
package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
FilteredConfigGroup* group = nullptr;
for (const auto& type_entry : type_spec.type_entries) {
- if (type_entry.config.match(configuration_)) {
- if (!group) {
- group = &package.filtered_configs_.editItemAt(type_id - 1);
+ for (auto & config : configurations_) {
+ if (type_entry.config.match(config)) {
+ if (!group) {
+ group = &package.filtered_configs_.editItemAt(type_id - 1);
+ }
+ group->type_entries.push_back(&type_entry);
+ break;
}
- group->type_entries.push_back(&type_entry);
}
}
});
@@ -1377,25 +1502,40 @@ void AssetManager2::RebuildFilterList() {
}
void AssetManager2::InvalidateCaches(uint32_t diff) {
- cached_bag_resid_stacks_.clear();
+ cached_resolved_values_.clear();
if (diff == 0xffffffffu) {
// Everything must go.
cached_bags_.clear();
+ cached_bag_resid_stacks_.clear();
return;
}
// Be more conservative with what gets purged. Only if the bag has other possible
// variations with respect to what changed (diff) should we remove it.
- for (auto iter = cached_bags_.cbegin(); iter != cached_bags_.cend();) {
- if (diff & iter->second->type_spec_flags) {
- iter = cached_bags_.erase(iter);
+ for (auto stack_it = cached_bag_resid_stacks_.begin();
+ stack_it != cached_bag_resid_stacks_.end();) {
+ const auto it = cached_bags_.find(stack_it->first);
+ if (it == cached_bags_.end()) {
+ stack_it = cached_bag_resid_stacks_.erase(stack_it);
+ } else if ((diff & it->second->type_spec_flags) != 0) {
+ cached_bags_.erase(it);
+ stack_it = cached_bag_resid_stacks_.erase(stack_it);
} else {
- ++iter;
+ ++stack_it; // Keep the item in both caches.
}
}
- cached_resolved_values_.clear();
+ // Need to ensure that both bag caches are consistent, as we populate them in the same function.
+ // Iterate over the cached bags to erase the items without the corresponding resid_stack cache
+ // items.
+ for (auto it = cached_bags_.begin(); it != cached_bags_.end();) {
+ if ((diff & it->second->type_spec_flags) != 0) {
+ it = cached_bags_.erase(it);
+ } else {
+ ++it;
+ }
+ }
}
uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
@@ -1429,6 +1569,37 @@ void AssetManager2::ForEachPackage(base::function_ref<bool(const std::string&, u
}
}
+AssetManager2::ScopedOperation AssetManager2::StartOperation() const {
+ ++number_of_running_scoped_operations_;
+ return ScopedOperation(*this);
+}
+
+void AssetManager2::FinishOperation() const {
+ if (number_of_running_scoped_operations_ < 1) {
+ ALOGW("Invalid FinishOperation() call when there's none happening");
+ return;
+ }
+ if (--number_of_running_scoped_operations_ == 0) {
+ for (auto&& [_, assets] : apk_assets_) {
+ assets.clear();
+ }
+ }
+}
+
+const AssetManager2::ApkAssetsPtr& AssetManager2::GetApkAssets(ApkAssetsCookie cookie) const {
+ DCHECK(number_of_running_scoped_operations_ > 0) << "Must have an operation running";
+
+ if (cookie < 0 || cookie >= apk_assets_.size()) {
+ static const ApkAssetsPtr empty{};
+ return empty;
+ }
+ auto& [wptr, res] = apk_assets_[cookie];
+ if (!res) {
+ res = wptr.promote();
+ }
+ return res;
+}
+
Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
}
@@ -1561,14 +1732,16 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& source) {
using SourceToDestinationRuntimePackageMap = std::unordered_map<int, int>;
std::unordered_map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
- // Determine which ApkAssets are loaded in both theme AssetManagers.
- const auto& src_assets = source.asset_manager_->GetApkAssets();
- for (size_t i = 0; i < src_assets.size(); i++) {
- const ApkAssets* src_asset = src_assets[i];
+ auto op_src = source.asset_manager_->StartOperation();
+ auto op_dst = asset_manager_->StartOperation();
- const auto& dest_assets = asset_manager_->GetApkAssets();
- for (size_t j = 0; j < dest_assets.size(); j++) {
- const ApkAssets* dest_asset = dest_assets[j];
+ for (size_t i = 0; i < source.asset_manager_->GetApkAssetsCount(); i++) {
+ const auto& src_asset = source.asset_manager_->GetApkAssets(i);
+ if (!src_asset) {
+ continue;
+ }
+ for (int j = 0; j < asset_manager_->GetApkAssetsCount(); j++) {
+ const auto& dest_asset = asset_manager_->GetApkAssets(j);
if (src_asset != dest_asset) {
// ResourcesManager caches and reuses ApkAssets when the same apk must be present in
// multiple AssetManagers. Two ApkAssets point to the same version of the same resources
@@ -1694,4 +1867,11 @@ void Theme::Dump() const {
}
}
+AssetManager2::ScopedOperation::ScopedOperation(const AssetManager2& am) : am_(am) {
+}
+
+AssetManager2::ScopedOperation::~ScopedOperation() {
+ am_.FinishOperation();
+}
+
} // namespace android
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index 89835742c8ff..5f98b8f8db43 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -294,14 +294,14 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie
dtohl(header->version), kIdmapCurrentVersion);
return {};
}
+ std::optional<std::string_view> target_path = ReadString(&data_ptr, &data_size, "target path");
+ if (!target_path) {
+ return {};
+ }
std::optional<std::string_view> overlay_path = ReadString(&data_ptr, &data_size, "overlay path");
if (!overlay_path) {
return {};
}
- std::optional<std::string_view> target_path = ReadString(&data_ptr, &data_size, "target path");
- if (!target_path) {
- return {};
- }
if (!ReadString(&data_ptr, &data_size, "target name") ||
!ReadString(&data_ptr, &data_size, "debug info")) {
return {};
@@ -364,7 +364,7 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie
return std::unique_ptr<LoadedIdmap>(
new LoadedIdmap(std::string(idmap_path), header, data_header, target_entries,
target_inline_entries, target_inline_entry_values, configurations,
- overlay_entries, std::move(idmap_string_pool), *target_path, *overlay_path));
+ overlay_entries, std::move(idmap_string_pool), *overlay_path, *target_path));
}
bool LoadedIdmap::IsUpToDate() const {
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index c0fdfe25da21..c9d5e074271b 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -323,7 +323,7 @@ LoadedPackage::GetEntryFromOffset(incfs::verified_map_ptr<ResTable_type> type_ch
}
base::expected<std::monostate, IOError> LoadedPackage::CollectConfigurations(
- bool exclude_mipmap, std::set<ResTable_config>* out_configs) const {\
+ bool exclude_mipmap, std::set<ResTable_config>* out_configs) const {
for (const auto& type_spec : type_specs_) {
if (exclude_mipmap) {
const int type_idx = type_spec.first - 1;
@@ -494,6 +494,8 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
util::ReadUtf16StringFromDevice(header->name, arraysize(header->name),
&loaded_package->package_name_);
+ const bool only_overlayable = (property_flags & PROPERTY_ONLY_OVERLAYABLES) != 0;
+
// A map of TypeSpec builders, each associated with an type index.
// We use these to accumulate the set of Types available for a TypeSpec, and later build a single,
// contiguous block of memory that holds all the Types together with the TypeSpec.
@@ -502,6 +504,9 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
while (iter.HasNext()) {
const Chunk child_chunk = iter.Next();
+ if (only_overlayable && child_chunk.type() != RES_TABLE_OVERLAYABLE_TYPE) {
+ continue;
+ }
switch (child_chunk.type()) {
case RES_STRING_POOL_TYPE: {
const auto pool_address = child_chunk.header<ResChunk_header>();
@@ -655,6 +660,9 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
<< name_to_actor_it->first << "'.";
return {};
}
+ if (only_overlayable) {
+ break;
+ }
// Iterate over the overlayable policy chunks contained within the overlayable chunk data
ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
@@ -800,14 +808,21 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
global_string_pool_ = util::make_unique<OverlayStringPool>(loaded_idmap);
}
+ const bool only_overlayable = (property_flags & PROPERTY_ONLY_OVERLAYABLES) != 0;
+
const size_t package_count = dtohl(header->packageCount);
size_t packages_seen = 0;
- packages_.reserve(package_count);
+ if (!only_overlayable) {
+ packages_.reserve(package_count);
+ }
ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
while (iter.HasNext()) {
const Chunk child_chunk = iter.Next();
+ if (only_overlayable && child_chunk.type() != RES_TABLE_PACKAGE_TYPE) {
+ continue;
+ }
switch (child_chunk.type()) {
case RES_STRING_POOL_TYPE:
// Only use the first string pool. Ignore others.
@@ -837,6 +852,10 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
return false;
}
packages_.push_back(std::move(loaded_package));
+ if (only_overlayable) {
+ // Overlayable is always in the first package, no need to process anything else.
+ return true;
+ }
} break;
default:
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 29d33da6b2f7..06d19e064c91 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1769,13 +1769,21 @@ ResXMLTree::~ResXMLTree()
status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
{
+ const ResChunk_header* chunk = nullptr;
+ const ResChunk_header* lastChunk = nullptr;
+
uninit();
mEventCode = START_DOCUMENT;
if (!data || !size) {
return (mError=BAD_TYPE);
}
-
+ if (size < sizeof(ResXMLTree_header)) {
+ ALOGW("Bad XML block: total size %d is less than the header size %d\n",
+ int(size), int(sizeof(ResXMLTree_header)));
+ mError = BAD_TYPE;
+ goto done;
+ }
if (copyData) {
mOwnedData = malloc(size);
if (mOwnedData == NULL) {
@@ -1792,9 +1800,15 @@ status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
(int)dtohs(mHeader->header.headerSize),
(int)dtohl(mHeader->header.size), (int)size);
mError = BAD_TYPE;
- restart();
- return mError;
+ goto done;
}
+ if (dtohs(mHeader->header.type) != RES_XML_TYPE) {
+ ALOGW("Bad XML block: expected root block type %d, got %d\n",
+ int(RES_XML_TYPE), int(dtohs(mHeader->header.type)));
+ mError = BAD_TYPE;
+ goto done;
+ }
+
mDataEnd = ((const uint8_t*)mHeader) + mSize;
mStrings.uninit();
@@ -1804,9 +1818,8 @@ status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
// First look for a couple interesting chunks: the string block
// and first XML node.
- const ResChunk_header* chunk =
- (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize));
- const ResChunk_header* lastChunk = chunk;
+ chunk = (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize));
+ lastChunk = chunk;
while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) &&
((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) {
status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML");
@@ -1860,7 +1873,11 @@ status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
mError = mStrings.getError();
done:
- restart();
+ if (mError) {
+ uninit();
+ } else {
+ restart();
+ }
return mError;
}
@@ -2551,6 +2568,22 @@ bool ResTable_config::isLocaleBetterThan(const ResTable_config& o,
return false;
}
+bool ResTable_config::isBetterThanBeforeLocale(const ResTable_config& o,
+ const ResTable_config* requested) const {
+ if (requested) {
+ if (imsi || o.imsi) {
+ if ((mcc != o.mcc) && requested->mcc) {
+ return (mcc);
+ }
+
+ if ((mnc != o.mnc) && requested->mnc) {
+ return (mnc);
+ }
+ }
+ }
+ return false;
+}
+
bool ResTable_config::isBetterThan(const ResTable_config& o,
const ResTable_config* requested) const {
if (requested) {
@@ -5436,37 +5469,66 @@ bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
return U16StringToInt(s, len, outValue);
}
-bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
-{
- while (len > 0 && isspace16(*s)) {
- s++;
- len--;
+template <typename T>
+bool parseFloatingPoint(const char16_t* inBuf, size_t inLen, char* tempBuf,
+ const char** outEnd, T& out){
+ while (inLen > 0 && isspace16(*inBuf)) {
+ inBuf++;
+ inLen--;
}
- if (len <= 0) {
+ if (inLen <= 0) {
return false;
}
- char buf[128];
int i=0;
- while (len > 0 && *s != 0 && i < 126) {
- if (*s > 255) {
+ while (inLen > 0 && *inBuf != 0 && i < 126) {
+ if (*inBuf > 255) {
return false;
}
- buf[i++] = *s++;
- len--;
+ tempBuf[i++] = *inBuf++;
+ inLen--;
}
- if (len > 0) {
+ if (inLen > 0) {
+ return false;
+ }
+ if ((tempBuf[0] < '0' || tempBuf[0] > '9') && tempBuf[0] != '.' && tempBuf[0] != '-' && tempBuf[0] != '+') {
return false;
}
- if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
+
+ tempBuf[i] = 0;
+ if constexpr(std::is_same_v<T, float>) {
+ out = strtof(tempBuf, (char**)outEnd);
+ } else {
+ out = strtod(tempBuf, (char**)outEnd);
+ }
+ return true;
+}
+
+bool ResTable::stringToDouble(const char16_t* s, size_t len, double& d){
+ char buf[128];
+ const char* end = nullptr;
+ if (!parseFloatingPoint(s, len, buf, &end, d)) {
return false;
}
- buf[i] = 0;
- const char* end;
- float f = strtof(buf, (char**)&end);
+ while (*end != 0 && isspace((unsigned char)*end)) {
+ end++;
+ }
+
+ return *end == 0;
+}
+
+bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
+{
+ char buf[128];
+ const char* end = nullptr;
+ float f;
+
+ if (!parseFloatingPoint(s, len, buf, &end, f)) {
+ return false;
+ }
if (*end != 0 && !isspace((unsigned char)*end)) {
// Might be a unit...
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index 52e7a70521a1..d7b5914130ee 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -40,17 +40,24 @@ class _ZipEntryRO {
public:
ZipEntry entry;
std::string_view name;
- void *cookie;
+ void *cookie = nullptr;
- _ZipEntryRO() : cookie(NULL) {}
+ _ZipEntryRO() = default;
~_ZipEntryRO() {
- EndIteration(cookie);
+ EndIteration(cookie);
+ }
+
+ android::ZipEntryRO convertToPtr() {
+ _ZipEntryRO* result = new _ZipEntryRO;
+ result->entry = std::move(this->entry);
+ result->name = std::move(this->name);
+ result->cookie = std::exchange(this->cookie, nullptr);
+ return result;
}
private:
- _ZipEntryRO(const _ZipEntryRO& other);
- _ZipEntryRO& operator=(const _ZipEntryRO& other);
+ DISALLOW_COPY_AND_ASSIGN(_ZipEntryRO);
};
ZipFileRO::~ZipFileRO() {
@@ -94,17 +101,15 @@ ZipFileRO::~ZipFileRO() {
ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const
{
- _ZipEntryRO* data = new _ZipEntryRO;
-
- data->name = entryName;
+ _ZipEntryRO data;
+ data.name = entryName;
- const int32_t error = FindEntry(mHandle, entryName, &(data->entry));
+ const int32_t error = FindEntry(mHandle, entryName, &(data.entry));
if (error) {
- delete data;
- return NULL;
+ return nullptr;
}
- return (ZipEntryRO) data;
+ return data.convertToPtr();
}
/*
@@ -143,35 +148,50 @@ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, uint16_t* pMethod,
}
bool ZipFileRO::startIteration(void** cookie) {
- return startIteration(cookie, NULL, NULL);
+ return startIteration(cookie, nullptr, nullptr);
}
-bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* suffix)
-{
- _ZipEntryRO* ze = new _ZipEntryRO;
- int32_t error = StartIteration(mHandle, &(ze->cookie),
+bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* suffix) {
+ auto result = startIterationOrError(prefix, suffix);
+ if (!result.ok()) {
+ return false;
+ }
+ *cookie = result.value();
+ return true;
+}
+
+base::expected<void*, int32_t>
+ZipFileRO::startIterationOrError(const char* prefix, const char* suffix) {
+ _ZipEntryRO ze;
+ int32_t error = StartIteration(mHandle, &(ze.cookie),
prefix ? prefix : "", suffix ? suffix : "");
if (error) {
ALOGW("Could not start iteration over %s: %s", mFileName != NULL ? mFileName : "<null>",
ErrorCodeString(error));
- delete ze;
- return false;
+ return base::unexpected(error);
}
- *cookie = ze;
- return true;
+ return ze.convertToPtr();
}
-ZipEntryRO ZipFileRO::nextEntry(void* cookie)
-{
+ZipEntryRO ZipFileRO::nextEntry(void* cookie) {
+ auto result = nextEntryOrError(cookie);
+ if (!result.ok()) {
+ return nullptr;
+ }
+ return result.value();
+}
+
+base::expected<ZipEntryRO, int32_t> ZipFileRO::nextEntryOrError(void* cookie) {
_ZipEntryRO* ze = reinterpret_cast<_ZipEntryRO*>(cookie);
int32_t error = Next(ze->cookie, &(ze->entry), &(ze->name));
if (error) {
if (error != -1) {
ALOGW("Error iteration over %s: %s", mFileName != NULL ? mFileName : "<null>",
ErrorCodeString(error));
+ return base::unexpected(error);
}
- return NULL;
+ return nullptr;
}
return &(ze->entry);
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 6f88f41976cd..1fa67528c78b 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -17,12 +17,13 @@
#ifndef APKASSETS_H_
#define APKASSETS_H_
+#include <utils/RefBase.h>
+
#include <memory>
#include <string>
#include "android-base/macros.h"
#include "android-base/unique_fd.h"
-
#include "androidfw/Asset.h"
#include "androidfw/AssetsProvider.h"
#include "androidfw/Idmap.h"
@@ -31,34 +32,33 @@
namespace android {
+class ApkAssets;
+
+using ApkAssetsPtr = sp<ApkAssets>;
+
// Holds an APK.
-class ApkAssets {
+class ApkAssets : public RefBase {
public:
// Creates an ApkAssets from a path on device.
- static std::unique_ptr<ApkAssets> Load(const std::string& path,
- package_property_t flags = 0U);
+ static ApkAssetsPtr Load(const std::string& path, package_property_t flags = 0U);
// Creates an ApkAssets from an open file descriptor.
- static std::unique_ptr<ApkAssets> LoadFromFd(base::unique_fd fd,
- const std::string& debug_name,
- package_property_t flags = 0U,
- off64_t offset = 0,
- off64_t len = AssetsProvider::kUnknownLength);
+ static ApkAssetsPtr LoadFromFd(base::unique_fd fd, const std::string& debug_name,
+ package_property_t flags = 0U, off64_t offset = 0,
+ off64_t len = AssetsProvider::kUnknownLength);
// Creates an ApkAssets from an AssetProvider.
// The ApkAssets will take care of destroying the AssetsProvider when it is destroyed.
- static std::unique_ptr<ApkAssets> Load(std::unique_ptr<AssetsProvider> assets,
- package_property_t flags = 0U);
+ static ApkAssetsPtr Load(std::unique_ptr<AssetsProvider> assets, package_property_t flags = 0U);
// Creates an ApkAssets from the given asset file representing a resources.arsc.
- static std::unique_ptr<ApkAssets> LoadTable(std::unique_ptr<Asset> resources_asset,
- std::unique_ptr<AssetsProvider> assets,
- package_property_t flags = 0U);
+ static ApkAssetsPtr LoadTable(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t flags = 0U);
// Creates an ApkAssets from an IDMAP, which contains the original APK path, and the overlay
// data.
- static std::unique_ptr<ApkAssets> LoadOverlay(const std::string& idmap_path,
- package_property_t flags = 0U);
+ static ApkAssetsPtr LoadOverlay(const std::string& idmap_path, package_property_t flags = 0U);
// Path to the contents of the ApkAssets on disk. The path could represent an APk, a directory,
// or some other file type.
@@ -95,22 +95,27 @@ class ApkAssets {
bool IsUpToDate() const;
private:
- static std::unique_ptr<ApkAssets> LoadImpl(std::unique_ptr<AssetsProvider> assets,
- package_property_t property_flags,
- std::unique_ptr<Asset> idmap_asset,
- std::unique_ptr<LoadedIdmap> loaded_idmap);
-
- static std::unique_ptr<ApkAssets> LoadImpl(std::unique_ptr<Asset> resources_asset,
- std::unique_ptr<AssetsProvider> assets,
- package_property_t property_flags,
- std::unique_ptr<Asset> idmap_asset,
- std::unique_ptr<LoadedIdmap> loaded_idmap);
-
- ApkAssets(std::unique_ptr<Asset> resources_asset,
- std::unique_ptr<LoadedArsc> loaded_arsc,
- std::unique_ptr<AssetsProvider> assets,
- package_property_t property_flags,
- std::unique_ptr<Asset> idmap_asset,
+ static ApkAssetsPtr LoadImpl(std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap);
+
+ static ApkAssetsPtr LoadImpl(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap);
+
+ // Allows us to make it possible to call make_shared from inside the class but still keeps the
+ // ctor 'private' for all means and purposes.
+ struct PrivateConstructorUtil {
+ explicit PrivateConstructorUtil() = default;
+ };
+
+ public:
+ ApkAssets(PrivateConstructorUtil, std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<LoadedArsc> loaded_arsc, std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags, std::unique_ptr<Asset> idmap_asset,
std::unique_ptr<LoadedIdmap> loaded_idmap);
std::unique_ptr<Asset> resources_asset_;
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index f10cb9bf480a..d9ff35b49e0a 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -17,14 +17,16 @@
#ifndef ANDROIDFW_ASSETMANAGER2_H_
#define ANDROIDFW_ASSETMANAGER2_H_
-#include "android-base/function_ref.h"
-#include "android-base/macros.h"
+#include <utils/RefBase.h>
#include <array>
#include <limits>
#include <set>
+#include <span>
#include <unordered_map>
+#include "android-base/function_ref.h"
+#include "android-base/macros.h"
#include "androidfw/ApkAssets.h"
#include "androidfw/Asset.h"
#include "androidfw/AssetManager.h"
@@ -94,8 +96,25 @@ class AssetManager2 {
size_t entry_len = 0u;
};
+ using ApkAssetsPtr = sp<const ApkAssets>;
+ using ApkAssetsWPtr = wp<const ApkAssets>;
+ using ApkAssetsList = std::span<const ApkAssetsPtr>;
+
AssetManager2();
explicit AssetManager2(AssetManager2&& other) = default;
+ AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration);
+
+ struct ScopedOperation {
+ DISALLOW_COPY_AND_ASSIGN(ScopedOperation);
+ friend AssetManager2;
+ const AssetManager2& am_;
+ ScopedOperation(const AssetManager2& am);
+
+ public:
+ ~ScopedOperation();
+ };
+
+ [[nodiscard]] ScopedOperation StartOperation() const;
// Sets/resets the underlying ApkAssets for this AssetManager. The ApkAssets
// are not owned by the AssetManager, and must have a longer lifetime.
@@ -103,10 +122,12 @@ class AssetManager2 {
// Only pass invalidate_caches=false when it is known that the structure
// change in ApkAssets is due to a safe addition of resources with completely
// new resource IDs.
- bool SetApkAssets(std::vector<const ApkAssets*> apk_assets, bool invalidate_caches = true);
+ bool SetApkAssets(ApkAssetsList apk_assets, bool invalidate_caches = true);
+ bool SetApkAssets(std::initializer_list<ApkAssetsPtr> apk_assets, bool invalidate_caches = true);
- inline const std::vector<const ApkAssets*>& GetApkAssets() const {
- return apk_assets_;
+ const ApkAssetsPtr& GetApkAssets(ApkAssetsCookie cookie) const;
+ int GetApkAssetsCount() const {
+ return int(apk_assets_.size());
}
// Returns the string pool for the given asset cookie.
@@ -135,10 +156,14 @@ class AssetManager2 {
// Sets/resets the configuration for this AssetManager. This will cause all
// caches that are related to the configuration change to be invalidated.
- void SetConfiguration(const ResTable_config& configuration);
+ void SetConfigurations(std::vector<ResTable_config> configurations);
- inline const ResTable_config& GetConfiguration() const {
- return configuration_;
+ inline const std::vector<ResTable_config>& GetConfigurations() const {
+ return configurations_;
+ }
+
+ inline void SetDefaultLocale(uint32_t default_locale) {
+ default_locale_ = default_locale;
}
// Returns all configurations for which there are resources defined, or an I/O error if reading
@@ -222,9 +247,14 @@ class AssetManager2 {
friend AssetManager2;
friend Theme;
SelectedValue() = default;
- SelectedValue(const ResolvedBag* bag, const ResolvedBag::Entry& entry) :
- cookie(entry.cookie), data(entry.value.data), type(entry.value.dataType),
- flags(bag->type_spec_flags), resid(0U), config({}) {};
+ SelectedValue(const ResolvedBag* bag, const ResolvedBag::Entry& entry)
+ : cookie(entry.cookie),
+ data(entry.value.data),
+ type(entry.value.dataType),
+ flags(bag->type_spec_flags),
+ resid(0U),
+ config() {
+ }
// The cookie representing the ApkAssets in which the value resides.
ApkAssetsCookie cookie = kInvalidCookie;
@@ -306,7 +336,8 @@ class AssetManager2 {
// resource data failed.
base::expected<uint32_t, NullOrIOError> GetResourceTypeSpecFlags(uint32_t resid) const;
- const std::vector<uint32_t> GetBagResIdStack(uint32_t resid) const;
+ base::expected<const std::vector<uint32_t>*, NullOrIOError> GetBagResIdStack(
+ uint32_t resid) const;
// Resets the resource resolution structures in preparation for the next resource retrieval.
void ResetResourceResolution() const;
@@ -399,7 +430,7 @@ class AssetManager2 {
// Assigns package IDs to all shared library ApkAssets.
// Should be called whenever the ApkAssets are changed.
- void BuildDynamicRefTable();
+ void BuildDynamicRefTable(ApkAssetsList assets);
// Purge all resources that are cached and vary by the configuration axis denoted by the
// bitmask `diff`.
@@ -410,16 +441,23 @@ class AssetManager2 {
void RebuildFilterList();
// Retrieves the APK paths of overlays that overlay non-system packages.
- std::set<const ApkAssets*> GetNonSystemOverlays() const;
+ std::set<ApkAssetsPtr> GetNonSystemOverlays() const;
// AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
// been seen while traversing bag parents.
base::expected<const ResolvedBag*, NullOrIOError> GetBag(
uint32_t resid, std::vector<uint32_t>& child_resids) const;
+ // Finish an operation that was running with the current asset manager, and clean up the
+ // promoted apk assets when the last operation ends.
+ void FinishOperation() const;
+
// The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
// have a longer lifetime.
- std::vector<const ApkAssets*> apk_assets_;
+ // The second pair element is the promoted version of the assets, that is held for the duration
+ // of the currently running operation. FinishOperation() clears all promoted assets to make sure
+ // they can be released when the system needs that.
+ mutable std::vector<std::pair<ApkAssetsWPtr, ApkAssetsPtr>> apk_assets_;
// DynamicRefTables for shared library package resolution.
// These are ordered according to apk_assets_. The mappings may change depending on what is
@@ -431,9 +469,11 @@ class AssetManager2 {
// without taking too much memory.
std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_;
- // The current configuration set for this AssetManager. When this changes, cached resources
+ uint32_t default_locale_;
+
+ // The current configurations set for this AssetManager. When this changes, cached resources
// may need to be purged.
- ResTable_config configuration_;
+ std::vector<ResTable_config> configurations_;
// Cached set of bags. These are cached because they can inherit keys from parent bags,
// which involves some calculation.
@@ -446,6 +486,10 @@ class AssetManager2 {
// Cached set of resolved resource values.
mutable std::unordered_map<uint32_t, SelectedValue> cached_resolved_values_;
+ // Tracking the number of the started operations running with the current AssetManager.
+ // Finishing the last one clears all promoted apk assets.
+ mutable int number_of_running_scoped_operations_ = 0;
+
// Whether or not to save resource resolution steps
bool resource_resolution_logging_enabled_ = false;
@@ -463,10 +507,10 @@ class AssetManager2 {
// Marks what kind of override this step was.
Type type;
+ ApkAssetsCookie cookie = kInvalidCookie;
+
// Built name of configuration for this step.
String8 config_name;
-
- ApkAssetsCookie cookie = kInvalidCookie;
};
// Last resolved resource ID.
diff --git a/libs/androidfw/include/androidfw/Errors.h b/libs/androidfw/include/androidfw/Errors.h
index 948162d10480..6667747fc581 100644
--- a/libs/androidfw/include/androidfw/Errors.h
+++ b/libs/androidfw/include/androidfw/Errors.h
@@ -34,7 +34,7 @@ using NullOrIOError = std::variant<std::nullopt_t, IOError>;
// Checks whether the result holds an unexpected I/O error.
template <typename T>
-static inline bool IsIOError(const base::expected<T, NullOrIOError> result) {
+static inline bool IsIOError(const base::expected<T, NullOrIOError>& result) {
return !result.has_value() && std::holds_alternative<IOError>(result.error());
}
diff --git a/libs/androidfw/include/androidfw/IDiagnostics.h b/libs/androidfw/include/androidfw/IDiagnostics.h
index 4d5844eaa069..865a298f8389 100644
--- a/libs/androidfw/include/androidfw/IDiagnostics.h
+++ b/libs/androidfw/include/androidfw/IDiagnostics.h
@@ -86,6 +86,17 @@ struct IDiagnostics {
DiagMessageActual actual = message.Build();
Log(Level::Note, actual);
}
+
+ virtual void SetVerbose(bool val) {
+ verbose_ = val;
+ }
+
+ virtual bool IsVerbose() {
+ return verbose_;
+ }
+
+ private:
+ bool verbose_ = false;
};
class SourcePathDiagnostics : public IDiagnostics {
@@ -105,6 +116,14 @@ class SourcePathDiagnostics : public IDiagnostics {
return error;
}
+ void SetVerbose(bool val) override {
+ diag_->SetVerbose(val);
+ }
+
+ bool IsVerbose() override {
+ return diag_->IsVerbose();
+ }
+
private:
Source source_;
IDiagnostics* diag_;
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 4d12885ad291..3a7287187781 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -96,6 +96,9 @@ enum : package_property_t {
// The apk assets is owned by the application running in this process and incremental crash
// protections for this APK must be disabled.
PROPERTY_DISABLE_INCREMENTAL_HARDENING = 1U << 4U,
+
+ // The apk assets only contain the overlayable declarations information.
+ PROPERTY_ONLY_OVERLAYABLES = 1U << 5U,
};
struct OverlayableInfo {
diff --git a/libs/androidfw/include/androidfw/MutexGuard.h b/libs/androidfw/include/androidfw/MutexGuard.h
index 6fc6d64e2f6e..b6093dbb6d3d 100644
--- a/libs/androidfw/include/androidfw/MutexGuard.h
+++ b/libs/androidfw/include/androidfw/MutexGuard.h
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#ifndef ANDROIDFW_MUTEXGUARD_H
-#define ANDROIDFW_MUTEXGUARD_H
+#pragma once
#include <mutex>
#include <optional>
#include <type_traits>
+#include <utility>
#include "android-base/macros.h"
@@ -45,20 +45,25 @@ class ScopedLock;
//
template <typename T>
class Guarded {
- static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer");
+ static_assert(!std::is_pointer_v<T>, "T must not be a raw pointer");
public:
- Guarded() : guarded_(std::in_place, T()) {
+ Guarded() : guarded_(std::in_place) {
}
explicit Guarded(const T& guarded) : guarded_(std::in_place, guarded) {
}
- explicit Guarded(T&& guarded) : guarded_(std::in_place, std::forward<T>(guarded)) {
+ explicit Guarded(T&& guarded) : guarded_(std::in_place, std::move(guarded)) {
}
- ~Guarded() {
- std::lock_guard<std::mutex> scoped_lock(lock_);
+ // Unfortunately, some legacy designs make even class deletion race-prone, where some other
+ // thread may have not finished working with the same object. For those cases one may destroy the
+ // object under a lock (but please fix your code, at least eventually!).
+ template <class Func>
+ void safeDelete(Func f) {
+ std::lock_guard scoped_lock(lock_);
+ f(guarded_ ? &guarded_.value() : nullptr);
guarded_.reset();
}
@@ -96,5 +101,3 @@ class ScopedLock {
};
} // namespace android
-
-#endif // ANDROIDFW_MUTEXGUARD_H
diff --git a/libs/androidfw/include/androidfw/ObbFile.h b/libs/androidfw/include/androidfw/ObbFile.h
index 3dbf997dc367..38ece5c1546f 100644
--- a/libs/androidfw/include/androidfw/ObbFile.h
+++ b/libs/androidfw/include/androidfw/ObbFile.h
@@ -43,10 +43,6 @@ public:
bool removeFrom(const char* filename);
bool removeFrom(int fd);
- const char* getFileName() const {
- return mFileName;
- }
-
const String8 getPackageName() const {
return mPackageName;
}
@@ -127,8 +123,6 @@ private:
/* The encryption salt. */
unsigned char mSalt[8];
- const char* mFileName;
-
size_t mFooterStart;
bool parseObbFile(int fd);
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 631bda4f886c..52666ab8d1d5 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1375,6 +1375,8 @@ struct ResTable_config
// match the requested configuration at all.
bool isLocaleBetterThan(const ResTable_config& o, const ResTable_config* requested) const;
+ bool isBetterThanBeforeLocale(const ResTable_config& o, const ResTable_config* requested) const;
+
String8 toString() const;
};
@@ -2162,6 +2164,7 @@ public:
static bool stringToInt(const char16_t* s, size_t len, Res_value* outValue);
static bool stringToFloat(const char16_t* s, size_t len, Res_value* outValue);
+ static bool stringToDouble(const char16_t* s, size_t len, double& outValue);
// Used with stringToValue.
class Accessor
diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
index 10f6d0655bf4..be1f98f4843d 100644
--- a/libs/androidfw/include/androidfw/ZipFileRO.h
+++ b/libs/androidfw/include/androidfw/ZipFileRO.h
@@ -37,6 +37,8 @@
#include <unistd.h>
#include <time.h>
+#include <android-base/expected.h>
+
#include <util/map_ptr.h>
#include <utils/Compat.h>
@@ -102,6 +104,11 @@ public:
*/
bool startIteration(void** cookie);
bool startIteration(void** cookie, const char* prefix, const char* suffix);
+ /*
+ * Same as above, but returns the error code in case of failure.
+ * #see libziparchive/zip_error.h.
+ */
+ base::expected<void*, int32_t> startIterationOrError(const char* prefix, const char* suffix);
/**
* Return the next entry in iteration order, or NULL if there are no more
@@ -109,6 +116,12 @@ public:
*/
ZipEntryRO nextEntry(void* cookie);
+ /**
+ * Same as above, but returns the error code in case of failure.
+ * #see libziparchive/zip_error.h.
+ */
+ base::expected<ZipEntryRO, int32_t> nextEntryOrError(void* cookie);
+
void endIteration(void* cookie);
void releaseEntry(ZipEntryRO entry) const;
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index 19db25ce8811..70326b71da28 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -35,8 +35,7 @@ using ::testing::StrEq;
namespace android {
TEST(ApkAssetsTest, LoadApk) {
- std::unique_ptr<const ApkAssets> loaded_apk =
- ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+ auto loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
ASSERT_THAT(loaded_apk, NotNull());
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
@@ -50,7 +49,7 @@ TEST(ApkAssetsTest, LoadApkFromFd) {
unique_fd fd(::open(path.c_str(), O_RDONLY | O_BINARY));
ASSERT_THAT(fd.get(), Ge(0));
- std::unique_ptr<const ApkAssets> loaded_apk = ApkAssets::LoadFromFd(std::move(fd), path);
+ auto loaded_apk = ApkAssets::LoadFromFd(std::move(fd), path);
ASSERT_THAT(loaded_apk, NotNull());
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
@@ -60,8 +59,7 @@ TEST(ApkAssetsTest, LoadApkFromFd) {
}
TEST(ApkAssetsTest, LoadApkAsSharedLibrary) {
- std::unique_ptr<const ApkAssets> loaded_apk =
- ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
+ auto loaded_apk = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
ASSERT_THAT(loaded_apk, NotNull());
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
@@ -79,8 +77,7 @@ TEST(ApkAssetsTest, LoadApkAsSharedLibrary) {
}
TEST(ApkAssetsTest, CreateAndDestroyAssetKeepsApkAssetsOpen) {
- std::unique_ptr<const ApkAssets> loaded_apk =
- ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+ auto loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
ASSERT_THAT(loaded_apk, NotNull());
{ ASSERT_THAT(loaded_apk->GetAssetsProvider()->Open("res/layout/main.xml",
@@ -91,8 +88,7 @@ TEST(ApkAssetsTest, CreateAndDestroyAssetKeepsApkAssetsOpen) {
}
TEST(ApkAssetsTest, OpenUncompressedAssetFd) {
- std::unique_ptr<const ApkAssets> loaded_apk =
- ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+ auto loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
ASSERT_THAT(loaded_apk, NotNull());
auto asset = loaded_apk->GetAssetsProvider()->Open("assets/uncompressed.txt",
diff --git a/libs/androidfw/tests/ApkParsing_test.cpp b/libs/androidfw/tests/ApkParsing_test.cpp
index 62e88c619e5c..ac1dc9b88463 100644
--- a/libs/androidfw/tests/ApkParsing_test.cpp
+++ b/libs/androidfw/tests/ApkParsing_test.cpp
@@ -74,4 +74,10 @@ TEST(ApkParsingTest, InvalidFileAtRoot) {
auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
ASSERT_THAT(lastSlash, IsNull());
}
+
+TEST(ApkParsingTest, InvalidPrefix) {
+ const char* path = "assets/libhello.so";
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ ASSERT_THAT(lastSlash, IsNull());
+}
} \ No newline at end of file
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index c7ae618991b9..2caa98c35971 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -38,9 +38,9 @@ constexpr const static char* kFrameworkPath = "/system/framework/framework-res.a
static void BM_AssetManagerLoadAssets(benchmark::State& state) {
std::string path = GetTestDataPath() + "/basic/basic.apk";
while (state.KeepRunning()) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
+ auto apk = ApkAssets::Load(path);
AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
+ assets.SetApkAssets({apk});
}
}
BENCHMARK(BM_AssetManagerLoadAssets);
@@ -61,9 +61,9 @@ BENCHMARK(BM_AssetManagerLoadAssetsOld);
static void BM_AssetManagerLoadFrameworkAssets(benchmark::State& state) {
std::string path = kFrameworkPath;
while (state.KeepRunning()) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
+ auto apk = ApkAssets::Load(path);
AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
+ assets.SetApkAssets({apk});
}
}
BENCHMARK(BM_AssetManagerLoadFrameworkAssets);
@@ -129,14 +129,14 @@ static void BM_AssetManagerGetResourceFrameworkLocaleOld(benchmark::State& state
BENCHMARK(BM_AssetManagerGetResourceFrameworkLocaleOld);
static void BM_AssetManagerGetBag(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+ auto apk = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
if (apk == nullptr) {
state.SkipWithError("Failed to load assets");
return;
}
AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
+ assets.SetApkAssets({apk});
while (state.KeepRunning()) {
auto bag = assets.GetBag(app::R::style::StyleTwo);
@@ -181,14 +181,14 @@ static void BM_AssetManagerGetBagOld(benchmark::State& state) {
BENCHMARK(BM_AssetManagerGetBagOld);
static void BM_AssetManagerGetResourceLocales(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+ auto apk = ApkAssets::Load(kFrameworkPath);
if (apk == nullptr) {
state.SkipWithError("Failed to load assets");
return;
}
AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
+ assets.SetApkAssets({apk});
while (state.KeepRunning()) {
std::set<std::string> locales =
@@ -217,21 +217,23 @@ static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) {
BENCHMARK(BM_AssetManagerGetResourceLocalesOld);
static void BM_AssetManagerSetConfigurationFramework(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+ auto apk = ApkAssets::Load(kFrameworkPath);
if (apk == nullptr) {
state.SkipWithError("Failed to load assets");
return;
}
AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
+ assets.SetApkAssets({apk});
ResTable_config config;
memset(&config, 0, sizeof(config));
+ std::vector<ResTable_config> configs;
+ configs.push_back(config);
while (state.KeepRunning()) {
- config.sdkVersion = ~config.sdkVersion;
- assets.SetConfiguration(config);
+ configs[0].sdkVersion = ~configs[0].sdkVersion;
+ assets.SetConfigurations(configs);
}
}
BENCHMARK(BM_AssetManagerSetConfigurationFramework);
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 4394740e44ba..c62f095e9dac 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -91,19 +91,19 @@ class AssetManager2Test : public ::testing::Test {
}
protected:
- std::unique_ptr<const ApkAssets> basic_assets_;
- std::unique_ptr<const ApkAssets> basic_de_fr_assets_;
- std::unique_ptr<const ApkAssets> basic_xhdpi_assets_;
- std::unique_ptr<const ApkAssets> basic_xxhdpi_assets_;
- std::unique_ptr<const ApkAssets> style_assets_;
- std::unique_ptr<const ApkAssets> lib_one_assets_;
- std::unique_ptr<const ApkAssets> lib_two_assets_;
- std::unique_ptr<const ApkAssets> libclient_assets_;
- std::unique_ptr<const ApkAssets> appaslib_assets_;
- std::unique_ptr<const ApkAssets> system_assets_;
- std::unique_ptr<const ApkAssets> app_assets_;
- std::unique_ptr<const ApkAssets> overlay_assets_;
- std::unique_ptr<const ApkAssets> overlayable_assets_;
+ AssetManager2::ApkAssetsPtr basic_assets_;
+ AssetManager2::ApkAssetsPtr basic_de_fr_assets_;
+ AssetManager2::ApkAssetsPtr basic_xhdpi_assets_;
+ AssetManager2::ApkAssetsPtr basic_xxhdpi_assets_;
+ AssetManager2::ApkAssetsPtr style_assets_;
+ AssetManager2::ApkAssetsPtr lib_one_assets_;
+ AssetManager2::ApkAssetsPtr lib_two_assets_;
+ AssetManager2::ApkAssetsPtr libclient_assets_;
+ AssetManager2::ApkAssetsPtr appaslib_assets_;
+ AssetManager2::ApkAssetsPtr system_assets_;
+ AssetManager2::ApkAssetsPtr app_assets_;
+ AssetManager2::ApkAssetsPtr overlay_assets_;
+ AssetManager2::ApkAssetsPtr overlayable_assets_;
};
TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
@@ -113,8 +113,8 @@ TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
desired_config.language[1] = 'e';
AssetManager2 assetmanager;
- assetmanager.SetConfiguration(desired_config);
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetApkAssets({basic_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
ASSERT_TRUE(value.has_value());
@@ -137,8 +137,8 @@ TEST_F(AssetManager2Test, FindsResourceFromMultipleApkAssets) {
desired_config.language[1] = 'e';
AssetManager2 assetmanager;
- assetmanager.SetConfiguration(desired_config);
- assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
+ assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetApkAssets({basic_assets_, basic_de_fr_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
ASSERT_TRUE(value.has_value());
@@ -159,8 +159,7 @@ TEST_F(AssetManager2Test, FindsResourceFromSharedLibrary) {
// libclient is built with lib_one and then lib_two in order.
// Reverse the order to test that proper package ID re-assignment is happening.
- assetmanager.SetApkAssets(
- {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
+ assetmanager.SetApkAssets({lib_two_assets_, lib_one_assets_, libclient_assets_});
auto value = assetmanager.GetResource(libclient::R::string::foo_one);
ASSERT_TRUE(value.has_value());
@@ -195,7 +194,7 @@ TEST_F(AssetManager2Test, FindsResourceFromSharedLibrary) {
TEST_F(AssetManager2Test, FindsResourceFromAppLoadedAsSharedLibrary) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({appaslib_assets_.get()});
+ assetmanager.SetApkAssets({appaslib_assets_});
// The appaslib package will have been assigned the package ID 0x02.
auto value = assetmanager.GetResource(fix_package_id(appaslib::R::integer::number1, 0x02));
@@ -206,27 +205,26 @@ TEST_F(AssetManager2Test, FindsResourceFromAppLoadedAsSharedLibrary) {
TEST_F(AssetManager2Test, AssignsOverlayPackageIdLast) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets(
- {overlayable_assets_.get(), overlay_assets_.get(), lib_one_assets_.get()});
+ assetmanager.SetApkAssets({overlayable_assets_, overlay_assets_, lib_one_assets_});
- auto apk_assets = assetmanager.GetApkAssets();
- ASSERT_EQ(3, apk_assets.size());
- ASSERT_EQ(overlayable_assets_.get(), apk_assets[0]);
- ASSERT_EQ(overlay_assets_.get(), apk_assets[1]);
- ASSERT_EQ(lib_one_assets_.get(), apk_assets[2]);
+ ASSERT_EQ(3, assetmanager.GetApkAssetsCount());
+ auto op = assetmanager.StartOperation();
+ ASSERT_EQ(overlayable_assets_, assetmanager.GetApkAssets(0));
+ ASSERT_EQ(overlay_assets_, assetmanager.GetApkAssets(1));
+ ASSERT_EQ(lib_one_assets_, assetmanager.GetApkAssets(2));
- auto get_first_package_id = [&assetmanager](const ApkAssets* apkAssets) -> uint8_t {
+ auto get_first_package_id = [&assetmanager](auto apkAssets) -> uint8_t {
return assetmanager.GetAssignedPackageId(apkAssets->GetLoadedArsc()->GetPackages()[0].get());
};
- ASSERT_EQ(0x7f, get_first_package_id(overlayable_assets_.get()));
- ASSERT_EQ(0x03, get_first_package_id(overlay_assets_.get()));
- ASSERT_EQ(0x02, get_first_package_id(lib_one_assets_.get()));
+ ASSERT_EQ(0x7f, get_first_package_id(overlayable_assets_));
+ ASSERT_EQ(0x03, get_first_package_id(overlay_assets_));
+ ASSERT_EQ(0x02, get_first_package_id(lib_one_assets_));
}
TEST_F(AssetManager2Test, GetSharedLibraryResourceName) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({lib_one_assets_.get()});
+ assetmanager.SetApkAssets({lib_one_assets_});
auto name = assetmanager.GetResourceName(lib_one::R::string::foo);
ASSERT_TRUE(name.has_value());
@@ -235,7 +233,7 @@ TEST_F(AssetManager2Test, GetSharedLibraryResourceName) {
TEST_F(AssetManager2Test, GetResourceNameNonMatchingConfig) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_de_fr_assets_.get()});
+ assetmanager.SetApkAssets({basic_de_fr_assets_});
auto value = assetmanager.GetResourceName(basic::R::string::test1);
ASSERT_TRUE(value.has_value());
@@ -244,7 +242,7 @@ TEST_F(AssetManager2Test, GetResourceNameNonMatchingConfig) {
TEST_F(AssetManager2Test, GetResourceTypeSpecFlags) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_de_fr_assets_.get()});
+ assetmanager.SetApkAssets({basic_de_fr_assets_});
auto value = assetmanager.GetResourceTypeSpecFlags(basic::R::string::test1);
ASSERT_TRUE(value.has_value());
@@ -253,7 +251,7 @@ TEST_F(AssetManager2Test, GetResourceTypeSpecFlags) {
TEST_F(AssetManager2Test, FindsBagResourceFromSingleApkAssets) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetApkAssets({basic_assets_});
auto bag = assetmanager.GetBag(basic::R::array::integerArray1);
ASSERT_TRUE(bag.has_value());
@@ -280,8 +278,7 @@ TEST_F(AssetManager2Test, FindsBagResourceFromSharedLibrary) {
// libclient is built with lib_one and then lib_two in order.
// Reverse the order to test that proper package ID re-assignment is happening.
- assetmanager.SetApkAssets(
- {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
+ assetmanager.SetApkAssets({lib_two_assets_, lib_one_assets_, libclient_assets_});
auto bag = assetmanager.GetBag(fix_package_id(lib_one::R::style::Theme, 0x03));
ASSERT_TRUE(bag.has_value());
@@ -300,8 +297,7 @@ TEST_F(AssetManager2Test, FindsBagResourceFromMultipleSharedLibraries) {
// libclient is built with lib_one and then lib_two in order.
// Reverse the order to test that proper package ID re-assignment is happening.
- assetmanager.SetApkAssets(
- {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
+ assetmanager.SetApkAssets({lib_two_assets_, lib_one_assets_, libclient_assets_});
auto bag = assetmanager.GetBag(libclient::R::style::ThemeMultiLib);
ASSERT_TRUE(bag.has_value());
@@ -321,8 +317,7 @@ TEST_F(AssetManager2Test, FindsStyleResourceWithParentFromSharedLibrary) {
// libclient is built with lib_one and then lib_two in order.
// Reverse the order to test that proper package ID re-assignment is happening.
- assetmanager.SetApkAssets(
- {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
+ assetmanager.SetApkAssets({lib_two_assets_, lib_one_assets_, libclient_assets_});
auto bag = assetmanager.GetBag(libclient::R::style::Theme);
ASSERT_TRUE(bag.has_value());
@@ -337,7 +332,7 @@ TEST_F(AssetManager2Test, FindsStyleResourceWithParentFromSharedLibrary) {
TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({style_assets_.get()});
+ assetmanager.SetApkAssets({style_assets_});
auto bag_one = assetmanager.GetBag(app::R::style::StyleOne);
ASSERT_TRUE(bag_one.has_value());
@@ -401,7 +396,7 @@ TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
TEST_F(AssetManager2Test, MergeStylesCircularDependency) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({style_assets_.get()});
+ assetmanager.SetApkAssets({style_assets_});
// GetBag should stop traversing the parents of styles when a circular
// dependency is detected
@@ -412,7 +407,7 @@ TEST_F(AssetManager2Test, MergeStylesCircularDependency) {
TEST_F(AssetManager2Test, ResolveReferenceToResource) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetApkAssets({basic_assets_});
auto value = assetmanager.GetResource(basic::R::integer::ref1);
ASSERT_TRUE(value.has_value());
@@ -428,7 +423,7 @@ TEST_F(AssetManager2Test, ResolveReferenceToResource) {
TEST_F(AssetManager2Test, ResolveReferenceToBag) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetApkAssets({basic_assets_});
auto value = assetmanager.GetResource(basic::R::integer::number2, true /*may_be_bag*/);
ASSERT_TRUE(value.has_value());
@@ -444,7 +439,7 @@ TEST_F(AssetManager2Test, ResolveReferenceToBag) {
TEST_F(AssetManager2Test, ResolveDeepIdReference) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetApkAssets({basic_assets_});
// Set up the resource ids
auto high_ref = assetmanager.GetResourceId("@id/high_ref", "values", "com.android.basic");
@@ -470,12 +465,11 @@ TEST_F(AssetManager2Test, ResolveDeepIdReference) {
TEST_F(AssetManager2Test, DensityOverride) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_assets_.get(), basic_xhdpi_assets_.get(),
- basic_xxhdpi_assets_.get()});
- assetmanager.SetConfiguration({
+ assetmanager.SetApkAssets({basic_assets_, basic_xhdpi_assets_, basic_xxhdpi_assets_});
+ assetmanager.SetConfigurations({{
.density = ResTable_config::DENSITY_XHIGH,
.sdkVersion = 21,
- });
+ }});
auto value = assetmanager.GetResource(basic::R::string::density, false /*may_be_bag*/);
ASSERT_TRUE(value.has_value());
@@ -493,7 +487,7 @@ TEST_F(AssetManager2Test, DensityOverride) {
TEST_F(AssetManager2Test, KeepLastReferenceIdUnmodifiedIfNoReferenceIsResolved) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetApkAssets({basic_assets_});
// Create some kind of value that is NOT a reference.
AssetManager2::SelectedValue value{};
@@ -509,7 +503,7 @@ TEST_F(AssetManager2Test, KeepLastReferenceIdUnmodifiedIfNoReferenceIsResolved)
TEST_F(AssetManager2Test, ResolveReferenceMissingResourceDoNotCacheFlags) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetApkAssets({basic_assets_});
{
AssetManager2::SelectedValue value{};
value.data = basic::R::string::test1;
@@ -540,7 +534,7 @@ TEST_F(AssetManager2Test, ResolveReferenceMissingResourceDoNotCacheFlags) {
TEST_F(AssetManager2Test, ResolveReferenceMissingResource) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetApkAssets({basic_assets_});
const uint32_t kMissingResId = 0x8001ffff;
AssetManager2::SelectedValue value{};
@@ -558,7 +552,7 @@ TEST_F(AssetManager2Test, ResolveReferenceMissingResource) {
TEST_F(AssetManager2Test, ResolveReferenceMissingResourceLib) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({libclient_assets_.get()});
+ assetmanager.SetApkAssets({libclient_assets_});
AssetManager2::SelectedValue value{};
value.type = Res_value::TYPE_REFERENCE;
@@ -580,7 +574,7 @@ static bool IsConfigurationPresent(const std::set<ResTable_config>& configuratio
TEST_F(AssetManager2Test, GetResourceConfigurations) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({system_assets_.get(), basic_de_fr_assets_.get()});
+ assetmanager.SetApkAssets({system_assets_, basic_de_fr_assets_});
auto configurations = assetmanager.GetResourceConfigurations();
ASSERT_TRUE(configurations.has_value());
@@ -625,7 +619,7 @@ TEST_F(AssetManager2Test, GetResourceConfigurations) {
TEST_F(AssetManager2Test, GetResourceLocales) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({system_assets_.get(), basic_de_fr_assets_.get()});
+ assetmanager.SetApkAssets({system_assets_, basic_de_fr_assets_});
std::set<std::string> locales = assetmanager.GetResourceLocales();
@@ -644,7 +638,7 @@ TEST_F(AssetManager2Test, GetResourceLocales) {
TEST_F(AssetManager2Test, GetResourceId) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetApkAssets({basic_assets_});
auto resid = assetmanager.GetResourceId("com.android.basic:layout/main", "", "");
ASSERT_TRUE(resid.has_value());
@@ -661,7 +655,7 @@ TEST_F(AssetManager2Test, GetResourceId) {
TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({system_assets_.get()});
+ assetmanager.SetApkAssets({system_assets_});
std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
ASSERT_THAT(asset, NotNull());
@@ -673,7 +667,7 @@ TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {
TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
+ assetmanager.SetApkAssets({system_assets_, app_assets_});
std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
ASSERT_THAT(asset, NotNull());
@@ -685,7 +679,7 @@ TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {
TEST_F(AssetManager2Test, OpenDir) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({system_assets_.get()});
+ assetmanager.SetApkAssets({system_assets_});
std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
ASSERT_THAT(asset_dir, NotNull());
@@ -707,7 +701,7 @@ TEST_F(AssetManager2Test, OpenDir) {
TEST_F(AssetManager2Test, OpenDirFromManyApks) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
+ assetmanager.SetApkAssets({system_assets_, app_assets_});
std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
ASSERT_THAT(asset_dir, NotNull());
@@ -727,8 +721,8 @@ TEST_F(AssetManager2Test, GetLastPathWithoutEnablingReturnsEmpty) {
ResTable_config desired_config;
AssetManager2 assetmanager;
- assetmanager.SetConfiguration(desired_config);
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetApkAssets({basic_assets_});
assetmanager.SetResourceResolutionLoggingEnabled(false);
auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -742,8 +736,8 @@ TEST_F(AssetManager2Test, GetLastPathWithoutResolutionReturnsEmpty) {
ResTable_config desired_config;
AssetManager2 assetmanager;
- assetmanager.SetConfiguration(desired_config);
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetApkAssets({basic_assets_});
auto result = assetmanager.GetLastResourceResolution();
EXPECT_EQ("", result);
@@ -757,18 +751,19 @@ TEST_F(AssetManager2Test, GetLastPathWithSingleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetResourceResolutionLoggingEnabled(true);
- assetmanager.SetConfiguration(desired_config);
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetApkAssets({basic_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
ASSERT_TRUE(value.has_value());
auto result = assetmanager.GetLastResourceResolution();
- EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n"
- "\tFor config - de\n"
- "\tFound initial: basic/basic.apk\n"
- "Best matching is from default configuration of com.android.basic",
- result);
+ EXPECT_EQ(
+ "Resolution for 0x7f030000 com.android.basic:string/test1\n"
+ "\tFor config - de\n"
+ "\tFound initial: basic/basic.apk #0\n"
+ "Best matching is from default configuration of com.android.basic",
+ result);
}
TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
@@ -779,19 +774,20 @@ TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetResourceResolutionLoggingEnabled(true);
- assetmanager.SetConfiguration(desired_config);
- assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
+ assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetApkAssets({basic_assets_, basic_de_fr_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
ASSERT_TRUE(value.has_value());
auto result = assetmanager.GetLastResourceResolution();
- EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n"
- "\tFor config - de\n"
- "\tFound initial: basic/basic.apk\n"
- "\tFound better: basic/basic_de_fr.apk - de\n"
- "Best matching is from de configuration of com.android.basic",
- result);
+ EXPECT_EQ(
+ "Resolution for 0x7f030000 com.android.basic:string/test1\n"
+ "\tFor config - de\n"
+ "\tFound initial: basic/basic.apk #0\n"
+ "\tFound better: basic/basic_de_fr.apk #1 - de\n"
+ "Best matching is from de configuration of com.android.basic",
+ result);
}
TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
@@ -800,8 +796,8 @@ TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
AssetManager2 assetmanager;
assetmanager.SetResourceResolutionLoggingEnabled(true);
- assetmanager.SetConfiguration(desired_config);
- assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetApkAssets({basic_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
ASSERT_TRUE(value.has_value());
@@ -821,8 +817,8 @@ TEST_F(AssetManager2Test, GetOverlayablesToString) {
AssetManager2 assetmanager;
assetmanager.SetResourceResolutionLoggingEnabled(true);
- assetmanager.SetConfiguration(desired_config);
- assetmanager.SetApkAssets({overlayable_assets_.get()});
+ assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetApkAssets({overlayable_assets_});
const auto map = assetmanager.GetOverlayableMapForPackage(0x7f);
ASSERT_NE(nullptr, map);
@@ -838,4 +834,26 @@ TEST_F(AssetManager2Test, GetOverlayablesToString) {
std::string::npos);
}
+TEST_F(AssetManager2Test, GetApkAssets) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({overlayable_assets_, overlay_assets_, lib_one_assets_});
+
+ ASSERT_EQ(3, assetmanager.GetApkAssetsCount());
+ EXPECT_EQ(1, overlayable_assets_->getStrongCount());
+ EXPECT_EQ(1, overlay_assets_->getStrongCount());
+ EXPECT_EQ(1, lib_one_assets_->getStrongCount());
+
+ {
+ auto op = assetmanager.StartOperation();
+ ASSERT_EQ(overlayable_assets_, assetmanager.GetApkAssets(0));
+ ASSERT_EQ(overlay_assets_, assetmanager.GetApkAssets(1));
+ EXPECT_EQ(2, overlayable_assets_->getStrongCount());
+ EXPECT_EQ(2, overlay_assets_->getStrongCount());
+ EXPECT_EQ(1, lib_one_assets_->getStrongCount());
+ }
+ EXPECT_EQ(1, overlayable_assets_->getStrongCount());
+ EXPECT_EQ(1, overlay_assets_->getStrongCount());
+ EXPECT_EQ(1, lib_one_assets_->getStrongCount());
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_bench.cpp b/libs/androidfw/tests/AttributeResolution_bench.cpp
index 1c89c61c8f78..384f4a78b36d 100644
--- a/libs/androidfw/tests/AttributeResolution_bench.cpp
+++ b/libs/androidfw/tests/AttributeResolution_bench.cpp
@@ -36,15 +36,14 @@ constexpr const static char* kFrameworkPath = "/system/framework/framework-res.a
constexpr const static uint32_t Theme_Material_Light = 0x01030237u;
static void BM_ApplyStyle(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> styles_apk =
- ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+ auto styles_apk = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
if (styles_apk == nullptr) {
state.SkipWithError("failed to load assets");
return;
}
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({styles_apk.get()});
+ assetmanager.SetApkAssets({styles_apk});
std::unique_ptr<Asset> asset =
assetmanager.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
@@ -80,21 +79,20 @@ static void BM_ApplyStyle(benchmark::State& state) {
BENCHMARK(BM_ApplyStyle);
static void BM_ApplyStyleFramework(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> framework_apk = ApkAssets::Load(kFrameworkPath);
+ auto framework_apk = ApkAssets::Load(kFrameworkPath);
if (framework_apk == nullptr) {
state.SkipWithError("failed to load framework assets");
return;
}
- std::unique_ptr<const ApkAssets> basic_apk =
- ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+ auto basic_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
if (basic_apk == nullptr) {
state.SkipWithError("failed to load assets");
return;
}
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({framework_apk.get(), basic_apk.get()});
+ assetmanager.SetApkAssets({framework_apk, basic_apk});
ResTable_config device_config;
memset(&device_config, 0, sizeof(device_config));
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index bb9129ad01c8..329830fa47b2 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -36,11 +36,11 @@ class AttributeResolutionTest : public ::testing::Test {
virtual void SetUp() override {
styles_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
ASSERT_NE(nullptr, styles_assets_);
- assetmanager_.SetApkAssets({styles_assets_.get()});
+ assetmanager_.SetApkAssets({styles_assets_});
}
protected:
- std::unique_ptr<const ApkAssets> styles_assets_;
+ AssetManager2::ApkAssetsPtr styles_assets_;
AssetManager2 assetmanager_;
};
@@ -69,7 +69,7 @@ TEST(AttributeResolutionLibraryTest, ApplyStyleWithDefaultStyleResId) {
AssetManager2 assetmanager;
auto apk_assets = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk", PROPERTY_DYNAMIC);
ASSERT_NE(nullptr, apk_assets);
- assetmanager.SetApkAssets({apk_assets.get()});
+ assetmanager.SetApkAssets({apk_assets});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index 0fa0573bcbb8..8b883f4ed1df 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -53,22 +53,20 @@ void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTab
void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config,
uint32_t resid, benchmark::State& state) {
- std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
- std::vector<const ApkAssets*> apk_assets_ptrs;
+ std::vector<AssetManager2::ApkAssetsPtr> apk_assets;
for (const std::string& path : paths) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
+ auto apk = ApkAssets::Load(path);
if (apk == nullptr) {
state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str());
return;
}
- apk_assets_ptrs.push_back(apk.get());
apk_assets.push_back(std::move(apk));
}
AssetManager2 assetmanager;
- assetmanager.SetApkAssets(apk_assets_ptrs);
+ assetmanager.SetApkAssets(apk_assets);
if (config != nullptr) {
- assetmanager.SetConfiguration(*config);
+ assetmanager.SetConfigurations({*config});
}
while (state.KeepRunning()) {
diff --git a/libs/androidfw/tests/Generic_bench.cpp b/libs/androidfw/tests/Generic_bench.cpp
new file mode 100644
index 000000000000..4c978e889f83
--- /dev/null
+++ b/libs/androidfw/tests/Generic_bench.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <stdint.h>
+
+#include <map>
+#include <unordered_map>
+
+#include "benchmark/benchmark.h"
+
+namespace android {
+
+template <class Map = std::unordered_map<uint32_t, std::vector<uint32_t>>>
+static Map prepare_map() {
+ Map map;
+ std::vector<uint32_t> vec;
+ for (int i = 0; i < 1000; ++i) {
+ map.emplace(i, vec);
+ }
+ return map;
+}
+
+static void BM_hashmap_emplace_same(benchmark::State& state) {
+ auto map = prepare_map<>();
+ auto val = map.size() - 1;
+ std::vector<uint32_t> vec;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.emplace(val, vec));
+ }
+}
+BENCHMARK(BM_hashmap_emplace_same);
+static void BM_hashmap_try_emplace_same(benchmark::State& state) {
+ auto map = prepare_map();
+ auto val = map.size() - 1;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.try_emplace(val));
+ }
+}
+BENCHMARK(BM_hashmap_try_emplace_same);
+static void BM_hashmap_find(benchmark::State& state) {
+ auto map = prepare_map<>();
+ auto val = map.size() - 1;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.find(val));
+ }
+}
+BENCHMARK(BM_hashmap_find);
+
+static void BM_hashmap_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map<>();
+ std::vector<uint32_t> vec;
+ auto i = map.size();
+ for (auto&& _ : state) {
+ map.emplace(i++, vec);
+ }
+}
+BENCHMARK(BM_hashmap_emplace_diff);
+static void BM_hashmap_try_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map();
+ auto i = map.size();
+ for (auto&& _ : state) {
+ map.try_emplace(i++);
+ }
+}
+BENCHMARK(BM_hashmap_try_emplace_diff);
+static void BM_hashmap_find_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map<>();
+ std::vector<uint32_t> vec;
+ auto i = map.size();
+ for (auto&& _ : state) {
+ if (map.find(i++) == map.end()) {
+ map.emplace(i - 1, vec);
+ }
+ }
+}
+BENCHMARK(BM_hashmap_find_emplace_diff);
+
+static void BM_treemap_emplace_same(benchmark::State& state) {
+ auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
+ auto val = map.size() - 1;
+ std::vector<uint32_t> vec;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.emplace(val, vec));
+ }
+}
+BENCHMARK(BM_treemap_emplace_same);
+static void BM_treemap_try_emplace_same(benchmark::State& state) {
+ auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
+ auto val = map.size() - 1;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.try_emplace(val));
+ }
+}
+BENCHMARK(BM_treemap_try_emplace_same);
+static void BM_treemap_find(benchmark::State& state) {
+ auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
+ auto val = map.size() - 1;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.find(val));
+ }
+}
+BENCHMARK(BM_treemap_find);
+
+static void BM_treemap_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
+ std::vector<uint32_t> vec;
+ auto i = map.size();
+ for (auto&& _ : state) {
+ map.emplace(i++, vec);
+ }
+}
+BENCHMARK(BM_treemap_emplace_diff);
+static void BM_treemap_try_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map();
+ auto i = map.size();
+ for (auto&& _ : state) {
+ map.try_emplace(i++);
+ }
+}
+BENCHMARK(BM_treemap_try_emplace_diff);
+static void BM_treemap_find_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map();
+ std::vector<uint32_t> vec;
+ auto i = map.size();
+ for (auto&& _ : state) {
+ if (map.find(i++) == map.end()) {
+ map.emplace(i - 1, vec);
+ }
+ }
+}
+BENCHMARK(BM_treemap_find_emplace_diff);
+
+} // namespace android \ No newline at end of file
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index b43491548e2b..60aa7d88925d 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -59,15 +59,16 @@ class IdmapTest : public ::testing::Test {
protected:
std::string original_path;
- std::unique_ptr<const ApkAssets> system_assets_;
- std::unique_ptr<const ApkAssets> overlay_assets_;
- std::unique_ptr<const ApkAssets> overlayable_assets_;
+ AssetManager2::ApkAssetsPtr system_assets_;
+ AssetManager2::ApkAssetsPtr overlay_assets_;
+ AssetManager2::ApkAssetsPtr overlayable_assets_;
};
std::string GetStringFromApkAssets(const AssetManager2& asset_manager,
const AssetManager2::SelectedValue& value) {
- auto assets = asset_manager.GetApkAssets();
- const ResStringPool* string_pool = assets[value.cookie]->GetLoadedArsc()->GetStringPool();
+ auto op = asset_manager.StartOperation();
+ const ResStringPool* string_pool =
+ asset_manager.GetApkAssets(value.cookie)->GetLoadedArsc()->GetStringPool();
return GetStringFromPool(string_pool, value.data);
}
@@ -75,8 +76,7 @@ std::string GetStringFromApkAssets(const AssetManager2& asset_manager,
TEST_F(IdmapTest, OverlayOverridesResourceValue) {
AssetManager2 asset_manager;
- asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
- overlay_assets_.get()});
+ asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
auto value = asset_manager.GetResource(overlayable::R::string::overlayable5);
ASSERT_TRUE(value.has_value());
@@ -87,8 +87,7 @@ TEST_F(IdmapTest, OverlayOverridesResourceValue) {
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingDifferentPackage) {
AssetManager2 asset_manager;
- asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
- overlay_assets_.get()});
+ asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
auto value = asset_manager.GetResource(overlayable::R::string::overlayable10);
ASSERT_TRUE(value.has_value());
@@ -99,8 +98,7 @@ TEST_F(IdmapTest, OverlayOverridesResourceValueUsingDifferentPackage) {
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInternalResource) {
AssetManager2 asset_manager;
- asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
- overlay_assets_.get()});
+ asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
auto value = asset_manager.GetResource(overlayable::R::string::overlayable8);
ASSERT_TRUE(value.has_value());
@@ -111,8 +109,7 @@ TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInternalResource) {
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineInteger) {
AssetManager2 asset_manager;
- asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
- overlay_assets_.get()});
+ asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
auto value = asset_manager.GetResource(overlayable::R::integer::config_integer);
ASSERT_TRUE(value.has_value());
@@ -123,8 +120,7 @@ TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineInteger) {
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineString) {
AssetManager2 asset_manager;
- asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
- overlay_assets_.get()});
+ asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
ASSERT_TRUE(value.has_value());
@@ -135,8 +131,7 @@ TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineString) {
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingOverlayingResource) {
AssetManager2 asset_manager;
- asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
- overlay_assets_.get()});
+ asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
auto value = asset_manager.GetResource(overlayable::R::string::overlayable9);
ASSERT_TRUE(value.has_value());
@@ -147,8 +142,7 @@ TEST_F(IdmapTest, OverlayOverridesResourceValueUsingOverlayingResource) {
TEST_F(IdmapTest, OverlayOverridesXmlParser) {
AssetManager2 asset_manager;
- asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
- overlay_assets_.get()});
+ asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
auto value = asset_manager.GetResource(overlayable::R::layout::hello_view);
ASSERT_TRUE(value.has_value());
@@ -186,8 +180,7 @@ TEST_F(IdmapTest, OverlayOverridesXmlParser) {
TEST_F(IdmapTest, OverlaidResourceHasSameName) {
AssetManager2 asset_manager;
- asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
- overlay_assets_.get()});
+ asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
auto name = asset_manager.GetResourceName(overlayable::R::string::overlayable9);
ASSERT_TRUE(name.has_value());
@@ -203,8 +196,7 @@ TEST_F(IdmapTest, OverlayLoaderInterop) {
auto loader_assets = ApkAssets::LoadTable(std::move(asset), EmptyAssetsProvider::Create(),
PROPERTY_LOADER);
AssetManager2 asset_manager;
- asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(),
- overlay_assets_.get()});
+ asset_manager.SetApkAssets({overlayable_assets_, loader_assets, overlay_assets_});
auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
ASSERT_TRUE(value.has_value());
diff --git a/libs/androidfw/tests/Theme_bench.cpp b/libs/androidfw/tests/Theme_bench.cpp
index f3d60bbe4f15..dfbb5a76dec6 100644
--- a/libs/androidfw/tests/Theme_bench.cpp
+++ b/libs/androidfw/tests/Theme_bench.cpp
@@ -28,14 +28,14 @@ constexpr const static uint32_t kStyleId = 0x01030237u; // android:style/Theme.
constexpr const static uint32_t kAttrId = 0x01010030u; // android:attr/colorForeground
static void BM_ThemeApplyStyleFramework(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+ auto apk = ApkAssets::Load(kFrameworkPath);
if (apk == nullptr) {
state.SkipWithError("Failed to load assets");
return;
}
AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
+ assets.SetApkAssets({apk});
while (state.KeepRunning()) {
auto theme = assets.NewTheme();
@@ -62,10 +62,10 @@ static void BM_ThemeApplyStyleFrameworkOld(benchmark::State& state) {
BENCHMARK(BM_ThemeApplyStyleFrameworkOld);
static void BM_ThemeGetAttribute(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+ auto apk = ApkAssets::Load(kFrameworkPath);
AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
+ assets.SetApkAssets({apk});
auto theme = assets.NewTheme();
theme->ApplyStyle(kStyleId, false /* force */);
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 77114f273d3d..181d1411fb91 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -53,16 +53,16 @@ class ThemeTest : public ::testing::Test {
}
protected:
- std::unique_ptr<const ApkAssets> system_assets_;
- std::unique_ptr<const ApkAssets> style_assets_;
- std::unique_ptr<const ApkAssets> libclient_assets_;
- std::unique_ptr<const ApkAssets> lib_one_assets_;
- std::unique_ptr<const ApkAssets> lib_two_assets_;
+ AssetManager2::ApkAssetsPtr system_assets_;
+ AssetManager2::ApkAssetsPtr style_assets_;
+ AssetManager2::ApkAssetsPtr libclient_assets_;
+ AssetManager2::ApkAssetsPtr lib_one_assets_;
+ AssetManager2::ApkAssetsPtr lib_two_assets_;
};
TEST_F(ThemeTest, EmptyTheme) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({style_assets_.get()});
+ assetmanager.SetApkAssets({style_assets_});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
EXPECT_EQ(0u, theme->GetChangingConfigurations());
@@ -72,7 +72,7 @@ TEST_F(ThemeTest, EmptyTheme) {
TEST_F(ThemeTest, SingleThemeNoParent) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({style_assets_.get()});
+ assetmanager.SetApkAssets({style_assets_});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleOne).has_value());
@@ -92,7 +92,7 @@ TEST_F(ThemeTest, SingleThemeNoParent) {
TEST_F(ThemeTest, SingleThemeWithParent) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({style_assets_.get()});
+ assetmanager.SetApkAssets({style_assets_});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
@@ -121,7 +121,7 @@ TEST_F(ThemeTest, SingleThemeWithParent) {
TEST_F(ThemeTest, TryToUseBadResourceId) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({style_assets_.get()});
+ assetmanager.SetApkAssets({style_assets_});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
@@ -130,7 +130,7 @@ TEST_F(ThemeTest, TryToUseBadResourceId) {
TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({style_assets_.get()});
+ assetmanager.SetApkAssets({style_assets_});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
@@ -160,7 +160,7 @@ TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({style_assets_.get()});
+ assetmanager.SetApkAssets({style_assets_});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
@@ -190,8 +190,7 @@ TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
TEST_F(ThemeTest, ResolveDynamicAttributesAndReferencesToSharedLibrary) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets(
- {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
+ assetmanager.SetApkAssets({lib_two_assets_, lib_one_assets_, libclient_assets_});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
ASSERT_TRUE(theme->ApplyStyle(libclient::R::style::Theme, false /*force*/).has_value());
@@ -216,7 +215,7 @@ TEST_F(ThemeTest, ResolveDynamicAttributesAndReferencesToSharedLibrary) {
TEST_F(ThemeTest, CopyThemeSameAssetManager) {
AssetManager2 assetmanager;
- assetmanager.SetApkAssets({style_assets_.get()});
+ assetmanager.SetApkAssets({style_assets_});
std::unique_ptr<Theme> theme_one = assetmanager.NewTheme();
ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne).has_value());
@@ -253,15 +252,15 @@ TEST_F(ThemeTest, CopyThemeSameAssetManager) {
TEST_F(ThemeTest, ThemeRebase) {
AssetManager2 am;
- am.SetApkAssets({style_assets_.get()});
+ am.SetApkAssets({style_assets_});
AssetManager2 am_night;
- am_night.SetApkAssets({style_assets_.get()});
+ am_night.SetApkAssets({style_assets_});
ResTable_config night{};
night.uiMode = ResTable_config::UI_MODE_NIGHT_YES;
night.version = 8u;
- am_night.SetConfiguration(night);
+ am_night.SetConfigurations({night});
auto theme = am.NewTheme();
{
@@ -327,12 +326,11 @@ TEST_F(ThemeTest, ThemeRebase) {
TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
AssetManager2 assetmanager_dst;
- assetmanager_dst.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(),
- libclient_assets_.get()});
+ assetmanager_dst.SetApkAssets(
+ {system_assets_, lib_one_assets_, style_assets_, libclient_assets_});
AssetManager2 assetmanager_src;
- assetmanager_src.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(),
- style_assets_.get()});
+ assetmanager_src.SetApkAssets({system_assets_, lib_two_assets_, lib_one_assets_, style_assets_});
auto theme_dst = assetmanager_dst.NewTheme();
ASSERT_TRUE(theme_dst->ApplyStyle(app::R::style::StyleOne).has_value());
@@ -376,10 +374,10 @@ TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
TEST_F(ThemeTest, CopyNonReferencesWhenPackagesDiffer) {
AssetManager2 assetmanager_dst;
- assetmanager_dst.SetApkAssets({system_assets_.get()});
+ assetmanager_dst.SetApkAssets({system_assets_});
AssetManager2 assetmanager_src;
- assetmanager_src.SetApkAssets({system_assets_.get(), style_assets_.get()});
+ assetmanager_src.SetApkAssets({system_assets_, style_assets_});
auto theme_dst = assetmanager_dst.NewTheme();
auto theme_src = assetmanager_src.NewTheme();
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt
index 96bfb78eff0d..d1dd8df81a3e 100644
--- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt
@@ -23,6 +23,7 @@ import android.content.ComponentName
import android.util.Log
import com.android.dream.lowlight.dagger.LowLightDreamModule
import com.android.dream.lowlight.dagger.qualifiers.Application
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.TimeoutCancellationException
@@ -103,6 +104,11 @@ class LowLightDreamManager @Inject constructor(
)
} catch (ex: TimeoutCancellationException) {
Log.e(TAG, "timed out while waiting for low light animation", ex)
+ } catch (ex: CancellationException) {
+ Log.w(TAG, "low light transition animation cancelled")
+ // Catch the cancellation so that we still set the system dream component if the
+ // animation is cancelled, such as by a user tapping to wake as the transition to
+ // low light happens.
}
dreamManager.setSystemDreamComponent(
if (shouldEnterLowLight) lowLightDreamComponent else null
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
index 473603002b21..de1aee598667 100644
--- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
@@ -110,15 +110,5 @@ class LowLightTransitionCoordinator @Inject constructor() {
}
}
animator.addListener(listener)
- continuation.invokeOnCancellation {
- try {
- animator.removeListener(listener)
- animator.cancel()
- } catch (exception: IndexOutOfBoundsException) {
- // TODO(b/285666217): remove this try/catch once a proper fix is implemented.
- // Cancelling the animator can cause an exception since we may be removing a
- // listener during the cancellation. See b/285666217 for more details.
- }
- }
}
}
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/util/TruncatedInterpolator.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/util/TruncatedInterpolator.kt
new file mode 100644
index 000000000000..f69c84dafbb2
--- /dev/null
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/util/TruncatedInterpolator.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 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.dream.lowlight.util
+
+import android.view.animation.Interpolator
+
+/**
+ * Interpolator wrapper that shortens another interpolator from its original duration to a portion
+ * of that duration.
+ *
+ * For example, an `originalDuration` of 1000 and a `newDuration` of 200 results in an animation
+ * that when played for 200ms is the exact same as the first 200ms of a 1000ms animation if using
+ * the original interpolator.
+ *
+ * This is useful for the transition between the user dream and the low light clock as some
+ * animations are defined in the spec to be longer than the total duration of the animation. For
+ * example, the low light clock exit translation animation is defined to last >1s while the actual
+ * fade out of the low light clock is only 250ms, meaning the clock isn't visible anymore after
+ * 250ms.
+ *
+ * Since the dream framework currently only allows one dream to be visible and running, we use this
+ * interpolator to play just the first 250ms of the translation animation. Simply reducing the
+ * duration of the animation would result in the text exiting much faster than intended, so a custom
+ * interpolator is needed.
+ */
+class TruncatedInterpolator(
+ private val baseInterpolator: Interpolator,
+ originalDuration: Float,
+ newDuration: Float
+) : Interpolator {
+ private val scaleFactor: Float
+
+ init {
+ scaleFactor = newDuration / originalDuration
+ }
+
+ override fun getInterpolation(input: Float): Float {
+ return baseInterpolator.getInterpolation(input * scaleFactor)
+ }
+}
diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp
index 2d79090cd7d4..64b53cbb5c5a 100644
--- a/libs/dream/lowlight/tests/Android.bp
+++ b/libs/dream/lowlight/tests/Android.bp
@@ -27,6 +27,7 @@ android_test {
"androidx.test.runner",
"androidx.test.rules",
"androidx.test.ext.junit",
+ "animationlib",
"frameworks-base-testutils",
"junit",
"kotlinx_coroutines_test",
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt
index 2a886bc31788..de84adb2e5c2 100644
--- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt
@@ -152,6 +152,21 @@ class LowLightDreamManagerTest {
verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT)
}
+ @Test
+ fun setAmbientLightMode_animationCancelled_SetsSystemDream() = testScope.runTest {
+ mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
+ runCurrent()
+ cancelEnterAnimations()
+ runCurrent()
+ // Animation never finishes, but we should still set the system dream
+ verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT)
+ }
+
+ private fun cancelEnterAnimations() {
+ val listener = withArgCaptor { verify(mEnterAnimator).addListener(capture()) }
+ listener.onAnimationCancel(mEnterAnimator)
+ }
+
private fun completeEnterAnimations() {
val listener = withArgCaptor { verify(mEnterAnimator).addListener(capture()) }
listener.onAnimationEnd(mEnterAnimator)
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt
index 4c526a6ac69d..9ae304f9763a 100644
--- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt
@@ -158,26 +158,6 @@ class LowLightTransitionCoordinatorTest {
assertThat(job.isCancelled).isTrue()
}
- @Test
- fun shouldCancelAnimatorWhenJobCancelled() = testScope.runTest {
- whenever(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator)
- val coordinator = LowLightTransitionCoordinator()
- coordinator.setLowLightEnterListener(mEnterListener)
- val job = launch {
- coordinator.waitForLowLightTransitionAnimation(timeout = TIMEOUT, entering = true)
- }
- runCurrent()
- // Animator listener is added and the runnable is not run yet.
- verify(mAnimator).addListener(mAnimatorListenerCaptor.capture())
- verify(mAnimator, never()).cancel()
- assertThat(job.isCompleted).isFalse()
-
- job.cancel()
- // We should have removed the listener and cancelled the animator
- verify(mAnimator).removeListener(mAnimatorListenerCaptor.value)
- verify(mAnimator).cancel()
- }
-
companion object {
private val TIMEOUT = 1.toDuration(DurationUnit.SECONDS)
}
diff --git a/libs/dream/lowlight/tests/src/com/android/dream/lowlight/util/TruncatedInterpolatorTest.kt b/libs/dream/lowlight/tests/src/com/android/dream/lowlight/util/TruncatedInterpolatorTest.kt
new file mode 100644
index 000000000000..190f02e97136
--- /dev/null
+++ b/libs/dream/lowlight/tests/src/com/android/dream/lowlight/util/TruncatedInterpolatorTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 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.dream.lowlight.util
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class TruncatedInterpolatorTest {
+ @Test
+ fun truncatedInterpolator_matchesRegularInterpolator() {
+ val originalInterpolator = Interpolators.EMPHASIZED
+ val truncatedInterpolator =
+ TruncatedInterpolator(originalInterpolator, ORIGINAL_DURATION_MS, NEW_DURATION_MS)
+
+ // Both interpolators should start at the same value.
+ var animationPercent = 0f
+ Truth.assertThat(truncatedInterpolator.getInterpolation(animationPercent))
+ .isEqualTo(originalInterpolator.getInterpolation(animationPercent))
+
+ animationPercent = 1f
+ Truth.assertThat(truncatedInterpolator.getInterpolation(animationPercent))
+ .isEqualTo(originalInterpolator.getInterpolation(animationPercent * DURATION_RATIO))
+
+ animationPercent = 0.25f
+ Truth.assertThat(truncatedInterpolator.getInterpolation(animationPercent))
+ .isEqualTo(originalInterpolator.getInterpolation(animationPercent * DURATION_RATIO))
+ }
+
+ companion object {
+ private const val ORIGINAL_DURATION_MS: Float = 1000f
+ private const val NEW_DURATION_MS: Float = 200f
+ private const val DURATION_RATIO: Float = NEW_DURATION_MS / ORIGINAL_DURATION_MS
+ }
+}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index db581471e2ca..b5e6f94af022 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -514,6 +514,7 @@ cc_defaults {
"canvas/CanvasOpRasterizer.cpp",
"effects/StretchEffect.cpp",
"effects/GainmapRenderer.cpp",
+ "pipeline/skia/BackdropFilterDrawable.cpp",
"pipeline/skia/HolePunch.cpp",
"pipeline/skia/SkiaDisplayList.cpp",
"pipeline/skia/SkiaRecordingCanvas.cpp",
diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp
index b656b6ac8204..d237cc261b53 100644
--- a/libs/hwui/AutoBackendTextureRelease.cpp
+++ b/libs/hwui/AutoBackendTextureRelease.cpp
@@ -16,6 +16,11 @@
#include "AutoBackendTextureRelease.h"
+#include <SkImage.h>
+#include <include/gpu/ganesh/SkImageGanesh.h>
+#include <include/gpu/GrBackendSurfaceMutableState.h>
+#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/GrBackendSurface.h>
#include "renderthread/RenderThread.h"
#include "utils/Color.h"
#include "utils/PaintUtils.h"
@@ -70,7 +75,7 @@ void AutoBackendTextureRelease::unref(bool releaseImage) {
// releaseProc is invoked by SkImage, when texture is no longer in use.
// "releaseContext" contains an "AutoBackendTextureRelease*".
-static void releaseProc(SkImage::ReleaseContext releaseContext) {
+static void releaseProc(SkImages::ReleaseContext releaseContext) {
AutoBackendTextureRelease* textureRelease =
reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
textureRelease->unref(false);
@@ -83,10 +88,10 @@ void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer,
AHardwareBuffer_describe(buffer, &desc);
SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
// The following ref will be counteracted by Skia calling releaseProc, either during
- // MakeFromTexture if there is a failure, or later when SkImage is discarded. It must
- // be called before MakeFromTexture, otherwise Skia may remove HWUI's ref on failure.
+ // BorrowTextureFrom if there is a failure, or later when SkImage is discarded. It must
+ // be called before BorrowTextureFrom, otherwise Skia may remove HWUI's ref on failure.
ref();
- mImage = SkImage::MakeFromTexture(
+ mImage = SkImages::BorrowTextureFrom(
context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType,
uirenderer::DataSpaceToColorSpace(dataspace), releaseProc, this);
}
diff --git a/libs/hwui/ColorFilter.h b/libs/hwui/ColorFilter.h
new file mode 100644
index 000000000000..1a5b938d6eed
--- /dev/null
+++ b/libs/hwui/ColorFilter.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#ifndef COLORFILTER_H_
+#define COLORFILTER_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "GraphicsJNI.h"
+#include "SkColorFilter.h"
+#include "SkiaWrapper.h"
+
+namespace android {
+namespace uirenderer {
+
+class ColorFilter : public SkiaWrapper<SkColorFilter> {
+public:
+ static ColorFilter* fromJava(jlong handle) { return reinterpret_cast<ColorFilter*>(handle); }
+
+protected:
+ ColorFilter() = default;
+};
+
+class BlendModeColorFilter : public ColorFilter {
+public:
+ BlendModeColorFilter(SkColor color, SkBlendMode mode) : mColor(color), mMode(mode) {}
+
+private:
+ sk_sp<SkColorFilter> createInstance() override { return SkColorFilters::Blend(mColor, mMode); }
+
+private:
+ const SkColor mColor;
+ const SkBlendMode mMode;
+};
+
+class LightingFilter : public ColorFilter {
+public:
+ LightingFilter(SkColor mul, SkColor add) : mMul(mul), mAdd(add) {}
+
+ void setMul(SkColor mul) {
+ mMul = mul;
+ discardInstance();
+ }
+
+ void setAdd(SkColor add) {
+ mAdd = add;
+ discardInstance();
+ }
+
+private:
+ sk_sp<SkColorFilter> createInstance() override { return SkColorFilters::Lighting(mMul, mAdd); }
+
+private:
+ SkColor mMul;
+ SkColor mAdd;
+};
+
+class ColorMatrixColorFilter : public ColorFilter {
+public:
+ ColorMatrixColorFilter(std::vector<float>&& matrix) : mMatrix(std::move(matrix)) {}
+
+ void setMatrix(std::vector<float>&& matrix) {
+ mMatrix = std::move(matrix);
+ discardInstance();
+ }
+
+private:
+ sk_sp<SkColorFilter> createInstance() override {
+ return SkColorFilters::Matrix(mMatrix.data());
+ }
+
+private:
+ std::vector<float> mMatrix;
+};
+
+} // namespace uirenderer
+} // namespace android
+
+#endif // COLORFILTER_H_
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index a18ba1c633b9..d21f07efe36a 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-X(Flush)
X(Save)
X(Restore)
X(SaveLayer)
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index b7e99994355c..19a1dfa91539 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -25,6 +25,7 @@
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkImage.h>
+#include <SkImageAndroid.h>
#include <SkImageInfo.h>
#include <SkRefCnt.h>
#include <gui/TraceUtils.h>
@@ -262,7 +263,8 @@ private:
}
sk_sp<SkImage> image =
- SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
+ SkImages::TextureFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(),
+ ahb);
mGrContext->submit(true);
uploadSucceeded = (image.get() != nullptr);
diff --git a/libs/hwui/MemoryPolicy.cpp b/libs/hwui/MemoryPolicy.cpp
index ca1312e75f4c..21f4ca79b68c 100644
--- a/libs/hwui/MemoryPolicy.cpp
+++ b/libs/hwui/MemoryPolicy.cpp
@@ -28,7 +28,10 @@ namespace android::uirenderer {
constexpr static MemoryPolicy sDefaultMemoryPolicy;
constexpr static MemoryPolicy sPersistentOrSystemPolicy{
.contextTimeout = 10_s,
+ .minimumResourceRetention = 1_s,
+ .maximumResourceRetention = 10_s,
.useAlternativeUiHidden = true,
+ .purgeScratchOnly = false,
};
constexpr static MemoryPolicy sLowRamPolicy{
.useAlternativeUiHidden = true,
diff --git a/libs/hwui/MemoryPolicy.h b/libs/hwui/MemoryPolicy.h
index 347daf34f52a..e10dda990dec 100644
--- a/libs/hwui/MemoryPolicy.h
+++ b/libs/hwui/MemoryPolicy.h
@@ -53,6 +53,8 @@ struct MemoryPolicy {
// The minimum amount of time to hold onto items in the resource cache
// The actual time used will be the max of this & when frames were actually rendered
nsecs_t minimumResourceRetention = 10_s;
+ // The maximum amount of time to hold onto items in the resource cache
+ nsecs_t maximumResourceRetention = 100000_s;
// If false, use only TRIM_UI_HIDDEN to drive background cache limits;
// If true, use all signals (such as all contexts are stopped) to drive the limits
bool useAlternativeUiHidden = true;
diff --git a/libs/hwui/Mesh.h b/libs/hwui/Mesh.h
index 13e3c8e7bf77..764d1efcc8f4 100644
--- a/libs/hwui/Mesh.h
+++ b/libs/hwui/Mesh.h
@@ -19,6 +19,7 @@
#include <GrDirectContext.h>
#include <SkMesh.h>
+#include <include/gpu/ganesh/SkMeshGanesh.h>
#include <jni.h>
#include <log/log.h>
@@ -143,14 +144,26 @@ public:
}
if (mIsDirty || genId != mGenerationId) {
- auto vb = SkMesh::MakeVertexBuffer(
- context, reinterpret_cast<const void*>(mVertexBufferData.data()),
- mVertexBufferData.size());
+ auto vertexData = reinterpret_cast<const void*>(mVertexBufferData.data());
+#ifdef __ANDROID__
+ auto vb = SkMeshes::MakeVertexBuffer(context,
+ vertexData,
+ mVertexBufferData.size());
+#else
+ auto vb = SkMeshes::MakeVertexBuffer(vertexData,
+ mVertexBufferData.size());
+#endif
auto meshMode = SkMesh::Mode(mMode);
if (!mIndexBufferData.empty()) {
- auto ib = SkMesh::MakeIndexBuffer(
- context, reinterpret_cast<const void*>(mIndexBufferData.data()),
- mIndexBufferData.size());
+ auto indexData = reinterpret_cast<const void*>(mIndexBufferData.data());
+#ifdef __ANDROID__
+ auto ib = SkMeshes::MakeIndexBuffer(context,
+ indexData,
+ mIndexBufferData.size());
+#else
+ auto ib = SkMeshes::MakeIndexBuffer(indexData,
+ mIndexBufferData.size());
+#endif
mMesh = SkMesh::MakeIndexed(mMeshSpec, meshMode, vb, mVertexCount, mVertexOffset,
ib, mIndexCount, mIndexOffset, mBuilder->fUniforms,
mBounds)
diff --git a/libs/hwui/OWNERS b/libs/hwui/OWNERS
index bb93e66968be..6ca991d8b294 100644
--- a/libs/hwui/OWNERS
+++ b/libs/hwui/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1075005
+
alecmouri@google.com
djsollen@google.com
jreck@google.com
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 06aed63d8def..5e5eb4a51b35 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -20,7 +20,7 @@
#ifdef __ANDROID__
#include "HWUIProperties.sysprop.h"
#endif
-#include "SkTraceEventCommon.h"
+#include "src/core/SkTraceEventCommon.h"
#include <algorithm>
#include <cstdlib>
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 045de35c1d97..afe4c3896ed2 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -21,6 +21,7 @@
#include <SkCanvas.h>
#include <SkColorSpace.h>
#include <SkImage.h>
+#include <SkImageAndroid.h>
#include <SkImageInfo.h>
#include <SkMatrix.h>
#include <SkPaint.h>
@@ -29,6 +30,7 @@
#include <SkSamplingOptions.h>
#include <SkSurface.h>
#include "include/gpu/GpuTypes.h" // from Skia
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <gui/TraceUtils.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <shaders/shaders.h>
@@ -108,7 +110,8 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy
sk_sp<SkColorSpace> colorSpace =
DataSpaceToColorSpace(static_cast<android_dataspace>(dataspace));
sk_sp<SkImage> image =
- SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace);
+ SkImages::DeferredFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType,
+ colorSpace);
if (!image.get()) {
return request->onCopyFinished(CopyResult::UnknownError);
@@ -171,16 +174,16 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy
SkBitmap skBitmap = request->getDestinationBitmap(srcRect.width(), srcRect.height());
SkBitmap* bitmap = &skBitmap;
sk_sp<SkSurface> tmpSurface =
- SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), skgpu::Budgeted::kYes,
- bitmap->info(), 0, kTopLeft_GrSurfaceOrigin, nullptr);
+ SkSurfaces::RenderTarget(mRenderThread.getGrContext(), skgpu::Budgeted::kYes,
+ bitmap->info(), 0, kTopLeft_GrSurfaceOrigin, nullptr);
// if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we
// attempt to do the intermediate rendering step in 8888
if (!tmpSurface.get()) {
SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
- tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- skgpu::Budgeted::kYes,
- tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
+ tmpSurface = SkSurfaces::RenderTarget(mRenderThread.getGrContext(),
+ skgpu::Budgeted::kYes,
+ tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
if (!tmpSurface.get()) {
ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap");
return request->onCopyFinished(CopyResult::UnknownError);
@@ -346,19 +349,19 @@ bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect*
* a scaling issue (b/62262733) that was encountered when sampling from an EGLImage into a
* software buffer.
*/
- sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- skgpu::Budgeted::kYes,
- bitmap->info(),
- 0,
- kTopLeft_GrSurfaceOrigin, nullptr);
+ sk_sp<SkSurface> tmpSurface = SkSurfaces::RenderTarget(mRenderThread.getGrContext(),
+ skgpu::Budgeted::kYes,
+ bitmap->info(),
+ 0,
+ kTopLeft_GrSurfaceOrigin, nullptr);
// if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we
// attempt to do the intermediate rendering step in 8888
if (!tmpSurface.get()) {
SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
- tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- skgpu::Budgeted::kYes,
- tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
+ tmpSurface = SkSurfaces::RenderTarget(mRenderThread.getGrContext(),
+ skgpu::Budgeted::kYes,
+ tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
if (!tmpSurface.get()) {
ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap");
return false;
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 924fbd659824..71f47e92e055 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -36,6 +36,7 @@
#include "SkImageFilter.h"
#include "SkImageInfo.h"
#include "SkLatticeIter.h"
+#include "SkMesh.h"
#include "SkPaint.h"
#include "SkPicture.h"
#include "SkRRect.h"
@@ -49,6 +50,7 @@
#include "effects/GainmapRenderer.h"
#include "include/gpu/GpuTypes.h" // from Skia
#include "include/gpu/GrDirectContext.h"
+#include "include/gpu/ganesh/SkMeshGanesh.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/FunctorDrawable.h"
#ifdef __ANDROID__
@@ -107,11 +109,6 @@ struct Op {
};
static_assert(sizeof(Op) == 4, "");
-struct Flush final : Op {
- static const auto kType = Type::Flush;
- void draw(SkCanvas* c, const SkMatrix&) const { c->flush(); }
-};
-
struct Save final : Op {
static const auto kType = Type::Save;
void draw(SkCanvas* c, const SkMatrix&) const { c->save(); }
@@ -532,12 +529,13 @@ struct DrawSkMesh final : Op {
mutable bool isGpuBased;
mutable GrDirectContext::DirectContextID contextId;
void draw(SkCanvas* c, const SkMatrix&) const {
+#ifdef __ANDROID__
GrDirectContext* directContext = c->recordingContext()->asDirectContext();
GrDirectContext::DirectContextID id = directContext->directContextID();
if (!isGpuBased || contextId != id) {
sk_sp<SkMesh::VertexBuffer> vb =
- SkMesh::CopyVertexBuffer(directContext, cpuMesh.refVertexBuffer());
+ SkMeshes::CopyVertexBuffer(directContext, cpuMesh.refVertexBuffer());
if (!cpuMesh.indexBuffer()) {
gpuMesh = SkMesh::Make(cpuMesh.refSpec(), cpuMesh.mode(), vb, cpuMesh.vertexCount(),
cpuMesh.vertexOffset(), cpuMesh.refUniforms(),
@@ -545,7 +543,7 @@ struct DrawSkMesh final : Op {
.mesh;
} else {
sk_sp<SkMesh::IndexBuffer> ib =
- SkMesh::CopyIndexBuffer(directContext, cpuMesh.refIndexBuffer());
+ SkMeshes::CopyIndexBuffer(directContext, cpuMesh.refIndexBuffer());
gpuMesh = SkMesh::MakeIndexed(cpuMesh.refSpec(), cpuMesh.mode(), vb,
cpuMesh.vertexCount(), cpuMesh.vertexOffset(), ib,
cpuMesh.indexCount(), cpuMesh.indexOffset(),
@@ -558,6 +556,9 @@ struct DrawSkMesh final : Op {
}
c->drawMesh(gpuMesh, blender, paint);
+#else
+ c->drawMesh(cpuMesh, blender, paint);
+#endif
}
};
@@ -675,12 +676,11 @@ public:
// because the webview functor still doesn't respect the canvas clip stack.
const SkIRect deviceBounds = c->getDeviceClipBounds();
if (mLayerSurface == nullptr || c->imageInfo() != mLayerImageInfo) {
- GrRecordingContext* directContext = c->recordingContext();
mLayerImageInfo =
c->imageInfo().makeWH(deviceBounds.width(), deviceBounds.height());
- mLayerSurface = SkSurface::MakeRenderTarget(directContext, skgpu::Budgeted::kYes,
- mLayerImageInfo, 0,
- kTopLeft_GrSurfaceOrigin, nullptr);
+ // SkCanvas::makeSurface returns a new surface that will be GPU-backed if
+ // canvas was also.
+ mLayerSurface = c->makeSurface(mLayerImageInfo);
}
SkCanvas* layerCanvas = mLayerSurface->getCanvas();
@@ -752,10 +752,6 @@ inline void DisplayListData::map(const Fn fns[], Args... args) const {
}
}
-void DisplayListData::flush() {
- this->push<Flush>(0);
-}
-
void DisplayListData::save() {
this->push<Save>(0);
}
@@ -1047,10 +1043,6 @@ sk_sp<SkSurface> RecordingCanvas::onNewSurface(const SkImageInfo&, const SkSurfa
return nullptr;
}
-void RecordingCanvas::onFlush() {
- fDL->flush();
-}
-
void RecordingCanvas::willSave() {
mSaveCount++;
fDL->save();
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 1f4ba5d6d557..4f54ee286a56 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -127,8 +127,6 @@ public:
private:
friend class RecordingCanvas;
- void flush();
-
void save();
void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, SkCanvas::SaveLayerFlags);
void saveBehind(const SkRect*);
@@ -208,8 +206,6 @@ public:
void willRestore() override;
bool onDoSaveBehind(const SkRect*) override;
- void onFlush() override;
-
void didConcat44(const SkM44&) override;
void didSetM44(const SkM44&) override;
void didScale(SkScalar, SkScalar) override;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 1c39db3a31bb..1dd22cf43c5c 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -260,6 +260,12 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu
pushStagingDisplayListChanges(observer, info);
}
+ // always damageSelf when filtering backdrop content, or else the BackdropFilterDrawable will
+ // get a wrong snapshot of previous content.
+ if (mProperties.layerProperties().getBackdropImageFilter()) {
+ damageSelf(info);
+ }
+
if (mDisplayList) {
info.out.hasFunctors |= mDisplayList.hasFunctor();
mHasHolePunches = mDisplayList.hasHolePunches();
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 0589f136b666..c5371236b9cf 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -55,6 +55,12 @@ bool LayerProperties::setImageFilter(SkImageFilter* imageFilter) {
return true;
}
+bool LayerProperties::setBackdropImageFilter(SkImageFilter* imageFilter) {
+ if (mBackdropImageFilter.get() == imageFilter) return false;
+ mBackdropImageFilter = sk_ref_sp(imageFilter);
+ return true;
+}
+
bool LayerProperties::setFromPaint(const SkPaint* paint) {
bool changed = false;
changed |= setAlpha(static_cast<uint8_t>(PaintUtils::getAlphaDirect(paint)));
@@ -70,6 +76,7 @@ LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
setXferMode(other.xferMode());
setColorFilter(other.getColorFilter());
setImageFilter(other.getImageFilter());
+ setBackdropImageFilter(other.getBackdropImageFilter());
mStretchEffect = other.mStretchEffect;
return *this;
}
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 064ba7aee107..e358b57f6fe1 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -97,8 +97,12 @@ public:
bool setImageFilter(SkImageFilter* imageFilter);
+ bool setBackdropImageFilter(SkImageFilter* imageFilter);
+
SkImageFilter* getImageFilter() const { return mImageFilter.get(); }
+ SkImageFilter* getBackdropImageFilter() const { return mBackdropImageFilter.get(); }
+
const StretchEffect& getStretchEffect() const { return mStretchEffect; }
StretchEffect& mutableStretchEffect() { return mStretchEffect; }
@@ -129,6 +133,7 @@ private:
SkBlendMode mMode;
sk_sp<SkColorFilter> mColorFilter;
sk_sp<SkImageFilter> mImageFilter;
+ sk_sp<SkImageFilter> mBackdropImageFilter;
StretchEffect mStretchEffect;
};
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index b785989f35cb..ced02241ffe2 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -175,7 +175,7 @@ protected:
const Paint& paint, const SkPath& path, size_t start,
size_t end) override;
- void onFilterPaint(Paint& paint);
+ virtual void onFilterPaint(Paint& paint);
Paint filterPaint(const Paint& src) {
Paint dst(src);
diff --git a/libs/hwui/SkiaInterpolator.cpp b/libs/hwui/SkiaInterpolator.cpp
index b58f517834a3..c67b135855f7 100644
--- a/libs/hwui/SkiaInterpolator.cpp
+++ b/libs/hwui/SkiaInterpolator.cpp
@@ -18,9 +18,8 @@
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
-#include "include/private/SkFixed.h"
-#include "src/core/SkTSearch.h"
+#include <cstdlib>
#include <log/log.h>
typedef int Dot14;
@@ -41,18 +40,18 @@ static inline Dot14 pin_and_convert(float x) {
if (x <= 0) {
return 0;
}
- if (x >= SK_Scalar1) {
+ if (x >= 1.0f) {
return Dot14_ONE;
}
- return SkScalarToFixed(x) >> 2;
+ return static_cast<Dot14>(x * Dot14_ONE);
}
static float SkUnitCubicInterp(float value, float bx, float by, float cx, float cy) {
// pin to the unit-square, and convert to 2.14
Dot14 x = pin_and_convert(value);
- if (x == 0) return 0;
- if (x == Dot14_ONE) return SK_Scalar1;
+ if (x == 0) return 0.0f;
+ if (x == Dot14_ONE) return 1.0f;
Dot14 b = pin_and_convert(bx);
Dot14 c = pin_and_convert(cx);
@@ -84,7 +83,7 @@ static float SkUnitCubicInterp(float value, float bx, float by, float cx, float
A = 3 * b;
B = 3 * (c - 2 * b);
C = 3 * (b - c) + Dot14_ONE;
- return SkFixedToScalar(eval_cubic(t, A, B, C) << 2);
+ return Dot14ToFloat(eval_cubic(t, A, B, C));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -104,7 +103,7 @@ void SkiaInterpolatorBase::reset(int elemCount, int frameCount) {
fFlags = 0;
fElemCount = static_cast<uint8_t>(elemCount);
fFrameCount = static_cast<int16_t>(frameCount);
- fRepeat = SK_Scalar1;
+ fRepeat = 1.0f;
if (fStorage) {
free(fStorage);
fStorage = nullptr;
@@ -136,17 +135,46 @@ bool SkiaInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const
float SkiaInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime, SkMSec nextTime,
const float blend[4]) {
- SkASSERT(time > prevTime && time < nextTime);
+ LOG_FATAL_IF(time < prevTime || time > nextTime);
float t = (float)(time - prevTime) / (float)(nextTime - prevTime);
return blend ? SkUnitCubicInterp(t, blend[0], blend[1], blend[2], blend[3]) : t;
}
+// Returns the index of where the item is or the bit not of the index
+// where the item should go in order to keep arr sorted in ascending order.
+int SkiaInterpolatorBase::binarySearch(const SkTimeCode* arr, int count, SkMSec target) {
+ if (count <= 0) {
+ return ~0;
+ }
+
+ int lo = 0;
+ int hi = count - 1;
+
+ while (lo < hi) {
+ int mid = (hi + lo) / 2;
+ SkMSec elem = arr[mid].fTime;
+ if (elem == target) {
+ return mid;
+ } else if (elem < target) {
+ lo = mid + 1;
+ } else {
+ hi = mid;
+ }
+ }
+ // Check to see if target is greater or less than where we stopped
+ if (target < arr[lo].fTime) {
+ return ~lo;
+ }
+ // e.g. it should go at the end.
+ return ~(lo + 1);
+}
+
SkiaInterpolatorBase::Result SkiaInterpolatorBase::timeToT(SkMSec time, float* T, int* indexPtr,
bool* exactPtr) const {
- SkASSERT(fFrameCount > 0);
+ LOG_FATAL_IF(fFrameCount <= 0);
Result result = kNormal_Result;
- if (fRepeat != SK_Scalar1) {
+ if (fRepeat != 1.0f) {
SkMSec startTime = 0, endTime = 0; // initialize to avoid warning
this->getDuration(&startTime, &endTime);
SkMSec totalTime = endTime - startTime;
@@ -168,10 +196,8 @@ SkiaInterpolatorBase::Result SkiaInterpolatorBase::timeToT(SkMSec time, float* T
time = offsetTime + startTime;
}
- int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time, sizeof(SkTimeCode));
-
+ int index = SkiaInterpolatorBase::binarySearch(fTimes, fFrameCount, time);
bool exact = true;
-
if (index < 0) {
index = ~index;
if (index == 0) {
@@ -184,10 +210,11 @@ SkiaInterpolatorBase::Result SkiaInterpolatorBase::timeToT(SkMSec time, float* T
}
result = kFreezeEnd_Result;
} else {
+ // Need to interpolate between two frames.
exact = false;
}
}
- SkASSERT(index < fFrameCount);
+ LOG_FATAL_IF(index >= fFrameCount);
const SkTimeCode* nextTime = &fTimes[index];
SkMSec nextT = nextTime[0].fTime;
if (exact) {
@@ -207,7 +234,7 @@ SkiaInterpolator::SkiaInterpolator() {
}
SkiaInterpolator::SkiaInterpolator(int elemCount, int frameCount) {
- SkASSERT(elemCount > 0);
+ LOG_FATAL_IF(elemCount <= 0);
this->reset(elemCount, frameCount);
}
@@ -221,21 +248,19 @@ void SkiaInterpolator::reset(int elemCount, int frameCount) {
fValues = (float*)((char*)fStorage + sizeof(SkTimeCode) * frameCount);
}
-#define SK_Fixed1Third (SK_Fixed1 / 3)
-#define SK_Fixed2Third (SK_Fixed1 * 2 / 3)
-
static const float gIdentityBlend[4] = {0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f};
bool SkiaInterpolator::setKeyFrame(int index, SkMSec time, const float values[],
const float blend[4]) {
- SkASSERT(values != nullptr);
+ LOG_FATAL_IF(values == nullptr);
if (blend == nullptr) {
blend = gIdentityBlend;
}
- bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time, sizeof(SkTimeCode));
- SkASSERT(success);
+ // Verify the time should go after all the frames before index
+ bool success = ~index == SkiaInterpolatorBase::binarySearch(fTimes, index, time);
+ LOG_FATAL_IF(!success);
if (success) {
SkTimeCode* timeCode = &fTimes[index];
timeCode->fTime = time;
@@ -257,7 +282,7 @@ SkiaInterpolator::Result SkiaInterpolator::timeToValues(SkMSec time, float value
if (exact) {
memcpy(values, nextSrc, fElemCount * sizeof(float));
} else {
- SkASSERT(index > 0);
+ LOG_FATAL_IF(index <= 0);
const float* prevSrc = nextSrc - fElemCount;
diff --git a/libs/hwui/SkiaInterpolator.h b/libs/hwui/SkiaInterpolator.h
index 9422cb526a8f..62e6c1e33e40 100644
--- a/libs/hwui/SkiaInterpolator.h
+++ b/libs/hwui/SkiaInterpolator.h
@@ -68,14 +68,16 @@ protected:
enum Flags { kMirror = 1, kReset = 2, kHasBlend = 4 };
static float ComputeRelativeT(uint32_t time, uint32_t prevTime, uint32_t nextTime,
const float blend[4] = nullptr);
- int16_t fFrameCount;
- uint8_t fElemCount;
- uint8_t fFlags;
- float fRepeat;
struct SkTimeCode {
uint32_t fTime;
float fBlend[4];
};
+ static int binarySearch(const SkTimeCode* arr, int count, uint32_t target);
+
+ int16_t fFrameCount;
+ uint8_t fElemCount;
+ uint8_t fFlags;
+ float fRepeat;
SkTimeCode* fTimes; // pointer into fStorage
void* fStorage;
};
diff --git a/libs/hwui/SkiaWrapper.h b/libs/hwui/SkiaWrapper.h
new file mode 100644
index 000000000000..bd0e35aadbb4
--- /dev/null
+++ b/libs/hwui/SkiaWrapper.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#ifndef SKIA_WRAPPER_H_
+#define SKIA_WRAPPER_H_
+
+#include <SkRefCnt.h>
+#include <utils/RefBase.h>
+
+namespace android::uirenderer {
+
+template <typename T>
+class SkiaWrapper : public VirtualLightRefBase {
+public:
+ sk_sp<T> getInstance() {
+ if (mInstance != nullptr && shouldDiscardInstance()) {
+ mInstance = nullptr;
+ }
+
+ if (mInstance == nullptr) {
+ mInstance = createInstance();
+ mGenerationId++;
+ }
+ return mInstance;
+ }
+
+ virtual bool shouldDiscardInstance() const { return false; }
+
+ void discardInstance() { mInstance = nullptr; }
+
+ [[nodiscard]] int32_t getGenerationId() const { return mGenerationId; }
+
+protected:
+ virtual sk_sp<T> createInstance() = 0;
+
+private:
+ sk_sp<T> mInstance = nullptr;
+ int32_t mGenerationId = 0;
+};
+
+} // namespace android::uirenderer
+
+#endif // SKIA_WRAPPER_H_
diff --git a/libs/hwui/apex/android_canvas.cpp b/libs/hwui/apex/android_canvas.cpp
index 905b123076a2..19f726a31b33 100644
--- a/libs/hwui/apex/android_canvas.cpp
+++ b/libs/hwui/apex/android_canvas.cpp
@@ -45,9 +45,9 @@ static bool convert(const ANativeWindow_Buffer* buffer,
SkImageInfo imageInfo = uirenderer::ANativeWindowToImageInfo(*buffer, cs);
size_t rowBytes = buffer->stride * imageInfo.bytesPerPixel();
- // If SkSurface::MakeRasterDirect fails then we should as well as we will not be able to
+ // If SkSurfaces::WrapPixels fails then we should as well as we will not be able to
// draw into the canvas.
- sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(imageInfo, buffer->bits, rowBytes);
+ sk_sp<SkSurface> surface = SkSurfaces::WrapPixels(imageInfo, buffer->bits, rowBytes);
if (surface.get() != nullptr) {
if (outBitmap) {
outBitmap->setInfo(imageInfo, rowBytes);
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 8049dc946c9e..27773a60355a 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -111,7 +111,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::decodeNextFrame() {
{
std::unique_lock lock{mImageLock};
snap.mDurationMS = adjustFrameDuration(mSkAnimatedImage->decodeNextFrame());
- snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
+ snap.mPic = mSkAnimatedImage->makePictureSnapshot();
}
return snap;
@@ -123,7 +123,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::reset() {
{
std::unique_lock lock{mImageLock};
mSkAnimatedImage->reset();
- snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
+ snap.mPic = mSkAnimatedImage->makePictureSnapshot();
snap.mDurationMS = currentFrameDuration();
}
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 92d875bf7f1e..8344a86923ee 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -43,12 +43,15 @@
#include <SkColor.h>
#include <SkEncodedImageFormat.h>
#include <SkHighContrastFilter.h>
-#include <SkImageEncoder.h>
+#include <SkImage.h>
+#include <SkImageAndroid.h>
#include <SkImagePriv.h>
#include <SkJpegGainmapEncoder.h>
#include <SkPixmap.h>
#include <SkRect.h>
#include <SkStream.h>
+#include <SkJpegEncoder.h>
+#include <SkPngEncoder.h>
#include <SkWebpEncoder.h>
#include <limits>
@@ -296,7 +299,8 @@ Bitmap::Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes
mPixelStorage.hardware.size = AHardwareBuffer_getAllocationSize(buffer);
AHardwareBuffer_acquire(buffer);
setImmutable(); // HW bitmaps are always immutable
- mImage = SkImage::MakeFromAHardwareBuffer(buffer, mInfo.alphaType(), mInfo.refColorSpace());
+ mImage = SkImages::DeferredFromAHardwareBuffer(buffer, mInfo.alphaType(),
+ mInfo.refColorSpace());
}
#endif
@@ -407,7 +411,12 @@ sk_sp<SkImage> Bitmap::makeImage() {
// Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
// internally and ~Bitmap won't be invoked.
// TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
+#ifdef __ANDROID__
+ // pinnable images are only supported with the Ganesh GPU backend compiled in.
+ image = SkImages::PinnableRasterFromBitmap(skiaBitmap);
+#else
image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+#endif
}
return image;
}
@@ -528,17 +537,25 @@ bool Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format,
return false;
}
- SkEncodedImageFormat fm;
switch (format) {
- case JavaCompressFormat::Jpeg:
- fm = SkEncodedImageFormat::kJPEG;
- break;
+ case JavaCompressFormat::Jpeg: {
+ SkJpegEncoder::Options options;
+ options.fQuality = quality;
+ return SkJpegEncoder::Encode(stream, bitmap.pixmap(), options);
+ }
case JavaCompressFormat::Png:
- fm = SkEncodedImageFormat::kPNG;
- break;
- case JavaCompressFormat::Webp:
- fm = SkEncodedImageFormat::kWEBP;
- break;
+ return SkPngEncoder::Encode(stream, bitmap.pixmap(), {});
+ case JavaCompressFormat::Webp: {
+ SkWebpEncoder::Options options;
+ if (quality >= 100) {
+ options.fCompression = SkWebpEncoder::Compression::kLossless;
+ options.fQuality = 75; // This is effort to compress
+ } else {
+ options.fCompression = SkWebpEncoder::Compression::kLossy;
+ options.fQuality = quality;
+ }
+ return SkWebpEncoder::Encode(stream, bitmap.pixmap(), options);
+ }
case JavaCompressFormat::WebpLossy:
case JavaCompressFormat::WebpLossless: {
SkWebpEncoder::Options options;
@@ -548,8 +565,6 @@ bool Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format,
return SkWebpEncoder::Encode(stream, bitmap.pixmap(), options);
}
}
-
- return SkEncodeImage(stream, bitmap, fm, quality);
}
sp<uirenderer::Gainmap> Bitmap::gainmap() const {
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index cd8af3d933b1..2351797ac787 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -151,7 +151,7 @@ void Canvas::drawGlyphs(const minikin::Font& font, const int* glyphIds, const fl
memcpy(outPositions, positions, sizeof(float) * 2 * glyphCount);
};
- const minikin::MinikinFont* minikinFont = font.typeface().get();
+ const minikin::MinikinFont* minikinFont = font.baseTypeface().get();
SkFont* skfont = &copied.getSkFont();
MinikinFontSkia::populateSkFont(skfont, minikinFont, minikin::FontFakery());
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index 009b84b140ea..51960b036c49 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -76,7 +76,7 @@ public:
size_t start = 0;
size_t nGlyphs = layout.nGlyphs();
for (size_t i = 0; i < nGlyphs; i++) {
- const minikin::MinikinFont* nextFont = layout.getFont(i)->typeface().get();
+ const minikin::MinikinFont* nextFont = layout.typeface(i).get();
if (i > 0 && nextFont != curFont) {
SkFont* skfont = &paint->getSkFont();
MinikinFontSkia::populateSkFont(skfont, curFont, layout.getFakery(start));
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 3c67edc9a428..b63ee1bd3d98 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -140,9 +140,8 @@ Typeface* Typeface::createFromFamilies(std::vector<std::shared_ptr<minikin::Font
const minikin::FontStyle defaultStyle;
const minikin::MinikinFont* mf =
- families.empty()
- ? nullptr
- : families[0]->getClosestMatch(defaultStyle).font->typeface().get();
+ families.empty() ? nullptr
+ : families[0]->getClosestMatch(defaultStyle).typeface().get();
if (mf != nullptr) {
SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
const SkFontStyle& style = skTypeface->fontStyle();
diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp
index a7f5aa83e624..90b1da846205 100644
--- a/libs/hwui/jni/AnimatedImageDrawable.cpp
+++ b/libs/hwui/jni/AnimatedImageDrawable.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-#include "GraphicsJNI.h"
-#include "ImageDecoder.h"
-#include "Utils.h"
-
#include <SkAndroidCodec.h>
#include <SkAnimatedImage.h>
#include <SkColorFilter.h>
@@ -27,10 +23,15 @@
#include <SkRect.h>
#include <SkRefCnt.h>
#include <hwui/AnimatedImageDrawable.h>
-#include <hwui/ImageDecoder.h>
#include <hwui/Canvas.h>
+#include <hwui/ImageDecoder.h>
#include <utils/Looper.h>
+#include "ColorFilter.h"
+#include "GraphicsJNI.h"
+#include "ImageDecoder.h"
+#include "Utils.h"
+
using namespace android;
static jclass gAnimatedImageDrawableClass;
@@ -145,8 +146,9 @@ static jlong AnimatedImageDrawable_nGetAlpha(JNIEnv* env, jobject /*clazz*/, jlo
static void AnimatedImageDrawable_nSetColorFilter(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
jlong nativeFilter) {
auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
- auto* filter = reinterpret_cast<SkColorFilter*>(nativeFilter);
- drawable->setStagingColorFilter(sk_ref_sp(filter));
+ auto filter = uirenderer::ColorFilter::fromJava(nativeFilter);
+ auto skColorFilter = filter != nullptr ? filter->getInstance() : sk_sp<SkColorFilter>();
+ drawable->setStagingColorFilter(skColorFilter);
}
static jboolean AnimatedImageDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
diff --git a/libs/hwui/jni/ColorFilter.cpp b/libs/hwui/jni/ColorFilter.cpp
index 4bd7ef47b871..0b95148d3c82 100644
--- a/libs/hwui/jni/ColorFilter.cpp
+++ b/libs/hwui/jni/ColorFilter.cpp
@@ -15,20 +15,21 @@
** limitations under the License.
*/
-#include "GraphicsJNI.h"
+#include "ColorFilter.h"
+#include "GraphicsJNI.h"
#include "SkBlendMode.h"
-#include "SkColorFilter.h"
-#include "SkColorMatrixFilter.h"
namespace android {
using namespace uirenderer;
-class SkColorFilterGlue {
+class ColorFilterGlue {
public:
- static void SafeUnref(SkColorFilter* filter) {
- SkSafeUnref(filter);
+ static void SafeUnref(ColorFilter* filter) {
+ if (filter) {
+ filter->decStrong(nullptr);
+ }
}
static jlong GetNativeFinalizer(JNIEnv*, jobject) {
@@ -36,41 +37,75 @@ public:
}
static jlong CreateBlendModeFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) {
- SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
- return reinterpret_cast<jlong>(SkColorFilters::Blend(srcColor, mode).release());
+ auto mode = static_cast<SkBlendMode>(modeHandle);
+ auto* blendModeFilter = new BlendModeColorFilter(srcColor, mode);
+ blendModeFilter->incStrong(nullptr);
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(blendModeFilter));
}
static jlong CreateLightingFilter(JNIEnv* env, jobject, jint mul, jint add) {
- return reinterpret_cast<jlong>(SkColorMatrixFilter::MakeLightingFilter(mul, add).release());
+ auto* lightingFilter = new LightingFilter(mul, add);
+ lightingFilter->incStrong(nullptr);
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(lightingFilter));
}
- static jlong CreateColorMatrixFilter(JNIEnv* env, jobject, jfloatArray jarray) {
- float matrix[20];
- env->GetFloatArrayRegion(jarray, 0, 20, matrix);
+ static void SetLightingFilterMul(JNIEnv* env, jobject, jlong lightingFilterPtr, jint mul) {
+ auto* filter = reinterpret_cast<LightingFilter*>(lightingFilterPtr);
+ if (filter) {
+ filter->setMul(mul);
+ }
+ }
+
+ static void SetLightingFilterAdd(JNIEnv* env, jobject, jlong lightingFilterPtr, jint add) {
+ auto* filter = reinterpret_cast<LightingFilter*>(lightingFilterPtr);
+ if (filter) {
+ filter->setAdd(add);
+ }
+ }
+
+ static std::vector<float> getMatrixFromJFloatArray(JNIEnv* env, jfloatArray jarray) {
+ std::vector<float> matrix(20);
+ // float matrix[20];
+ env->GetFloatArrayRegion(jarray, 0, 20, matrix.data());
// java biases the translates by 255, so undo that before calling skia
matrix[ 4] *= (1.0f/255);
matrix[ 9] *= (1.0f/255);
matrix[14] *= (1.0f/255);
matrix[19] *= (1.0f/255);
- return reinterpret_cast<jlong>(SkColorFilters::Matrix(matrix).release());
+ return matrix;
+ }
+
+ static jlong CreateColorMatrixFilter(JNIEnv* env, jobject, jfloatArray jarray) {
+ std::vector<float> matrix = getMatrixFromJFloatArray(env, jarray);
+ auto* colorMatrixColorFilter = new ColorMatrixColorFilter(std::move(matrix));
+ colorMatrixColorFilter->incStrong(nullptr);
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(colorMatrixColorFilter));
+ }
+
+ static void SetColorMatrix(JNIEnv* env, jobject, jlong colorMatrixColorFilterPtr,
+ jfloatArray jarray) {
+ auto* filter = reinterpret_cast<ColorMatrixColorFilter*>(colorMatrixColorFilterPtr);
+ if (filter) {
+ filter->setMatrix(getMatrixFromJFloatArray(env, jarray));
+ }
}
};
static const JNINativeMethod colorfilter_methods[] = {
- {"nativeGetFinalizer", "()J", (void*) SkColorFilterGlue::GetNativeFinalizer }
-};
+ {"nativeGetFinalizer", "()J", (void*)ColorFilterGlue::GetNativeFinalizer}};
static const JNINativeMethod blendmode_methods[] = {
- { "native_CreateBlendModeFilter", "(II)J", (void*) SkColorFilterGlue::CreateBlendModeFilter },
+ {"native_CreateBlendModeFilter", "(II)J", (void*)ColorFilterGlue::CreateBlendModeFilter},
};
static const JNINativeMethod lighting_methods[] = {
- { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
-};
+ {"native_CreateLightingFilter", "(II)J", (void*)ColorFilterGlue::CreateLightingFilter},
+ {"native_SetLightingFilterAdd", "(JI)V", (void*)ColorFilterGlue::SetLightingFilterAdd},
+ {"native_SetLightingFilterMul", "(JI)V", (void*)ColorFilterGlue::SetLightingFilterMul}};
static const JNINativeMethod colormatrix_methods[] = {
- { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
-};
+ {"nativeColorMatrixFilter", "([F)J", (void*)ColorFilterGlue::CreateColorMatrixFilter},
+ {"nativeSetColorMatrix", "(J[F)V", (void*)ColorFilterGlue::SetColorMatrix}};
int register_android_graphics_ColorFilter(JNIEnv* env) {
android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods,
diff --git a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
index 15e529e169fc..a66d3b860ade 100644
--- a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
+++ b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
@@ -1,11 +1,11 @@
#include "CreateJavaOutputStreamAdaptor.h"
#include "SkData.h"
-#include "SkMalloc.h"
#include "SkRefCnt.h"
#include "SkStream.h"
#include "SkTypes.h"
#include "Utils.h"
+#include <cstdlib>
#include <nativehelper/JNIHelp.h>
#include <log/log.h>
#include <memory>
@@ -177,6 +177,10 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, jbyteArray s
return JavaInputStreamAdaptor::Create(env, stream, storage, swallowExceptions);
}
+static void free_pointer_skproc(const void* ptr, void*) {
+ free((void*)ptr);
+}
+
sk_sp<SkData> CopyJavaInputStream(JNIEnv* env, jobject inputStream, jbyteArray storage) {
std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, inputStream, storage));
if (!stream) {
@@ -186,19 +190,31 @@ sk_sp<SkData> CopyJavaInputStream(JNIEnv* env, jobject inputStream, jbyteArray s
size_t bufferSize = 4096;
size_t streamLen = 0;
size_t len;
- char* data = (char*)sk_malloc_throw(bufferSize);
+ char* data = (char*)malloc(bufferSize);
+ LOG_ALWAYS_FATAL_IF(!data);
while ((len = stream->read(data + streamLen,
bufferSize - streamLen)) != 0) {
streamLen += len;
if (streamLen == bufferSize) {
bufferSize *= 2;
- data = (char*)sk_realloc_throw(data, bufferSize);
+ data = (char*)realloc(data, bufferSize);
+ LOG_ALWAYS_FATAL_IF(!data);
}
}
- data = (char*)sk_realloc_throw(data, streamLen);
-
- return SkData::MakeFromMalloc(data, streamLen);
+ if (streamLen == 0) {
+ // realloc with size 0 is unspecified behavior in C++11
+ free(data);
+ data = nullptr;
+ } else {
+ // Trim down the buffer to the actual size of the data.
+ LOG_FATAL_IF(streamLen > bufferSize);
+ data = (char*)realloc(data, streamLen);
+ LOG_ALWAYS_FATAL_IF(!data);
+ }
+ // Just in case sk_free differs from free, we ask Skia to use
+ // free to cleanup the buffer that SkData wraps.
+ return SkData::MakeWithProc(data, streamLen, free_pointer_skproc, nullptr);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/jni/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp
index 28e71d74e5b9..af1668fbd7dd 100644
--- a/libs/hwui/jni/FontFamily.cpp
+++ b/libs/hwui/jni/FontFamily.cpp
@@ -45,6 +45,7 @@
namespace android {
+namespace {
struct NativeFamilyBuilder {
NativeFamilyBuilder(uint32_t langId, int variant)
: langId(langId), variant(static_cast<minikin::FamilyVariant>(variant)) {}
@@ -53,6 +54,7 @@ struct NativeFamilyBuilder {
std::vector<std::shared_ptr<minikin::Font>> fonts;
std::vector<minikin::FontVariation> axes;
};
+} // namespace
static inline NativeFamilyBuilder* toNativeBuilder(jlong ptr) {
return reinterpret_cast<NativeFamilyBuilder*>(ptr);
@@ -87,7 +89,8 @@ static jlong FontFamily_create(CRITICAL_JNI_PARAMS_COMMA jlong builderPtr) {
}
std::shared_ptr<minikin::FontFamily> family = minikin::FontFamily::create(
builder->langId, builder->variant, std::move(builder->fonts),
- true /* isCustomFallback */, false /* isDefaultFallback */);
+ true /* isCustomFallback */, false /* isDefaultFallback */,
+ minikin::VariationFamilyType::None);
if (family->getCoverage().length() == 0) {
return 0;
}
diff --git a/libs/hwui/jni/GraphicsJNI.h b/libs/hwui/jni/GraphicsJNI.h
index 23ab5dd38b1a..b9fff36d372e 100644
--- a/libs/hwui/jni/GraphicsJNI.h
+++ b/libs/hwui/jni/GraphicsJNI.h
@@ -125,14 +125,6 @@ public:
static jobject createBitmapRegionDecoder(JNIEnv* env,
android::BitmapRegionDecoderWrapper* bitmap);
- /**
- * Given a bitmap we natively allocate a memory block to store the contents
- * of that bitmap. The memory is then attached to the bitmap via an
- * SkPixelRef, which ensures that upon deletion the appropriate caches
- * are notified.
- */
- static bool allocatePixels(JNIEnv* env, SkBitmap* bitmap);
-
/** Copy the colors in colors[] to the bitmap, convert to the correct
format along the way.
Whether to use premultiplied pixels is determined by dstBitmap's alphaType.
diff --git a/libs/hwui/jni/MaskFilter.cpp b/libs/hwui/jni/MaskFilter.cpp
index 048ce025ce27..cbd452031f69 100644
--- a/libs/hwui/jni/MaskFilter.cpp
+++ b/libs/hwui/jni/MaskFilter.cpp
@@ -1,6 +1,5 @@
#include "GraphicsJNI.h"
#include "SkMaskFilter.h"
-#include "SkBlurMask.h"
#include "SkBlurMaskFilter.h"
#include "SkBlurTypes.h"
#include "SkTableMaskFilter.h"
@@ -11,6 +10,13 @@ static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
}
}
+// From https://skia.googlesource.com/skia/+/d74c99a3cd5eef5f16b2eb226e6b45fe523c8552/src/core/SkBlurMask.cpp#28
+static constexpr float kBLUR_SIGMA_SCALE = 0.57735f;
+
+static float convertRadiusToSigma(float radius) {
+ return radius > 0 ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+}
+
class SkMaskFilterGlue {
public:
static void destructor(JNIEnv* env, jobject, jlong filterHandle) {
@@ -19,7 +25,7 @@ public:
}
static jlong createBlur(JNIEnv* env, jobject, jfloat radius, jint blurStyle) {
- SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
+ SkScalar sigma = convertRadiusToSigma(radius);
SkMaskFilter* filter = SkMaskFilter::MakeBlur((SkBlurStyle)blurStyle, sigma).release();
ThrowIAE_IfNull(env, filter);
return reinterpret_cast<jlong>(filter);
@@ -34,7 +40,7 @@ public:
direction[i] = values[i];
}
- SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
+ SkScalar sigma = convertRadiusToSigma(radius);
SkMaskFilter* filter = SkBlurMaskFilter::MakeEmboss(sigma,
direction, ambient, specular).release();
ThrowIAE_IfNull(env, filter);
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index 13357fa25e8c..d2a4efe05219 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -18,27 +18,6 @@
#undef LOG_TAG
#define LOG_TAG "Paint"
-#include <utils/Log.h>
-
-#include "GraphicsJNI.h"
-#include <nativehelper/ScopedStringChars.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include <nativehelper/ScopedPrimitiveArray.h>
-
-#include "SkColorFilter.h"
-#include "SkColorSpace.h"
-#include "SkFont.h"
-#include "SkFontMetrics.h"
-#include "SkFontTypes.h"
-#include "SkMaskFilter.h"
-#include "SkPath.h"
-#include "SkPathEffect.h"
-#include "SkPathUtils.h"
-#include "SkShader.h"
-#include "SkBlendMode.h"
-#include "unicode/uloc.h"
-#include "utils/Blur.h"
-
#include <hwui/BlurDrawLooper.h>
#include <hwui/MinikinSkia.h>
#include <hwui/MinikinUtils.h>
@@ -48,13 +27,33 @@
#include <minikin/LocaleList.h>
#include <minikin/Measurement.h>
#include <minikin/MinikinPaint.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedUtfChars.h>
#include <unicode/utf16.h>
+#include <utils/Log.h>
#include <cassert>
#include <cstring>
#include <memory>
#include <vector>
+#include "ColorFilter.h"
+#include "GraphicsJNI.h"
+#include "SkBlendMode.h"
+#include "SkColorFilter.h"
+#include "SkColorSpace.h"
+#include "SkFont.h"
+#include "SkFontMetrics.h"
+#include "SkFontTypes.h"
+#include "SkMaskFilter.h"
+#include "SkPath.h"
+#include "SkPathEffect.h"
+#include "SkPathUtils.h"
+#include "SkShader.h"
+#include "unicode/uloc.h"
+#include "utils/Blur.h"
+
namespace android {
static void getPosTextPath(const SkFont& font, const uint16_t glyphs[], int count,
@@ -584,7 +583,7 @@ namespace PaintGlue {
minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
float saveSkewX = font->getSkewX();
bool savefakeBold = font->isEmbolden();
- MinikinFontSkia::populateSkFont(font, baseFont.font->typeface().get(), baseFont.fakery);
+ MinikinFontSkia::populateSkFont(font, baseFont.typeface().get(), baseFont.fakery);
SkScalar spacing = font->getMetrics(metrics);
// The populateSkPaint call may have changed fake bold / text skew
// because we want to measure with those effects applied, so now
@@ -821,9 +820,11 @@ namespace PaintGlue {
static jlong setColorFilter(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong filterHandle) {
Paint* obj = reinterpret_cast<Paint *>(objHandle);
- SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(filterHandle);
- obj->setColorFilter(sk_ref_sp(filter));
- return reinterpret_cast<jlong>(obj->getColorFilter());
+ auto colorFilter = uirenderer::ColorFilter::fromJava(filterHandle);
+ auto skColorFilter =
+ colorFilter != nullptr ? colorFilter->getInstance() : sk_sp<SkColorFilter>();
+ obj->setColorFilter(skColorFilter);
+ return filterHandle;
}
static void setXfermode(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle, jint xfermodeHandle) {
diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp
index f3db1705e694..dcd3fa4932fc 100644
--- a/libs/hwui/jni/RenderEffect.cpp
+++ b/libs/hwui/jni/RenderEffect.cpp
@@ -14,13 +14,13 @@
* limitations under the License.
*/
#include "Bitmap.h"
+#include "ColorFilter.h"
#include "GraphicsJNI.h"
#include "SkBlendMode.h"
#include "SkImageFilter.h"
#include "SkImageFilters.h"
#include "graphics_jni_helpers.h"
#include "utils/Blur.h"
-#include <utils/Log.h>
using namespace android::uirenderer;
@@ -76,11 +76,13 @@ static jlong createColorFilterEffect(
jlong colorFilterHandle,
jlong inputFilterHandle
) {
- auto* colorFilter = reinterpret_cast<const SkColorFilter*>(colorFilterHandle);
+ auto colorFilter = android::uirenderer::ColorFilter::fromJava(colorFilterHandle);
+ auto skColorFilter =
+ colorFilter != nullptr ? colorFilter->getInstance() : sk_sp<SkColorFilter>();
auto* inputFilter = reinterpret_cast<const SkImageFilter*>(inputFilterHandle);
- sk_sp<SkImageFilter> colorFilterImageFilter = SkImageFilters::ColorFilter(
- sk_ref_sp(colorFilter), sk_ref_sp(inputFilter), nullptr);
- return reinterpret_cast<jlong>(colorFilterImageFilter.release());
+ sk_sp<SkImageFilter> colorFilterImageFilter =
+ SkImageFilters::ColorFilter(skColorFilter, sk_ref_sp(inputFilter), nullptr);
+ return reinterpret_cast<jlong>(colorFilterImageFilter.release());
}
static jlong createBlendModeEffect(
diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
index f060bb32031a..426644ee6a4e 100644
--- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
@@ -84,7 +84,7 @@ static void android_view_DisplayListCanvas_resetDisplayListCanvas(CRITICAL_JNI_P
canvas->resetRecording(width, height, renderNode);
}
-static jint android_view_DisplayListCanvas_getMaxTextureSize(CRITICAL_JNI_PARAMS) {
+static jint android_view_DisplayListCanvas_getMaxTextureSize(JNIEnv*, jobject) {
#ifdef __ANDROID__ // Layoutlib does not support RenderProxy (RenderThread)
return android::uirenderer::renderthread::RenderProxy::maxTextureSize();
#else
@@ -175,14 +175,14 @@ static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAM
const char* const kClassPathName = "android/graphics/RecordingCanvas";
static JNINativeMethod gMethods[] = {
+ {"nGetMaximumTextureWidth", "()I", (void*)android_view_DisplayListCanvas_getMaxTextureSize},
+ {"nGetMaximumTextureHeight", "()I",
+ (void*)android_view_DisplayListCanvas_getMaxTextureSize},
// ------------ @CriticalNative --------------
{"nCreateDisplayListCanvas", "(JII)J",
(void*)android_view_DisplayListCanvas_createDisplayListCanvas},
{"nResetDisplayListCanvas", "(JJII)V",
(void*)android_view_DisplayListCanvas_resetDisplayListCanvas},
- {"nGetMaximumTextureWidth", "()I", (void*)android_view_DisplayListCanvas_getMaxTextureSize},
- {"nGetMaximumTextureHeight", "()I",
- (void*)android_view_DisplayListCanvas_getMaxTextureSize},
{"nEnableZ", "(JZ)V", (void*)android_view_DisplayListCanvas_enableZ},
{"nFinishRecording", "(JJ)V", (void*)android_view_DisplayListCanvas_finishRecording},
{"nDrawRenderNode", "(JJ)V", (void*)android_view_DisplayListCanvas_drawRenderNode},
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index d04de37f6961..ee22f7c6cf03 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -27,7 +27,7 @@
#include <SkColorSpace.h>
#include <SkData.h>
#include <SkImage.h>
-#include <SkImagePriv.h>
+#include <SkImageAndroid.h>
#include <SkPicture.h>
#include <SkPixmap.h>
#include <SkSerialProcs.h>
@@ -35,6 +35,7 @@
#include <SkTypeface.h>
#include <dlfcn.h>
#include <gui/TraceUtils.h>
+#include <include/encode/SkPngEncoder.h>
#include <inttypes.h>
#include <media/NdkImage.h>
#include <media/NdkImageReader.h>
@@ -54,6 +55,7 @@
#include <algorithm>
#include <atomic>
+#include <log/log.h>
#include <vector>
#include "JvmErrorReporter.h"
@@ -477,7 +479,7 @@ public:
// actually cross thread boundaries here, make a copy so it's immutable proper
if (bitmap && !bitmap->isImmutable()) {
ATRACE_NAME("Copying mutable bitmap");
- return SkImage::MakeFromBitmap(*bitmap);
+ return SkImages::RasterFromBitmap(*bitmap);
}
if (img->isTextureBacked()) {
ATRACE_NAME("Readback of texture image");
@@ -497,7 +499,7 @@ public:
return sk_ref_sp(img);
}
bm.setImmutable();
- return SkMakeImageFromRasterBitmap(bm, kNever_SkCopyPixelsMode);
+ return SkImages::PinnableRasterFromBitmap(bm);
}
return sk_ref_sp(img);
}
@@ -524,7 +526,16 @@ public:
if (iter != context->mTextureMap.end()) {
img = iter->second.get();
}
- return img->encodeToData();
+ if (!img) {
+ return nullptr;
+ }
+ // The following encode (specifically the pixel readback) will fail on a
+ // texture-backed image. They should already be raster images, but on
+ // the off-chance they aren't, we will just serialize it as nothing.
+ if (img->isTextureBacked()) {
+ return SkData::MakeEmpty();
+ }
+ return SkPngEncoder::Encode(nullptr, img, {});
}
void serialize(SkWStream* stream) const override {
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 8c7b9a4b5e94..2a218a25913d 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -243,6 +243,13 @@ static jboolean android_view_RenderNode_setRenderEffect(CRITICAL_JNI_PARAMS_COMM
return SET_AND_DIRTY(mutateLayerProperties().setImageFilter, imageFilter, RenderNode::GENERIC);
}
+static jboolean android_view_RenderNode_setBackdropRenderEffect(
+ CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jlong renderEffectPtr) {
+ SkImageFilter* imageFilter = reinterpret_cast<SkImageFilter*>(renderEffectPtr);
+ return SET_AND_DIRTY(mutateLayerProperties().setBackdropImageFilter, imageFilter,
+ RenderNode::GENERIC);
+}
+
static jboolean android_view_RenderNode_setHasOverlappingRendering(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
bool hasOverlappingRendering) {
return SET_AND_DIRTY(setHasOverlappingRendering, hasOverlappingRendering,
@@ -792,6 +799,8 @@ static const JNINativeMethod gMethods[] = {
{"nSetAlpha", "(JF)Z", (void*)android_view_RenderNode_setAlpha},
{"nSetRenderEffect", "(JJ)Z", (void*)android_view_RenderNode_setRenderEffect},
+ {"nSetBackdropRenderEffect", "(JJ)Z",
+ (void*)android_view_RenderNode_setBackdropRenderEffect},
{"nSetHasOverlappingRendering", "(JZ)Z",
(void*)android_view_RenderNode_setHasOverlappingRendering},
{"nSetUsageHint", "(JI)V", (void*)android_view_RenderNode_setUsageHint},
diff --git a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
index 9cffceb308c8..ade48f26937f 100644
--- a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#include "GraphicsJNI.h"
+#include <hwui/Paint.h>
+#include "ColorFilter.h"
+#include "GraphicsJNI.h"
#include "PathParser.h"
#include "VectorDrawable.h"
-#include <hwui/Paint.h>
-
namespace android {
using namespace uirenderer;
using namespace uirenderer::VectorDrawable;
@@ -108,8 +108,9 @@ static jint draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
SkRect rect;
GraphicsJNI::jrect_to_rect(env, jrect, &rect);
- SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
- return tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
+ auto colorFilter = ColorFilter::fromJava(colorFilterPtr);
+ auto skColorFilter = colorFilter != nullptr ? colorFilter->getInstance() : nullptr;
+ return tree->draw(canvas, skColorFilter.get(), rect, needsMirroring, canReuseCache);
}
/**
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 1af60b2f5fae..8cfdeeb7e128 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -127,7 +127,7 @@ static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jo
static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong builderPtr,
jint weight, jboolean italic, jint ttcIndex) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
+ MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->baseTypeface().get());
std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
// Reconstruct SkTypeface with different arguments from existing SkTypeface.
@@ -159,7 +159,7 @@ static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong
static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
jlong paintHandle, jobject rect) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
+ MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->baseTypeface().get());
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
SkFont* skFont = &paint->getSkFont();
@@ -179,7 +179,7 @@ static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint g
static jfloat Font_getFontMetrics(JNIEnv* env, jobject, jlong fontHandle, jlong paintHandle,
jobject metricsObj) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
+ MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->baseTypeface().get());
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
SkFont* skFont = &paint->getSkFont();
@@ -209,7 +209,7 @@ static jlong Font_cloneFont(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
// Fast Native
static jobject Font_newByteBuffer(JNIEnv* env, jobject, jlong fontPtr) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
- const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->baseTypeface();
return env->NewDirectByteBuffer(const_cast<void*>(minikinFont->GetFontData()),
minikinFont->GetFontSize());
}
@@ -217,7 +217,7 @@ static jobject Font_newByteBuffer(JNIEnv* env, jobject, jlong fontPtr) {
// Critical Native
static jlong Font_getBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
- return reinterpret_cast<jlong>(font->font->typeface()->GetFontData());
+ return reinterpret_cast<jlong>(font->font->baseTypeface()->GetFontData());
}
// Critical Native
@@ -236,7 +236,7 @@ static jstring Font_getFontPath(JNIEnv* env, jobject, jlong fontPtr) {
}
return env->NewStringUTF(path.c_str());
} else {
- const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->baseTypeface();
const std::string& path = minikinFont->GetFontPath();
if (path.empty()) {
return nullptr;
@@ -275,7 +275,7 @@ static jint Font_getIndex(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
reader.skipString(); // fontPath
return reader.read<int>();
} else {
- const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->baseTypeface();
return minikinFont->GetFontIndex();
}
}
@@ -289,7 +289,7 @@ static jint Font_getAxisCount(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
reader.skip<int>(); // fontIndex
return reader.readArray<minikin::FontVariation>().second;
} else {
- const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->baseTypeface();
return minikinFont->GetAxes().size();
}
}
@@ -304,7 +304,7 @@ static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr, jint inde
reader.skip<int>(); // fontIndex
var = reader.readArray<minikin::FontVariation>().first[index];
} else {
- const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->baseTypeface();
var = minikinFont->GetAxes().at(index);
}
uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
@@ -314,7 +314,7 @@ static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr, jint inde
// Critical Native
static jint Font_getSourceId(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
- return font->font->typeface()->GetSourceId();
+ return font->font->baseTypeface()->GetSourceId();
}
static jlongArray Font_getAvailableFontSet(JNIEnv* env, jobject) {
diff --git a/libs/hwui/jni/fonts/FontFamily.cpp b/libs/hwui/jni/fonts/FontFamily.cpp
index 897c4d71c0d5..1e392b14728d 100644
--- a/libs/hwui/jni/fonts/FontFamily.cpp
+++ b/libs/hwui/jni/fonts/FontFamily.cpp
@@ -29,9 +29,11 @@
namespace android {
+namespace {
struct NativeFamilyBuilder {
std::vector<std::shared_ptr<minikin::Font>> fonts;
};
+} // namespace
static inline NativeFamilyBuilder* toBuilder(jlong ptr) {
return reinterpret_cast<NativeFamilyBuilder*>(ptr);
@@ -58,7 +60,7 @@ static void FontFamily_Builder_addFont(CRITICAL_JNI_PARAMS_COMMA jlong builderPt
// Regular JNI
static jlong FontFamily_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr,
jstring langTags, jint variant, jboolean isCustomFallback,
- jboolean isDefaultFallback) {
+ jboolean isDefaultFallback, jint variationFamilyType) {
std::unique_ptr<NativeFamilyBuilder> builder(toBuilder(builderPtr));
uint32_t localeId;
if (langTags == nullptr) {
@@ -69,7 +71,8 @@ static jlong FontFamily_Builder_build(JNIEnv* env, jobject clazz, jlong builderP
}
std::shared_ptr<minikin::FontFamily> family = minikin::FontFamily::create(
localeId, static_cast<minikin::FamilyVariant>(variant), std::move(builder->fonts),
- isCustomFallback, isDefaultFallback);
+ isCustomFallback, isDefaultFallback,
+ static_cast<minikin::VariationFamilyType>(variationFamilyType));
if (family->getCoverage().length() == 0) {
// No coverage means minikin rejected given font for some reasons.
jniThrowException(env, "java/lang/IllegalArgumentException",
@@ -119,7 +122,7 @@ static jlong FontFamily_getFont(CRITICAL_JNI_PARAMS_COMMA jlong familyPtr, jint
static const JNINativeMethod gFontFamilyBuilderMethods[] = {
{"nInitBuilder", "()J", (void*)FontFamily_Builder_initBuilder},
{"nAddFont", "(JJ)V", (void*)FontFamily_Builder_addFont},
- {"nBuild", "(JLjava/lang/String;IZZ)J", (void*)FontFamily_Builder_build},
+ {"nBuild", "(JLjava/lang/String;IZZI)J", (void*)FontFamily_Builder_build},
{"nGetReleaseNativeFamily", "()J", (void*)FontFamily_Builder_GetReleaseFunc},
};
diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp
index 8e4dd53069f4..8c377b9f1829 100644
--- a/libs/hwui/jni/text/TextShaper.cpp
+++ b/libs/hwui/jni/text/TextShaper.cpp
@@ -62,7 +62,7 @@ static jlong shapeTextRun(const uint16_t* text, int textSize, int start, int cou
const minikin::Font* font = layout.getFont(i);
if (seenFonts.find(font) != seenFonts.end()) continue;
minikin::MinikinExtent extent = {};
- font->typeface()->GetFontExtent(&extent, minikinPaint, layout.getFakery(i));
+ layout.typeface(i)->GetFontExtent(&extent, minikinPaint, layout.getFakery(i));
overallAscent = std::min(overallAscent, extent.ascent);
overallDescent = std::max(overallDescent, extent.descent);
}
@@ -148,6 +148,30 @@ static jfloat TextShaper_Result_getY(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i
}
// CriticalNative
+static jboolean TextShaper_Result_getFakeBold(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
+ const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+ return layout->layout.getFakery(i).isFakeBold();
+}
+
+// CriticalNative
+static jboolean TextShaper_Result_getFakeItalic(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
+ const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+ return layout->layout.getFakery(i).isFakeItalic();
+}
+
+// CriticalNative
+static jfloat TextShaper_Result_getWeightOverride(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
+ const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+ return layout->layout.getFakery(i).wghtAdjustment();
+}
+
+// CriticalNative
+static jfloat TextShaper_Result_getItalicOverride(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
+ const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+ return layout->layout.getFakery(i).italAdjustment();
+}
+
+// CriticalNative
static jlong TextShaper_Result_getFont(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
std::shared_ptr<minikin::Font> fontRef = layout->layout.getFontRef(i);
@@ -185,15 +209,19 @@ static const JNINativeMethod gMethods[] = {
};
static const JNINativeMethod gResultMethods[] = {
- { "nGetGlyphCount", "(J)I", (void*)TextShaper_Result_getGlyphCount },
- { "nGetTotalAdvance", "(J)F", (void*)TextShaper_Result_getTotalAdvance },
- { "nGetAscent", "(J)F", (void*)TextShaper_Result_getAscent },
- { "nGetDescent", "(J)F", (void*)TextShaper_Result_getDescent },
- { "nGetGlyphId", "(JI)I", (void*)TextShaper_Result_getGlyphId },
- { "nGetX", "(JI)F", (void*)TextShaper_Result_getX },
- { "nGetY", "(JI)F", (void*)TextShaper_Result_getY },
- { "nGetFont", "(JI)J", (void*)TextShaper_Result_getFont },
- { "nReleaseFunc", "()J", (void*)TextShaper_Result_nReleaseFunc },
+ {"nGetGlyphCount", "(J)I", (void*)TextShaper_Result_getGlyphCount},
+ {"nGetTotalAdvance", "(J)F", (void*)TextShaper_Result_getTotalAdvance},
+ {"nGetAscent", "(J)F", (void*)TextShaper_Result_getAscent},
+ {"nGetDescent", "(J)F", (void*)TextShaper_Result_getDescent},
+ {"nGetGlyphId", "(JI)I", (void*)TextShaper_Result_getGlyphId},
+ {"nGetX", "(JI)F", (void*)TextShaper_Result_getX},
+ {"nGetY", "(JI)F", (void*)TextShaper_Result_getY},
+ {"nGetFont", "(JI)J", (void*)TextShaper_Result_getFont},
+ {"nGetFakeBold", "(JI)Z", (void*)TextShaper_Result_getFakeBold},
+ {"nGetFakeItalic", "(JI)Z", (void*)TextShaper_Result_getFakeItalic},
+ {"nGetWeightOverride", "(JI)F", (void*)TextShaper_Result_getWeightOverride},
+ {"nGetItalicOverride", "(JI)F", (void*)TextShaper_Result_getItalicOverride},
+ {"nReleaseFunc", "()J", (void*)TextShaper_Result_nReleaseFunc},
};
int register_android_graphics_text_TextShaper(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp b/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
new file mode 100644
index 000000000000..ffad69993fd8
--- /dev/null
+++ b/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "BackdropFilterDrawable.h"
+
+#include <SkImage.h>
+#include <SkSurface.h>
+
+#include "RenderNode.h"
+#include "RenderNodeDrawable.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+BackdropFilterDrawable::~BackdropFilterDrawable() {}
+
+bool BackdropFilterDrawable::prepareToDraw(SkCanvas* canvas, const RenderProperties& properties,
+ int backdropImageWidth, int backdropImageHeight) {
+ // the drawing bounds for blurred content.
+ mDstBounds.setWH(properties.getWidth(), properties.getHeight());
+
+ float alphaMultiplier = 1.0f;
+ RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true);
+
+ // get proper subset for previous content.
+ canvas->getTotalMatrix().mapRect(&mImageSubset, mDstBounds);
+ SkRect imageSubset(mImageSubset);
+ // ensure the subset is inside bounds of previous content.
+ if (!mImageSubset.intersect(SkRect::MakeWH(backdropImageWidth, backdropImageHeight))) {
+ return false;
+ }
+
+ // correct the drawing bounds if subset was changed.
+ if (mImageSubset != imageSubset) {
+ SkMatrix inverse;
+ if (canvas->getTotalMatrix().invert(&inverse)) {
+ inverse.mapRect(&mDstBounds, mImageSubset);
+ }
+ }
+
+ // follow the alpha from the target RenderNode.
+ mPaint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier);
+ return true;
+}
+
+void BackdropFilterDrawable::onDraw(SkCanvas* canvas) {
+ const RenderProperties& properties = mTargetRenderNode->properties();
+ auto* backdropFilter = properties.layerProperties().getBackdropImageFilter();
+ auto* surface = canvas->getSurface();
+ if (!backdropFilter || !surface) {
+ return;
+ }
+
+ auto backdropImage = surface->makeImageSnapshot();
+ // sync necessary properties from target RenderNode.
+ if (!prepareToDraw(canvas, properties, backdropImage->width(), backdropImage->height())) {
+ return;
+ }
+
+ auto imageSubset = mImageSubset.roundOut();
+ backdropImage =
+ backdropImage->makeWithFilter(canvas->recordingContext(), backdropFilter, imageSubset,
+ imageSubset, &mOutSubset, &mOutOffset);
+ canvas->drawImageRect(backdropImage, SkRect::Make(mOutSubset), mDstBounds,
+ SkSamplingOptions(SkFilterMode::kLinear), &mPaint,
+ SkCanvas::kStrict_SrcRectConstraint);
+}
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/pipeline/skia/BackdropFilterDrawable.h b/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
new file mode 100644
index 000000000000..9e35837675ae
--- /dev/null
+++ b/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <SkCanvas.h>
+#include <SkDrawable.h>
+#include <SkPaint.h>
+
+namespace android {
+namespace uirenderer {
+
+class RenderNode;
+class RenderProperties;
+
+namespace skiapipeline {
+
+/**
+ * This drawable captures it's backdrop content and render it with a
+ * image filter.
+ */
+class BackdropFilterDrawable : public SkDrawable {
+public:
+ BackdropFilterDrawable(RenderNode* renderNode, SkCanvas* canvas)
+ : mTargetRenderNode(renderNode), mBounds(canvas->getLocalClipBounds()) {}
+
+ ~BackdropFilterDrawable();
+
+private:
+ RenderNode* mTargetRenderNode;
+ SkPaint mPaint;
+
+ SkRect mDstBounds;
+ SkRect mImageSubset;
+ SkIRect mOutSubset;
+ SkIPoint mOutOffset;
+
+ /**
+ * Check all necessary properties before actual drawing.
+ * Return true if ready to draw.
+ */
+ bool prepareToDraw(SkCanvas* canvas, const RenderProperties& properties, int backdropImageWidth,
+ int backdropImageHeight);
+
+protected:
+ void onDraw(SkCanvas* canvas) override;
+
+ virtual SkRect onGetBounds() override { return mBounds; }
+ const SkRect mBounds;
+};
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 8d5967bbd461..dbd9ef3c9e4c 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -21,9 +21,12 @@
#include "GrBackendSurface.h"
#include "RenderNode.h"
#include "SkAndroidFrameworkUtils.h"
+#include "SkCanvas.h"
+#include "SkCanvasAndroid.h"
#include "SkClipStack.h"
#include "SkRect.h"
#include "SkM44.h"
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include "include/gpu/GpuTypes.h" // from Skia
#include "utils/GLUtils.h"
#include <effects/GainmapRenderer.h>
@@ -34,7 +37,7 @@ namespace uirenderer {
namespace skiapipeline {
static void setScissor(int viewportHeight, const SkIRect& clip) {
- SkASSERT(!clip.isEmpty());
+ LOG_FATAL_IF(clip.isEmpty(), "empty scissor clip");
// transform to Y-flipped GL space, and prevent negatives
GLint y = viewportHeight - clip.fBottom;
GLint height = (viewportHeight - clip.fTop) - y;
@@ -42,7 +45,7 @@ static void setScissor(int viewportHeight, const SkIRect& clip) {
}
static void GetFboDetails(SkCanvas* canvas, GLuint* outFboID, SkISize* outFboSize) {
- GrBackendRenderTarget renderTarget = canvas->topLayerBackendRenderTarget();
+ GrBackendRenderTarget renderTarget = skgpu::ganesh::TopLayerBackendRenderTarget(canvas);
GrGLFramebufferInfo fboInfo;
LOG_ALWAYS_FATAL_IF(!renderTarget.getGLFramebufferInfo(&fboInfo),
"getGLFrameBufferInfo failed");
@@ -76,13 +79,13 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
}
// flush will create a GrRenderTarget if not already present.
- canvas->flush();
+ directContext->flushAndSubmit();
GLuint fboID = 0;
SkISize fboSize;
GetFboDetails(canvas, &fboID, &fboSize);
- SkIRect surfaceBounds = canvas->topLayerBounds();
+ SkIRect surfaceBounds = skgpu::ganesh::TopLayerBounds(canvas);
SkIRect clipBounds = canvas->getDeviceClipBounds();
SkM44 mat4(canvas->getLocalToDevice());
SkRegion clipRegion;
@@ -95,11 +98,12 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
SkImageInfo surfaceInfo =
canvas->imageInfo().makeWH(clipBounds.width(), clipBounds.height());
tmpSurface =
- SkSurface::MakeRenderTarget(directContext, skgpu::Budgeted::kYes, surfaceInfo);
+ SkSurfaces::RenderTarget(directContext, skgpu::Budgeted::kYes, surfaceInfo);
tmpSurface->getCanvas()->clear(SK_ColorTRANSPARENT);
GrGLFramebufferInfo fboInfo;
- if (!tmpSurface->getBackendRenderTarget(SkSurface::kFlushWrite_BackendHandleAccess)
+ if (!SkSurfaces::GetBackendRenderTarget(tmpSurface.get(),
+ SkSurfaces::BackendHandleAccess::kFlushWrite)
.getGLFramebufferInfo(&fboInfo)) {
ALOGW("Unable to extract renderTarget info from offscreen canvas; aborting GLFunctor");
return;
@@ -163,7 +167,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
// GL ops get inserted here if previous flush is missing, which could dirty the stencil
bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(tmpCanvas);
- tmpCanvas->flush(); // need this flush for the single op that draws into the stencil
+ directContext->flushAndSubmit(); // need this flush for the single op that draws into the stencil
// ensure that the framebuffer that the webview will render into is bound before after we
// draw into the stencil
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index da4f66d45a70..9d72c2315198 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -362,7 +362,7 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
}
void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, SkCanvas* canvas,
- float* alphaMultiplier) {
+ float* alphaMultiplier, bool ignoreLayer) {
if (properties.getLeft() != 0 || properties.getTop() != 0) {
canvas->translate(properties.getLeft(), properties.getTop());
}
@@ -378,7 +378,8 @@ void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, S
canvas->concat(*properties.getTransformMatrix());
}
}
- if (Properties::getStretchEffectBehavior() == StretchEffectBehavior::UniformScale) {
+ if (Properties::getStretchEffectBehavior() == StretchEffectBehavior::UniformScale &&
+ !ignoreLayer) {
const StretchEffect& stretch = properties.layerProperties().getStretchEffect();
if (!stretch.isEmpty()) {
canvas->concat(
@@ -388,10 +389,10 @@ void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, S
const bool isLayer = properties.effectiveLayerType() != LayerType::None;
int clipFlags = properties.getClippingFlags();
if (properties.getAlpha() < 1) {
- if (isLayer) {
+ if (isLayer && !ignoreLayer) {
clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
- if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
+ if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering()) || ignoreLayer) {
*alphaMultiplier = properties.getAlpha();
} else {
// savelayer needed to create an offscreen buffer
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
index c7582e734009..818ac45bf346 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
@@ -120,7 +120,7 @@ private:
* Applies the rendering properties of a view onto a SkCanvas.
*/
static void setViewProperties(const RenderProperties& properties, SkCanvas* canvas,
- float* alphaMultiplier);
+ float* alphaMultiplier, bool ignoreLayer = false);
/**
* Stores transform on the canvas at time of recording and is used for
@@ -149,6 +149,11 @@ private:
* display list that is searched for any render nodes with getProjectBackwards==true
*/
SkiaDisplayList* mProjectedDisplayList = nullptr;
+
+ /**
+ * Allow BackdropFilterDrawable to apply same render properties onto SkCanvas.
+ */
+ friend class BackdropFilterDrawable;
};
} // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 00919dc3f22a..b87002371775 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -79,7 +79,7 @@ bool ShaderCache::validateCache(const void* identity, ssize_t size) {
void ShaderCache::initShaderDiskCache(const void* identity, ssize_t size) {
ATRACE_NAME("initShaderDiskCache");
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
// Emulators can switch between different renders either as part of config
// or snapshot migration. Also, program binaries may not work well on some
@@ -88,23 +88,21 @@ void ShaderCache::initShaderDiskCache(const void* identity, ssize_t size) {
mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename));
validateCache(identity, size);
mInitialized = true;
+ if (identity != nullptr && size > 0 && mIDHash.size()) {
+ set(&sIDKey, sizeof(sIDKey), mIDHash.data(), mIDHash.size());
+ }
}
}
void ShaderCache::setFilename(const char* filename) {
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
mFilename = filename;
}
-BlobCache* ShaderCache::getBlobCacheLocked() {
- LOG_ALWAYS_FATAL_IF(!mInitialized, "ShaderCache has not been initialized");
- return mBlobCache.get();
-}
-
sk_sp<SkData> ShaderCache::load(const SkData& key) {
ATRACE_NAME("ShaderCache::load");
size_t keySize = key.size();
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
if (!mInitialized) {
return nullptr;
}
@@ -115,8 +113,7 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) {
if (!valueBuffer) {
return nullptr;
}
- BlobCache* bc = getBlobCacheLocked();
- size_t valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize);
+ size_t valueSize = mBlobCache->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize);
int maxTries = 3;
while (valueSize > mObservedBlobValueSize && maxTries > 0) {
mObservedBlobValueSize = std::min(valueSize, maxValueSize);
@@ -126,7 +123,7 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) {
return nullptr;
}
valueBuffer = newValueBuffer;
- valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize);
+ valueSize = mBlobCache->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize);
maxTries--;
}
if (!valueSize) {
@@ -143,16 +140,17 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) {
return SkData::MakeFromMalloc(valueBuffer, valueSize);
}
-namespace {
-// Helper for BlobCache::set to trace the result.
-void set(BlobCache* cache, const void* key, size_t keySize, const void* value, size_t valueSize) {
- switch (cache->set(key, keySize, value, valueSize)) {
+void ShaderCache::set(const void* key, size_t keySize, const void* value, size_t valueSize) {
+ switch (mBlobCache->set(key, keySize, value, valueSize)) {
case BlobCache::InsertResult::kInserted:
// This is what we expect/hope. It means the cache is large enough.
return;
case BlobCache::InsertResult::kDidClean: {
ATRACE_FORMAT("ShaderCache: evicted an entry to fit {key: %lu value %lu}!", keySize,
valueSize);
+ if (mIDHash.size()) {
+ set(&sIDKey, sizeof(sIDKey), mIDHash.data(), mIDHash.size());
+ }
return;
}
case BlobCache::InsertResult::kNotEnoughSpace: {
@@ -172,22 +170,22 @@ void set(BlobCache* cache, const void* key, size_t keySize, const void* value, s
}
}
}
-} // namespace
void ShaderCache::saveToDiskLocked() {
ATRACE_NAME("ShaderCache::saveToDiskLocked");
if (mInitialized && mBlobCache) {
- if (mIDHash.size()) {
- auto key = sIDKey;
- set(mBlobCache.get(), &key, sizeof(key), mIDHash.data(), mIDHash.size());
- }
+ // The most straightforward way to make ownership shared
+ mMutex.unlock();
+ mMutex.lock_shared();
mBlobCache->writeToFile();
+ mMutex.unlock_shared();
+ mMutex.lock();
}
}
void ShaderCache::store(const SkData& key, const SkData& data, const SkString& /*description*/) {
ATRACE_NAME("ShaderCache::store");
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
mNumShadersCachedInRam++;
ATRACE_FORMAT("HWUI RAM cache: %d shaders", mNumShadersCachedInRam);
@@ -204,11 +202,10 @@ void ShaderCache::store(const SkData& key, const SkData& data, const SkString& /
const void* value = data.data();
- BlobCache* bc = getBlobCacheLocked();
if (mInStoreVkPipelineInProgress) {
if (mOldPipelineCacheSize == -1) {
// Record the initial pipeline cache size stored in the file.
- mOldPipelineCacheSize = bc->get(key.data(), keySize, nullptr, 0);
+ mOldPipelineCacheSize = mBlobCache->get(key.data(), keySize, nullptr, 0);
}
if (mNewPipelineCacheSize != -1 && mNewPipelineCacheSize == valueSize) {
// There has not been change in pipeline cache size. Stop trying to save.
@@ -223,13 +220,13 @@ void ShaderCache::store(const SkData& key, const SkData& data, const SkString& /
mNewPipelineCacheSize = -1;
mTryToStorePipelineCache = true;
}
- set(bc, key.data(), keySize, value, valueSize);
+ set(key.data(), keySize, value, valueSize);
if (!mSavePending && mDeferredSaveDelayMs > 0) {
mSavePending = true;
std::thread deferredSaveThread([this]() {
usleep(mDeferredSaveDelayMs * 1000); // milliseconds to microseconds
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
// Store file on disk if there a new shader or Vulkan pipeline cache size changed.
if (mCacheDirty || mNewPipelineCacheSize != mOldPipelineCacheSize) {
saveToDiskLocked();
@@ -245,11 +242,12 @@ void ShaderCache::store(const SkData& key, const SkData& data, const SkString& /
void ShaderCache::onVkFrameFlushed(GrDirectContext* context) {
{
- std::lock_guard<std::mutex> lock(mMutex);
-
+ mMutex.lock_shared();
if (!mInitialized || !mTryToStorePipelineCache) {
+ mMutex.unlock_shared();
return;
}
+ mMutex.unlock_shared();
}
mInStoreVkPipelineInProgress = true;
context->storeVkPipelineCacheData();
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index f5506d60f811..6ccb212fe6ca 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -19,11 +19,14 @@
#include <GrContextOptions.h>
#include <SkRefCnt.h>
#include <cutils/compiler.h>
+#include <ftl/shared_mutex.h>
+#include <utils/Mutex.h>
+
#include <memory>
-#include <mutex>
#include <string>
#include <vector>
+class GrDirectContext;
class SkData;
namespace android {
@@ -94,25 +97,23 @@ private:
void operator=(const ShaderCache&) = delete;
/**
- * "getBlobCacheLocked" returns the BlobCache object being used to store the
- * key/value blob pairs. If the BlobCache object has not yet been created,
- * this will do so, loading the serialized cache contents from disk if
- * possible.
+ * "validateCache" updates the cache to match the given identity. If the
+ * cache currently has the wrong identity, all entries in the cache are cleared.
*/
- BlobCache* getBlobCacheLocked();
+ bool validateCache(const void* identity, ssize_t size) REQUIRES(mMutex);
/**
- * "validateCache" updates the cache to match the given identity. If the
- * cache currently has the wrong identity, all entries in the cache are cleared.
+ * Helper for BlobCache::set to trace the result and ensure the identity hash
+ * does not get evicted.
*/
- bool validateCache(const void* identity, ssize_t size);
+ void set(const void* key, size_t keySize, const void* value, size_t valueSize) REQUIRES(mMutex);
/**
- * "saveToDiskLocked" attemps to save the current contents of the cache to
+ * "saveToDiskLocked" attempts to save the current contents of the cache to
* disk. If the identity hash exists, we will insert the identity hash into
* the cache for next validation.
*/
- void saveToDiskLocked();
+ void saveToDiskLocked() REQUIRES(mMutex);
/**
* "mInitialized" indicates whether the ShaderCache is in the initialized
@@ -122,16 +123,14 @@ private:
* the load and store methods will return without performing any cache
* operations.
*/
- bool mInitialized = false;
+ bool mInitialized GUARDED_BY(mMutex) = false;
/**
- * "mBlobCache" is the cache in which the key/value blob pairs are stored. It
- * is initially NULL, and will be initialized by getBlobCacheLocked the
- * first time it's needed.
- * The blob cache contains the Android build number. We treat version mismatches as an empty
- * cache (logic implemented in BlobCache::unflatten).
+ * "mBlobCache" is the cache in which the key/value blob pairs are stored.
+ * The blob cache contains the Android build number. We treat version mismatches
+ * as an empty cache (logic implemented in BlobCache::unflatten).
*/
- std::unique_ptr<FileBlobCache> mBlobCache;
+ std::unique_ptr<FileBlobCache> mBlobCache GUARDED_BY(mMutex);
/**
* "mFilename" is the name of the file for storing cache contents in between
@@ -140,7 +139,7 @@ private:
* empty string indicates that the cache should not be saved to or restored
* from disk.
*/
- std::string mFilename;
+ std::string mFilename GUARDED_BY(mMutex);
/**
* "mIDHash" is the current identity hash for the cache validation. It is
@@ -149,7 +148,7 @@ private:
* indicates that cache validation is not performed, and the hash should
* not be stored on disk.
*/
- std::vector<uint8_t> mIDHash;
+ std::vector<uint8_t> mIDHash GUARDED_BY(mMutex);
/**
* "mSavePending" indicates whether or not a deferred save operation is
@@ -159,7 +158,7 @@ private:
* contents to disk, unless mDeferredSaveDelayMs is 0 in which case saving
* is disabled.
*/
- bool mSavePending = false;
+ bool mSavePending GUARDED_BY(mMutex) = false;
/**
* "mObservedBlobValueSize" is the maximum value size observed by the cache reading function.
@@ -174,16 +173,16 @@ private:
unsigned int mDeferredSaveDelayMs = 4 * 1000;
/**
- * "mMutex" is the mutex used to prevent concurrent access to the member
+ * "mMutex" is the shared mutex used to prevent concurrent access to the member
* variables. It must be locked whenever the member variables are accessed.
*/
- mutable std::mutex mMutex;
+ mutable ftl::SharedMutex mMutex;
/**
* If set to "true", the next call to onVkFrameFlushed, will invoke
* GrCanvas::storeVkPipelineCacheData. This does not guarantee that data will be stored on disk.
*/
- bool mTryToStorePipelineCache = true;
+ bool mTryToStorePipelineCache GUARDED_BY(mMutex) = true;
/**
* This flag is used by "ShaderCache::store" to distinguish between shader data and
@@ -195,16 +194,16 @@ private:
* "mNewPipelineCacheSize" has the size of the new Vulkan pipeline cache data. It is used
* to prevent unnecessary disk writes, if the pipeline cache size has not changed.
*/
- size_t mNewPipelineCacheSize = -1;
+ size_t mNewPipelineCacheSize GUARDED_BY(mMutex) = -1;
/**
* "mOldPipelineCacheSize" has the size of the Vulkan pipeline cache data stored on disk.
*/
- size_t mOldPipelineCacheSize = -1;
+ size_t mOldPipelineCacheSize GUARDED_BY(mMutex) = -1;
/**
* "mCacheDirty" is true when there is new shader cache data, which is not saved to disk.
*/
- bool mCacheDirty = false;
+ bool mCacheDirty GUARDED_BY(mMutex) = false;
/**
* "sCache" is the singleton ShaderCache object.
@@ -221,7 +220,7 @@ private:
* interesting to keep track of how many shaders are stored in RAM. This
* class provides a convenient entry point for that.
*/
- int mNumShadersCachedInRam = 0;
+ int mNumShadersCachedInRam GUARDED_BY(mMutex) = 0;
friend class ShaderCacheTestUtils; // used for unit testing
};
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index c4d3f5cedfa8..23b3074435cf 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -16,6 +16,7 @@
#include "SkiaOpenGLPipeline.h"
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <GrBackendSurface.h>
#include <SkBlendMode.h>
#include <SkImageInfo.h>
@@ -68,12 +69,15 @@ MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
return MakeCurrentResult::AlreadyCurrent;
}
- // Make sure read/draw buffer state of default framebuffer is GL_BACK. Vendor implementations
+ EGLint majorVersion = 0;
+ eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(), EGL_CONTEXT_CLIENT_VERSION, &majorVersion);
+
+ // Make sure read/draw buffer state of default framebuffer is GL_BACK for ES 3.X. Vendor implementations
// disagree on the draw/read buffer state if the default framebuffer transitions from a surface
// to EGL_NO_SURFACE and vice-versa. There was a related discussion within Khronos on this topic.
// See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13534.
// The discussion was not resolved with a clear consensus
- if (error == 0 && wasSurfaceless && mEglSurface != EGL_NO_SURFACE) {
+ if (error == 0 && (majorVersion > 2) && wasSurfaceless && mEglSurface != EGL_NO_SURFACE) {
GLint curReadFB = 0;
GLint curDrawFB = 0;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &curReadFB);
@@ -147,9 +151,9 @@ IRenderPipeline::DrawResult SkiaOpenGLPipeline::draw(
surface = getBufferSkSurface(bufferParams);
preTransform = bufferParams.getTransform();
} else {
- surface = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(), backendRT,
- getSurfaceOrigin(), colorType,
- mSurfaceColorSpace, &props);
+ surface = SkSurfaces::WrapBackendRenderTarget(mRenderThread.getGrContext(), backendRT,
+ getSurfaceOrigin(), colorType,
+ mSurfaceColorSpace, &props);
preTransform = SkMatrix::I();
}
@@ -171,7 +175,7 @@ IRenderPipeline::DrawResult SkiaOpenGLPipeline::draw(
{
ATRACE_NAME("flush commands");
- surface->flushAndSubmit();
+ skgpu::ganesh::FlushAndSubmit(surface);
}
layerUpdateQueue->clear();
@@ -242,8 +246,7 @@ bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBeh
if (mEglSurface != EGL_NO_SURFACE) {
const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
- const bool isPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
- ALOGE_IF(preserveBuffer != isPreserved, "Unable to match the desired swap behavior.");
+ mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
return true;
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index b020e966e05a..3d77877cf6eb 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -16,14 +16,15 @@
#include "SkiaPipeline.h"
+#include <include/android/SkSurfaceAndroid.h>
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <SkCanvas.h>
#include <SkColor.h>
#include <SkColorSpace.h>
#include <SkData.h>
#include <SkImage.h>
-#include <SkImageEncoder.h>
+#include <SkImageAndroid.h>
#include <SkImageInfo.h>
-#include <SkImagePriv.h>
#include <SkMatrix.h>
#include <SkMultiPictureDocument.h>
#include <SkOverdrawCanvas.h>
@@ -75,7 +76,7 @@ bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) {
return false;
}
for (SkImage* image : mutableImages) {
- if (SkImage_pinAsTexture(image, mRenderThread.getGrContext())) {
+ if (skgpu::ganesh::PinAsTexture(mRenderThread.getGrContext(), image)) {
mPinnedImages.emplace_back(sk_ref_sp(image));
} else {
return false;
@@ -86,7 +87,7 @@ bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) {
void SkiaPipeline::unpinImages() {
for (auto& image : mPinnedImages) {
- SkImage_unpinAsTexture(image.get(), mRenderThread.getGrContext());
+ skgpu::ganesh::UnpinTexture(mRenderThread.getGrContext(), image.get());
}
mPinnedImages.clear();
}
@@ -187,9 +188,9 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator
kPremul_SkAlphaType, getSurfaceColorSpace());
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
- node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- skgpu::Budgeted::kYes, info, 0,
- this->getSurfaceOrigin(), &props));
+ node->setLayerSurface(SkSurfaces::RenderTarget(mRenderThread.getGrContext(),
+ skgpu::Budgeted::kYes, info, 0,
+ this->getSurfaceOrigin(), &props));
if (node->getLayerSurface()) {
// update the transform in window of the layer to reset its origin wrt light source
// position
@@ -222,8 +223,8 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
auto image = bitmap->makeImage();
if (image.get()) {
- SkImage_pinAsTexture(image.get(), context);
- SkImage_unpinAsTexture(image.get(), context);
+ skgpu::ganesh::PinAsTexture(context, image.get());
+ skgpu::ganesh::UnpinTexture(context, image.get());
// A submit is necessary as there may not be a frame coming soon, so without a call
// to submit these texture uploads can just sit in the queue building up until
// we run out of RAM
@@ -621,7 +622,7 @@ sk_sp<SkSurface> SkiaPipeline::getBufferSkSurface(
auto bufferColorSpace = bufferParams.getColorSpace();
if (mBufferSurface == nullptr || mBufferColorSpace == nullptr ||
!SkColorSpace::Equals(mBufferColorSpace.get(), bufferColorSpace.get())) {
- mBufferSurface = SkSurface::MakeFromAHardwareBuffer(
+ mBufferSurface = SkSurfaces::WrapAndroidHardwareBuffer(
mRenderThread.getGrContext(), mHardwareBuffer, kTopLeft_GrSurfaceOrigin,
bufferColorSpace, nullptr, true);
mBufferColorSpace = bufferColorSpace;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 3ca7eeb37a89..e917f9a66917 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -37,6 +37,7 @@
#include "NinePatchUtils.h"
#include "RenderNode.h"
#include "pipeline/skia/AnimatedDrawables.h"
+#include "pipeline/skia/BackdropFilterDrawable.h"
#ifdef __ANDROID__ // Layoutlib does not support GL, Vulcan etc.
#include "pipeline/skia/GLFunctorDrawable.h"
#include "pipeline/skia/VkFunctorDrawable.h"
@@ -168,6 +169,14 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
// Put Vulkan WebViews with non-rectangular clips in a HW layer
renderNode->mutateStagingProperties().setClipMayBeComplex(mRecorder.isClipMayBeComplex());
}
+
+ // draw backdrop filter drawable if needed.
+ if (renderNode->stagingProperties().layerProperties().getBackdropImageFilter()) {
+ auto* backdropFilterDrawable =
+ mDisplayList->allocateDrawable<BackdropFilterDrawable>(renderNode, asSkCanvas());
+ drawDrawable(backdropFilterDrawable);
+ }
+
drawDrawable(&renderNodeDrawable);
// use staging property, since recording on UI thread
@@ -227,6 +236,17 @@ void SkiaRecordingCanvas::handleMutableImages(Bitmap& bitmap, DrawImagePayload&
}
}
+void SkiaRecordingCanvas::onFilterPaint(android::Paint& paint) {
+ INHERITED::onFilterPaint(paint);
+ SkShader* shader = paint.getShader();
+ // TODO(b/264559422): This only works for very specifically a BitmapShader.
+ // It's better than nothing, though
+ SkImage* image = shader ? shader->isAImage(nullptr, nullptr) : nullptr;
+ if (image) {
+ mDisplayList->mMutableImages.push_back(image);
+ }
+}
+
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
auto payload = DrawImagePayload(bitmap);
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index a8e4580dc200..3bd091df1ece 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -105,6 +105,8 @@ private:
void handleMutableImages(Bitmap& bitmap, DrawImagePayload& payload);
+ void onFilterPaint(Paint& paint) override;
+
using INHERITED = SkiaCanvas;
};
diff --git a/libs/hwui/pipeline/skia/StretchMask.cpp b/libs/hwui/pipeline/skia/StretchMask.cpp
index cad3703d8d2b..1676787ef671 100644
--- a/libs/hwui/pipeline/skia/StretchMask.cpp
+++ b/libs/hwui/pipeline/skia/StretchMask.cpp
@@ -18,14 +18,13 @@
#include "SkBlendMode.h"
#include "SkCanvas.h"
#include "SkSurface.h"
-#include "include/gpu/GpuTypes.h" // from Skia
#include "TransformCanvas.h"
#include "SkiaDisplayList.h"
using android::uirenderer::StretchMask;
-void StretchMask::draw(GrRecordingContext* context,
+void StretchMask::draw(GrRecordingContext*,
const StretchEffect& stretch,
const SkRect& bounds,
skiapipeline::SkiaDisplayList* displayList,
@@ -35,16 +34,14 @@ void StretchMask::draw(GrRecordingContext* context,
if (mMaskSurface == nullptr || mMaskSurface->width() != width ||
mMaskSurface->height() != height) {
// Create a new surface if we don't have one or our existing size does
- // not match.
- mMaskSurface = SkSurface::MakeRenderTarget(
- context,
- skgpu::Budgeted::kYes,
- SkImageInfo::Make(
- width,
- height,
- SkColorType::kAlpha_8_SkColorType,
- SkAlphaType::kPremul_SkAlphaType)
- );
+ // not match. SkCanvas::makeSurface returns a new surface that will
+ // be GPU-backed if canvas was also.
+ mMaskSurface = canvas->makeSurface(SkImageInfo::Make(
+ width,
+ height,
+ SkColorType::kAlpha_8_SkColorType,
+ SkAlphaType::kPremul_SkAlphaType
+ ));
mIsDirty = true;
}
@@ -53,7 +50,7 @@ void StretchMask::draw(GrRecordingContext* context,
// Make sure to apply target transformation to the mask canvas
// to ensure the replayed drawing commands generate the same result
auto previousMatrix = displayList->mParentMatrix;
- displayList->mParentMatrix = maskCanvas->getTotalMatrix();
+ displayList->mParentMatrix = maskCanvas->getLocalToDeviceAs3x3();
maskCanvas->save();
maskCanvas->drawColor(0, SkBlendMode::kClear);
TransformCanvas transformCanvas(maskCanvas, SkBlendMode::kSrcOver);
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index adf3c06b8624..475b110604e4 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -35,6 +35,8 @@
#include "effects/GainmapRenderer.h"
#include <SkBlendMode.h>
+#include <SkImage.h>
+#include <SkImageAndroid.h>
namespace android {
namespace uirenderer {
@@ -183,9 +185,9 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
// drawing into the offscreen surface, so we need to reset it here.
canvas->resetMatrix();
- auto functorImage = SkImage::MakeFromAHardwareBuffer(mFrameBuffer.get(), kPremul_SkAlphaType,
- canvas->imageInfo().refColorSpace(),
- kBottomLeft_GrSurfaceOrigin);
+ auto functorImage = SkImages::DeferredFromAHardwareBuffer(
+ mFrameBuffer.get(), kPremul_SkAlphaType, canvas->imageInfo().refColorSpace(),
+ kBottomLeft_GrSurfaceOrigin);
canvas->drawImage(functorImage, 0, 0, SkSamplingOptions(), &paint);
canvas->restore();
}
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index babce88b8e1e..8f81dbad2320 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -277,12 +277,13 @@ void CacheManager::onThreadIdle() {
const nsecs_t now = systemTime(CLOCK_MONOTONIC);
// Rate limiting
- if ((now - mLastDeferredCleanup) < 25_ms) {
+ if ((now - mLastDeferredCleanup) > 25_ms) {
mLastDeferredCleanup = now;
const nsecs_t frameCompleteNanos = mFrameCompletions[0];
const nsecs_t frameDiffNanos = now - frameCompleteNanos;
const nsecs_t cleanupMillis =
- ns2ms(std::max(frameDiffNanos, mMemoryPolicy.minimumResourceRetention));
+ ns2ms(std::clamp(frameDiffNanos, mMemoryPolicy.minimumResourceRetention,
+ mMemoryPolicy.maximumResourceRetention));
mGrContext->performDeferredCleanup(std::chrono::milliseconds(cleanupMillis),
mMemoryPolicy.purgeScratchOnly);
}
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index 5e43ac209696..bcfa4f359d83 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -64,12 +64,13 @@ public:
void unregisterCanvasContext(CanvasContext* context);
void onContextStopped(CanvasContext* context);
+ bool areAllContextsStopped();
+
private:
friend class RenderThread;
explicit CacheManager(RenderThread& thread);
void setupCacheLimits();
- bool areAllContextsStopped();
void checkUiHidden();
void scheduleDestroyContext();
void cancelDestroyContext();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 16b35ffcabac..2ef7802c0a3c 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -125,6 +125,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode*
, mRenderPipeline(std::move(renderPipeline))
, mHintSessionWrapper(uiThreadId, renderThreadId) {
mRenderThread.cacheManager().registerCanvasContext(this);
+ mRenderThread.renderState().registerContextCallback(this);
rootRenderNode->makeRoot();
mRenderNodes.emplace_back(rootRenderNode);
mProfiler.setDensity(DeviceInfo::getDensity());
@@ -137,6 +138,7 @@ CanvasContext::~CanvasContext() {
}
mRenderNodes.clear();
mRenderThread.cacheManager().unregisterCanvasContext(this);
+ mRenderThread.renderState().removeContextCallback(this);
}
void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) {
@@ -405,8 +407,17 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
// If the previous frame was dropped we don't need to hold onto it, so
// just keep using the previous frame's structure instead
- if (!wasSkipped(mCurrentFrameInfo)) {
+ if (wasSkipped(mCurrentFrameInfo)) {
+ // Use the oldest skipped frame in case we skip more than a single frame
+ if (!mSkippedFrameInfo) {
+ mSkippedFrameInfo.emplace();
+ mSkippedFrameInfo->vsyncId =
+ mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId);
+ mSkippedFrameInfo->startTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime);
+ }
+ } else {
mCurrentFrameInfo = mJankTracker.startFrame();
+ mSkippedFrameInfo.reset();
}
mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
@@ -602,10 +613,18 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) {
if (vsyncId != UiFrameInfoBuilder::INVALID_VSYNC_ID) {
const auto inputEventId =
static_cast<int32_t>(mCurrentFrameInfo->get(FrameInfoIndex::InputEventId));
- native_window_set_frame_timeline_info(
- mNativeSurface->getNativeWindow(), frameCompleteNr, vsyncId, inputEventId,
- mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime),
- solelyTextureViewUpdates);
+ const ANativeWindowFrameTimelineInfo ftl = {
+ .frameNumber = frameCompleteNr,
+ .frameTimelineVsyncId = vsyncId,
+ .inputEventId = inputEventId,
+ .startTimeNanos = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime),
+ .useForRefreshRateSelection = solelyTextureViewUpdates,
+ .skippedFrameVsyncId = mSkippedFrameInfo ? mSkippedFrameInfo->vsyncId
+ : UiFrameInfoBuilder::INVALID_VSYNC_ID,
+ .skippedFrameStartTimeNanos =
+ mSkippedFrameInfo ? mSkippedFrameInfo->startTime : 0,
+ };
+ native_window_set_frame_timeline_info(mNativeSurface->getNativeWindow(), ftl);
}
}
@@ -946,6 +965,10 @@ void CanvasContext::destroyHardwareResources() {
}
}
+void CanvasContext::onContextDestroyed() {
+ destroyHardwareResources();
+}
+
DeferredLayerUpdater* CanvasContext::createTextureLayer() {
return mRenderPipeline->createTextureLayer();
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 5219b5757008..3f02674d3b53 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -43,6 +43,7 @@
#include "Lighting.h"
#include "ReliableSurface.h"
#include "RenderNode.h"
+#include "renderstate/RenderState.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
#include "utils/RingBuffer.h"
@@ -64,7 +65,7 @@ class Frame;
// This per-renderer class manages the bridge between the global EGL context
// and the render surface.
// TODO: Rename to Renderer or some other per-window, top-level manager
-class CanvasContext : public IFrameCallback {
+class CanvasContext : public IFrameCallback, public IGpuContextCallback {
public:
static CanvasContext* create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
IContextFactory* contextFactory, pid_t uiThreadId,
@@ -154,6 +155,7 @@ public:
void markLayerInUse(RenderNode* node);
void destroyHardwareResources();
+ void onContextDestroyed() override;
DeferredLayerUpdater* createTextureLayer();
@@ -366,6 +368,12 @@ private:
ColorMode mColorMode = ColorMode::Default;
float mTargetSdrHdrRatio = 1.f;
+
+ struct SkippedFrameInfo {
+ int64_t vsyncId;
+ int64_t startTime;
+ };
+ std::optional<SkippedFrameInfo> mSkippedFrameInfo;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 224c878bf43d..f949dddd8b44 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -16,7 +16,13 @@
#include "RenderProxy.h"
+#include <SkBitmap.h>
+#include <SkImage.h>
+#include <SkPicture.h>
#include <gui/TraceUtils.h>
+#include <pthread.h>
+#include <ui/GraphicBufferAllocator.h>
+
#include "DeferredLayerUpdater.h"
#include "DisplayList.h"
#include "Properties.h"
@@ -29,12 +35,6 @@
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
-#include <SkBitmap.h>
-#include <SkImage.h>
-#include <SkPicture.h>
-
-#include <pthread.h>
-
namespace android {
namespace uirenderer {
namespace renderthread {
@@ -323,6 +323,9 @@ void RenderProxy::dumpGraphicsMemory(int fd, bool includeProfileData, bool reset
}
});
}
+ std::string grallocInfo;
+ GraphicBufferAllocator::getInstance().dump(grallocInfo);
+ dprintf(fd, "%s\n", grallocInfo.c_str());
}
void RenderProxy::getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage) {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 46698a6fdcc0..f3409455d401 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -24,6 +24,7 @@
#include <GrTypes.h>
#include <android/sync.h>
#include <gui/TraceUtils.h>
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <ui/FatVector.h>
#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
@@ -518,7 +519,7 @@ Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) {
// The following flush blocks the GPU immediately instead of waiting for
// other drawing ops. It seems dequeue_fence is not respected otherwise.
// TODO: remove the flush after finding why backendSemaphore is not working.
- bufferInfo->skSurface->flushAndSubmit();
+ skgpu::ganesh::FlushAndSubmit(bufferInfo->skSurface);
}
}
}
@@ -586,10 +587,10 @@ nsecs_t VulkanManager::finishFrame(SkSurface* surface) {
} else {
semaphore = VK_NULL_HANDLE;
}
- GrSemaphoresSubmitted submitted =
- surface->flush(SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
GrDirectContext* context = GrAsDirectContext(surface->recordingContext());
ALOGE_IF(!context, "Surface is not backed by gpu");
+ GrSemaphoresSubmitted submitted = context->flush(
+ surface, SkSurfaces::BackendSurfaceAccess::kPresent, flushInfo);
context->submit();
const nsecs_t submissionTime = systemTime();
if (semaphore != VK_NULL_HANDLE) {
@@ -599,7 +600,8 @@ nsecs_t VulkanManager::finishFrame(SkSurface* surface) {
// retrieve VkImage used as render target
VkImage image = VK_NULL_HANDLE;
GrBackendRenderTarget backendRenderTarget =
- surface->getBackendRenderTarget(SkSurface::kFlushRead_BackendHandleAccess);
+ SkSurfaces::GetBackendRenderTarget(
+ surface, SkSurfaces::BackendHandleAccess::kFlushRead);
if (backendRenderTarget.isValid()) {
GrVkImageInfo info;
if (backendRenderTarget.getVkImageInfo(&info)) {
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 3168cb09291b..b0ba619c63a4 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -16,6 +16,7 @@
#include "VulkanSurface.h"
+#include <include/android/SkSurfaceAndroid.h>
#include <GrDirectContext.h>
#include <SkSurface.h>
#include <algorithm>
@@ -470,12 +471,12 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
surfaceProps = SkSurfaceProps(SkSurfaceProps::kAlwaysDither_Flag | surfaceProps.flags(),
surfaceProps.pixelGeometry());
}
- bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
+ bufferInfo->skSurface = SkSurfaces::WrapAndroidHardwareBuffer(
mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, &surfaceProps,
/*from_window=*/true);
if (bufferInfo->skSurface.get() == nullptr) {
- ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
+ ALOGE("SkSurfaces::WrapAndroidHardwareBuffer failed");
mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer,
mNativeBuffers[idx].dequeue_fence.release());
mNativeBuffers[idx].dequeued = false;
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 81ecfe59d3bc..ffc664c2e1bc 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -61,18 +61,10 @@ namespace uirenderer {
ADD_FAILURE() << "ClipState not a rect"; \
}
-#define INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, functionCall) \
- TEST(test_case_name, test_name##_##pipeline) { \
- RenderPipelineType oldType = Properties::getRenderPipelineType(); \
- Properties::overrideRenderPipelineType(RenderPipelineType::pipeline); \
- functionCall; \
- Properties::overrideRenderPipelineType(oldType); \
- };
-
-#define INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, pipeline) \
- INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, \
- TestUtils::runOnRenderThread( \
- test_case_name##_##test_name##_RenderThreadTest::doTheThing))
+#define INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name) \
+ TEST(test_case_name, test_name) { \
+ TestUtils::runOnRenderThread(test_case_name##_##test_name##_RenderThreadTest::doTheThing); \
+ }
/**
* Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope
@@ -83,21 +75,7 @@ namespace uirenderer {
public: \
static void doTheThing(renderthread::RenderThread& renderThread); \
}; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
- /* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
- /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
- void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
- renderthread::RenderThread& renderThread)
-
-/**
- * Like RENDERTHREAD_TEST, but only runs with the Skia RenderPipelineTypes
- */
-#define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_RenderThreadTest { \
- public: \
- static void doTheThing(renderthread::RenderThread& renderThread); \
- }; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name); \
/* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
/* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
@@ -307,13 +285,21 @@ public:
int destroyed = 0;
int removeOverlays = 0;
int glesDraw = 0;
+ int vkInitialize = 0;
+ int vkDraw = 0;
+ int vkPostDraw = 0;
};
static void expectOnRenderThread(const std::string_view& function = "unknown") {
EXPECT_EQ(gettid(), TestUtils::getRenderThreadTid()) << "Called on wrong thread: " << function;
}
- static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) {
+ static int createMockFunctor() {
+ const auto renderMode = WebViewFunctor_queryPlatformRenderMode();
+ return WebViewFunctor_create(nullptr, createMockFunctorCallbacks(renderMode), renderMode);
+ }
+
+ static WebViewFunctorCallbacks createMockFunctorCallbacks(RenderMode mode) {
auto callbacks = WebViewFunctorCallbacks{
.onSync =
[](int functor, void* client_data, const WebViewSyncData& data) {
@@ -345,9 +331,22 @@ public:
sMockFunctorCounts[functor].glesDraw++;
};
break;
- default:
- ADD_FAILURE();
- return WebViewFunctorCallbacks{};
+ case RenderMode::Vulkan:
+ callbacks.vk.initialize = [](int functor, void* data,
+ const VkFunctorInitParams& params) {
+ expectOnRenderThread("initialize");
+ sMockFunctorCounts[functor].vkInitialize++;
+ };
+ callbacks.vk.draw = [](int functor, void* data, const VkFunctorDrawParams& params,
+ const WebViewOverlayData& overlayParams) {
+ expectOnRenderThread("draw");
+ sMockFunctorCounts[functor].vkDraw++;
+ };
+ callbacks.vk.postDraw = [](int functor, void* data) {
+ expectOnRenderThread("postDraw");
+ sMockFunctorCounts[functor].vkPostDraw++;
+ };
+ break;
}
return callbacks;
}
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index f3f32eb6897c..e227999c2432 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -14,30 +14,32 @@
* limitations under the License.
*/
-#include "tests/common/LeakChecker.h"
-#include "tests/common/TestScene.h"
-
-#include "Properties.h"
-#include "hwui/Typeface.h"
-#include "HardwareBitmapUploader.h"
-#include "renderthread/RenderProxy.h"
-
+#include <android-base/parsebool.h>
#include <benchmark/benchmark.h>
+#include <errno.h>
+#include <fcntl.h>
#include <fnmatch.h>
#include <getopt.h>
#include <pthread.h>
#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
+
+#include <regex>
#include <string>
#include <unordered_map>
#include <vector>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
+#include "HardwareBitmapUploader.h"
+#include "Properties.h"
+#include "hwui/Typeface.h"
+#include "renderthread/RenderProxy.h"
+#include "tests/common/LeakChecker.h"
+#include "tests/common/TestScene.h"
using namespace android;
+using namespace android::base;
using namespace android::uirenderer;
using namespace android::uirenderer::test;
@@ -69,6 +71,9 @@ OPTIONS:
--onscreen Render tests on device screen. By default tests
are offscreen rendered
--benchmark_format Set output format. Possible values are tabular, json, csv
+ --benchmark_list_tests Lists the tests that would run but does not run them
+ --benchmark_filter=<regex> Filters the test set to the given regex. If prefixed with `-` and test
+ that doesn't match the given regex is run
--renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk
--skip-leak-check Skips the memory leak check
--report-gpu-memory[=verbose] Dumps the GPU memory usage after each test run
@@ -140,6 +145,9 @@ static bool setBenchmarkFormat(const char* format) {
if (!strcmp(format, "tabular")) {
gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
} else if (!strcmp(format, "json")) {
+ // We cannot print the leak check if outputing to JSON as that will break
+ // JSON parsers since it's not JSON-formatted
+ gRunLeakCheck = false;
gBenchmarkReporter.reset(new benchmark::JSONReporter());
} else {
fprintf(stderr, "Unknown format '%s'\n", format);
@@ -160,6 +168,24 @@ static bool setRenderer(const char* renderer) {
return true;
}
+static void addTestsThatMatchFilter(std::string spec) {
+ if (spec.empty() || spec == "all") {
+ spec = "."; // Regexp that matches all benchmarks
+ }
+ bool isNegativeFilter = false;
+ if (spec[0] == '-') {
+ spec.replace(0, 1, "");
+ isNegativeFilter = true;
+ }
+ std::regex re(spec, std::regex_constants::extended);
+ for (auto& iter : TestScene::testMap()) {
+ if ((isNegativeFilter && !std::regex_search(iter.first, re)) ||
+ (!isNegativeFilter && std::regex_search(iter.first, re))) {
+ gRunTests.push_back(iter.second);
+ }
+ }
+}
+
// For options that only exist in long-form. Anything in the
// 0-255 range is reserved for short options (which just use their ASCII value)
namespace LongOpts {
@@ -170,6 +196,8 @@ enum {
ReportFrametime,
CpuSet,
BenchmarkFormat,
+ BenchmarkListTests,
+ BenchmarkFilter,
Onscreen,
Offscreen,
Renderer,
@@ -179,14 +207,16 @@ enum {
}
static const struct option LONG_OPTIONS[] = {
- {"frames", required_argument, nullptr, 'f'},
- {"repeat", required_argument, nullptr, 'r'},
+ {"count", required_argument, nullptr, 'c'},
+ {"runs", required_argument, nullptr, 'r'},
{"help", no_argument, nullptr, 'h'},
{"list", no_argument, nullptr, LongOpts::List},
{"wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu},
{"report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime},
{"cpuset", required_argument, nullptr, LongOpts::CpuSet},
{"benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat},
+ {"benchmark_list_tests", optional_argument, nullptr, LongOpts::BenchmarkListTests},
+ {"benchmark_filter", required_argument, nullptr, LongOpts::BenchmarkFilter},
{"onscreen", no_argument, nullptr, LongOpts::Onscreen},
{"offscreen", no_argument, nullptr, LongOpts::Offscreen},
{"renderer", required_argument, nullptr, LongOpts::Renderer},
@@ -197,8 +227,12 @@ static const struct option LONG_OPTIONS[] = {
static const char* SHORT_OPTIONS = "c:r:h";
void parseOptions(int argc, char* argv[]) {
+ benchmark::BenchmarkReporter::Context::executable_name = (argc > 0) ? argv[0] : "unknown";
+
int c;
bool error = false;
+ bool listTestsOnly = false;
+ bool testsAreFiltered = false;
opterr = 0;
while (true) {
@@ -272,6 +306,21 @@ void parseOptions(int argc, char* argv[]) {
}
break;
+ case LongOpts::BenchmarkListTests:
+ if (!optarg || ParseBool(optarg) == ParseBoolResult::kTrue) {
+ listTestsOnly = true;
+ }
+ break;
+
+ case LongOpts::BenchmarkFilter:
+ if (!optarg) {
+ error = true;
+ break;
+ }
+ addTestsThatMatchFilter(optarg);
+ testsAreFiltered = true;
+ break;
+
case LongOpts::Renderer:
if (!optarg) {
error = true;
@@ -346,11 +395,18 @@ void parseOptions(int argc, char* argv[]) {
}
}
} while (optind < argc);
- } else {
+ } else if (gRunTests.empty() && !testsAreFiltered) {
for (auto& iter : TestScene::testMap()) {
gRunTests.push_back(iter.second);
}
}
+
+ if (listTestsOnly) {
+ for (auto& iter : gRunTests) {
+ std::cout << iter.name << std::endl;
+ }
+ exit(EXIT_SUCCESS);
+ }
}
int main(int argc, char* argv[]) {
diff --git a/libs/hwui/tests/unit/AutoBackendTextureReleaseTests.cpp b/libs/hwui/tests/unit/AutoBackendTextureReleaseTests.cpp
index 138b3efd10ed..b8b3f0aa5229 100644
--- a/libs/hwui/tests/unit/AutoBackendTextureReleaseTests.cpp
+++ b/libs/hwui/tests/unit/AutoBackendTextureReleaseTests.cpp
@@ -46,7 +46,7 @@ RENDERTHREAD_TEST(AutoBackendTextureRelease, makeImage_invalid) {
EXPECT_EQ(1, TestUtils::getUsageCount(textureRelease));
- // SkImage::MakeFromTexture should fail if given null GrDirectContext.
+ // SkImages::BorrowTextureFrom should fail if given null GrDirectContext.
textureRelease->makeImage(buffer, HAL_DATASPACE_UNKNOWN, /*context = */ nullptr);
EXPECT_EQ(1, TestUtils::getUsageCount(textureRelease));
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index 2b90bda87ecd..89d00d3c0dcb 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -20,7 +20,8 @@
#include "renderthread/EglManager.h"
#include "tests/common/TestUtils.h"
-#include <SkImagePriv.h>
+#include <SkImageAndroid.h>
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include "include/gpu/GpuTypes.h" // from Skia
using namespace android;
@@ -34,7 +35,7 @@ static size_t getCacheUsage(GrDirectContext* grContext) {
}
// TOOD(258700630): fix this test and re-enable
-RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, DISABLED_trimMemory) {
+RENDERTHREAD_TEST(CacheManager, DISABLED_trimMemory) {
int32_t width = DeviceInfo::get()->getWidth();
int32_t height = DeviceInfo::get()->getHeight();
GrDirectContext* grContext = renderThread.getGrContext();
@@ -46,8 +47,8 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, DISABLED_trimMemory) {
while (getCacheUsage(grContext) <= renderThread.cacheManager().getBackgroundCacheSize()) {
SkImageInfo info = SkImageInfo::MakeA8(width, height);
- sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(grContext, skgpu::Budgeted::kYes,
- info);
+ sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kYes,
+ info);
surface->getCanvas()->drawColor(SK_AlphaTRANSPARENT);
grContext->flushAndSubmit();
@@ -57,9 +58,8 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, DISABLED_trimMemory) {
// create an image and pin it so that we have something with a unique key in the cache
sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(SkImageInfo::MakeA8(width, height));
- sk_sp<SkImage> image = bitmap->makeImage();
- ASSERT_TRUE(SkImage_pinAsTexture(image.get(), grContext));
-
+ sk_sp<SkImage> image = bitmap->makeImage(); // calls skgpu::ganesh::PinAsTexture under the hood.
+ ASSERT_TRUE(skgpu::ganesh::PinAsTexture(grContext, image.get()));
// attempt to trim all memory while we still hold strong refs
renderThread.cacheManager().trimMemory(TrimLevel::COMPLETE);
ASSERT_TRUE(0 == grContext->getResourceCachePurgeableBytes());
@@ -71,7 +71,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, DISABLED_trimMemory) {
}
// unpin the image which should add a unique purgeable key to the cache
- SkImage_unpinAsTexture(image.get(), grContext);
+ skgpu::ganesh::UnpinTexture(grContext, image.get());
// verify that we have enough purgeable bytes
const size_t purgeableBytes = grContext->getResourceCachePurgeableBytes();
diff --git a/libs/hwui/tests/unit/CanvasContextTests.cpp b/libs/hwui/tests/unit/CanvasContextTests.cpp
index 9e376e32f8ea..47a41057cac9 100644
--- a/libs/hwui/tests/unit/CanvasContextTests.cpp
+++ b/libs/hwui/tests/unit/CanvasContextTests.cpp
@@ -19,6 +19,7 @@
#include "AnimationContext.h"
#include "IContextFactory.h"
#include "renderthread/CanvasContext.h"
+#include "renderthread/VulkanManager.h"
#include "tests/common/TestUtils.h"
using namespace android;
@@ -42,3 +43,38 @@ RENDERTHREAD_TEST(CanvasContext, create) {
canvasContext->destroy();
}
+
+RENDERTHREAD_TEST(CanvasContext, buildLayerDoesntLeak) {
+ auto node = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(0xFFFF0000, SkBlendMode::kSrc);
+ });
+ ASSERT_TRUE(node->isValid());
+ EXPECT_EQ(LayerType::None, node->stagingProperties().effectiveLayerType());
+ node->mutateStagingProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
+
+ auto& cacheManager = renderThread.cacheManager();
+ EXPECT_TRUE(cacheManager.areAllContextsStopped());
+ ContextFactory contextFactory;
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, node.get(), &contextFactory, 0, 0));
+ canvasContext->buildLayer(node.get());
+ EXPECT_TRUE(node->hasLayer());
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ auto instance = VulkanManager::peekInstance();
+ if (instance) {
+ EXPECT_TRUE(instance->hasVkContext());
+ } else {
+ ADD_FAILURE() << "VulkanManager wasn't initialized to buildLayer?";
+ }
+ }
+ renderThread.destroyRenderingContext();
+ EXPECT_FALSE(node->hasLayer()) << "Node still has a layer after rendering context destroyed";
+
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ auto instance = VulkanManager::peekInstance();
+ if (instance) {
+ ADD_FAILURE() << "VulkanManager still exists";
+ EXPECT_FALSE(instance->hasVkContext());
+ }
+ }
+}
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index 0c389bfe8b71..cfa18ae01b4f 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -40,7 +40,7 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) {
// push the deferred updates to the layer
SkBitmap bitmap;
bitmap.allocN32Pixels(16, 16);
- sk_sp<SkImage> layerImage = SkImage::MakeFromBitmap(bitmap);
+ sk_sp<SkImage> layerImage = SkImages::RasterFromBitmap(bitmap);
layerUpdater->updateLayer(true, layerImage, 0, SkRect::MakeEmpty());
// the backing layer should now have all the properties applied.
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 596bd37e4cf5..073a8357e574 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -14,20 +14,22 @@
* limitations under the License.
*/
-#include <VectorDrawable.h>
-#include <gtest/gtest.h>
-
#include <SkBlendMode.h>
#include <SkClipStack.h>
#include <SkSurface_Base.h>
+#include <VectorDrawable.h>
+#include <gtest/gtest.h>
+#include <include/effects/SkImageFilters.h>
#include <string.h>
+
#include "AnimationContext.h"
#include "DamageAccumulator.h"
#include "FatalTestCanvas.h"
#include "IContextFactory.h"
-#include "hwui/Paint.h"
#include "RecordingCanvas.h"
#include "SkiaCanvas.h"
+#include "hwui/Paint.h"
+#include "pipeline/skia/BackdropFilterDrawable.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaPipeline.h"
@@ -141,7 +143,7 @@ TEST(RenderNodeDrawable, zReorder) {
}
TEST(RenderNodeDrawable, composeOnLayer) {
- auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+ auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(1, 1));
SkCanvas& canvas = *surface->getCanvas();
canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
@@ -152,7 +154,7 @@ TEST(RenderNodeDrawable, composeOnLayer) {
});
// attach a layer to the render node
- auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1);
+ auto surfaceLayer = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(1, 1));
auto canvas2 = surfaceLayer->getCanvas();
canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
rootNode->setLayerSurface(surfaceLayer);
@@ -187,7 +189,7 @@ static SkMatrix getRecorderMatrix(const SkiaRecordingCanvas& recorder) {
}
TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore) {
- auto surface = SkSurface::MakeRasterN32Premul(400, 800);
+ auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(400, 800));
SkCanvas& canvas = *surface->getCanvas();
canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
@@ -353,7 +355,7 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
EXPECT_EQ(3, canvas.getIndex());
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) {
+RENDERTHREAD_TEST(RenderNodeDrawable, emptyReceiver) {
class ProjectionTestCanvas : public SkCanvas {
public:
ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
@@ -417,7 +419,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) {
EXPECT_EQ(2, canvas.getDrawCounter());
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
+RENDERTHREAD_TEST(RenderNodeDrawable, projectionHwLayer) {
/* R is backward projected on B and C is a layer.
A
/ \
@@ -1050,7 +1052,7 @@ TEST(RenderNodeDrawable, renderNode) {
}
// Verify that layers are composed with linear filtering.
-RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
+RENDERTHREAD_TEST(RenderNodeDrawable, layerComposeQuality) {
static const int CANVAS_WIDTH = 1;
static const int CANVAS_HEIGHT = 1;
static const int LAYER_WIDTH = 1;
@@ -1074,7 +1076,8 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
});
layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
- layerNode->setLayerSurface(SkSurface::MakeRasterN32Premul(LAYER_WIDTH, LAYER_HEIGHT));
+ layerNode->setLayerSurface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(LAYER_WIDTH,
+ LAYER_HEIGHT)));
FrameTestCanvas canvas;
RenderNodeDrawable drawable(layerNode.get(), &canvas, true);
@@ -1167,7 +1170,7 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
}
// Draw a vector drawable twice but with different bounds and verify correct bounds are used.
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
+RENDERTHREAD_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
static const int CANVAS_WIDTH = 100;
static const int CANVAS_HEIGHT = 200;
class VectorDrawableTestCanvas : public TestCanvasBase {
@@ -1210,3 +1213,77 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
canvas.drawDrawable(&drawable);
EXPECT_EQ(2, canvas.mDrawCounter);
}
+
+// Verify drawing logics for BackdropFilterDrawable
+RENDERTHREAD_TEST(BackdropFilterDrawable, drawing) {
+ static const int CANVAS_WIDTH = 100;
+ static const int CANVAS_HEIGHT = 200;
+ class SimpleTestCanvas : public TestCanvasBase {
+ public:
+ SkRect mDstBounds;
+ SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
+ void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
+ // did nothing.
+ }
+
+ // called when BackdropFilterDrawable is drawn.
+ void onDrawImageRect2(const SkImage*, const SkRect& src, const SkRect& dst,
+ const SkSamplingOptions&, const SkPaint*,
+ SrcRectConstraint) override {
+ mDrawCounter++;
+ mDstBounds = dst;
+ }
+ };
+ class SimpleLayer : public SkSurface_Base {
+ public:
+ SimpleLayer()
+ : SkSurface_Base(SkImageInfo::MakeN32Premul(CANVAS_WIDTH, CANVAS_HEIGHT), nullptr) {
+ }
+ virtual sk_sp<SkImage> onNewImageSnapshot(const SkIRect* bounds) override {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(CANVAS_WIDTH, CANVAS_HEIGHT);
+ bitmap.setImmutable();
+ return bitmap.asImage();
+ }
+ SkCanvas* onNewCanvas() override { return new SimpleTestCanvas(); }
+ sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
+ bool onCopyOnWrite(ContentChangeMode) override { return true; }
+ void onWritePixels(const SkPixmap&, int x, int y) {}
+ };
+
+ auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ Paint());
+ });
+
+ sk_sp<SkSurface> surface(new SimpleLayer());
+ auto* canvas = reinterpret_cast<SimpleTestCanvas*>(surface->getCanvas());
+ RenderNodeDrawable drawable(node.get(), canvas, true);
+ BackdropFilterDrawable backdropDrawable(node.get(), canvas);
+ canvas->drawDrawable(&drawable);
+ canvas->drawDrawable(&backdropDrawable);
+ // no backdrop filter, skip drawing.
+ EXPECT_EQ(0, canvas->mDrawCounter);
+
+ sk_sp<SkImageFilter> filter(SkImageFilters::Blur(3, 3, nullptr));
+ node->animatorProperties().mutateLayerProperties().setBackdropImageFilter(filter.get());
+ canvas->drawDrawable(&drawable);
+ canvas->drawDrawable(&backdropDrawable);
+ // backdrop filter is set, ok to draw.
+ EXPECT_EQ(1, canvas->mDrawCounter);
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), canvas->mDstBounds);
+
+ canvas->translate(30, 30);
+ canvas->drawDrawable(&drawable);
+ canvas->drawDrawable(&backdropDrawable);
+ // the drawable is still visible, ok to draw.
+ EXPECT_EQ(2, canvas->mDrawCounter);
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH - 30, CANVAS_HEIGHT - 30), canvas->mDstBounds);
+
+ canvas->translate(CANVAS_WIDTH, CANVAS_HEIGHT);
+ canvas->drawDrawable(&drawable);
+ canvas->drawDrawable(&backdropDrawable);
+ // the drawable is invisible, skip drawing.
+ EXPECT_EQ(2, canvas->mDrawCounter);
+}
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index 80796f4a4111..8273524167f9 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -231,8 +231,7 @@ TEST(RenderNode, multiTreeValidity) {
}
TEST(RenderNode, releasedCallback) {
- int functor = WebViewFunctor_create(
- nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ int functor = TestUtils::createMockFunctor();
auto node = TestUtils::createNode(0, 0, 200, 400, [&](RenderProperties& props, Canvas& canvas) {
canvas.drawWebViewFunctor(functor);
diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp
index 7bcd45c6b643..0f8bd1368f5a 100644
--- a/libs/hwui/tests/unit/ShaderCacheTests.cpp
+++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp
@@ -49,7 +49,7 @@ public:
*/
static void reinitializeAllFields(ShaderCache& cache) {
ShaderCache newCache = ShaderCache();
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex), newLock(newCache.mMutex);
// By order of declaration
cache.mInitialized = newCache.mInitialized;
cache.mBlobCache.reset(nullptr);
@@ -72,7 +72,7 @@ public:
* manually, as seen in the "terminate" testing helper function.
*/
static void setSaveDelayMs(ShaderCache& cache, unsigned int saveDelayMs) {
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex);
cache.mDeferredSaveDelayMs = saveDelayMs;
}
@@ -81,7 +81,7 @@ public:
* Next call to "initShaderDiskCache" will load again the in-memory cache from disk.
*/
static void terminate(ShaderCache& cache, bool saveContent) {
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex);
if (saveContent) {
cache.saveToDiskLocked();
}
@@ -93,6 +93,7 @@ public:
*/
template <typename T>
static bool validateCache(ShaderCache& cache, std::vector<T> hash) {
+ std::lock_guard lock(cache.mMutex);
return cache.validateCache(hash.data(), hash.size() * sizeof(T));
}
@@ -108,7 +109,7 @@ public:
*/
static void waitForPendingSave(ShaderCache& cache, const int timeoutMs = 50) {
{
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex);
ASSERT_TRUE(cache.mSavePending);
}
bool saving = true;
@@ -123,7 +124,7 @@ public:
usleep(delayMicroseconds);
elapsedMilliseconds += (float)delayMicroseconds / 1000;
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex);
saving = cache.mSavePending;
}
}
@@ -369,9 +370,9 @@ TEST(ShaderCacheTest, testCacheValidation) {
}
using namespace android::uirenderer;
-RENDERTHREAD_SKIA_PIPELINE_TEST(ShaderCacheTest, testOnVkFrameFlushed) {
+RENDERTHREAD_TEST(ShaderCacheTest, testOnVkFrameFlushed) {
if (Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan) {
- // RENDERTHREAD_SKIA_PIPELINE_TEST declares both SkiaVK and SkiaGL variants.
+ // RENDERTHREAD_TEST declares both SkiaVK and SkiaGL variants.
GTEST_SKIP() << "This test is only applicable to RenderPipelineType::SkiaVulkan";
}
if (!folderExist(getExternalStorageFolder())) {
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 87c52161d68e..e53fcaa474e2 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -36,7 +36,7 @@ using namespace android;
using namespace android::uirenderer;
TEST(SkiaCanvas, drawShadowLayer) {
- auto surface = SkSurface::MakeRasterN32Premul(10, 10);
+ auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(10, 10));
SkiaCanvas canvas(surface->getCanvas());
// clear to white
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index f825d7c5d9cc..064d42ec8941 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -48,8 +48,7 @@ TEST(SkiaDisplayList, reset) {
SkCanvas dummyCanvas;
RenderNodeDrawable drawable(nullptr, &dummyCanvas);
skiaDL->mChildNodes.emplace_back(nullptr, &dummyCanvas);
- int functor1 = WebViewFunctor_create(
- nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ int functor1 = TestUtils::createMockFunctor();
GLFunctorDrawable functorDrawable{functor1, &dummyCanvas};
WebViewFunctor_release(functor1);
skiaDL->mChildFunctors.push_back(&functorDrawable);
@@ -101,8 +100,7 @@ TEST(SkiaDisplayList, syncContexts) {
SkCanvas dummyCanvas;
- int functor1 = WebViewFunctor_create(
- nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ int functor1 = TestUtils::createMockFunctor();
auto& counts = TestUtils::countsForFunctor(functor1);
skiaDL.mChildFunctors.push_back(
skiaDL.allocateDrawable<GLFunctorDrawable>(functor1, &dummyCanvas));
@@ -131,6 +129,33 @@ TEST(SkiaDisplayList, syncContexts) {
EXPECT_EQ(counts.destroyed, 1);
}
+TEST(SkiaDisplayList, recordMutableBitmap) {
+ SkiaRecordingCanvas canvas{nullptr, 100, 100};
+ auto bitmap = Bitmap::allocateHeapBitmap(SkImageInfo::Make(
+ 10, 20, SkColorType::kN32_SkColorType, SkAlphaType::kPremul_SkAlphaType));
+ EXPECT_FALSE(bitmap->isImmutable());
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ auto displayList = canvas.finishRecording();
+ ASSERT_EQ(1, displayList->mMutableImages.size());
+ EXPECT_EQ(10, displayList->mMutableImages[0]->width());
+ EXPECT_EQ(20, displayList->mMutableImages[0]->height());
+}
+
+TEST(SkiaDisplayList, recordMutableBitmapInShader) {
+ SkiaRecordingCanvas canvas{nullptr, 100, 100};
+ auto bitmap = Bitmap::allocateHeapBitmap(SkImageInfo::Make(
+ 10, 20, SkColorType::kN32_SkColorType, SkAlphaType::kPremul_SkAlphaType));
+ EXPECT_FALSE(bitmap->isImmutable());
+ SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
+ Paint paint;
+ paint.setShader(bitmap->makeImage()->makeShader(sampling));
+ canvas.drawPaint(paint);
+ auto displayList = canvas.finishRecording();
+ ASSERT_EQ(1, displayList->mMutableImages.size());
+ EXPECT_EQ(10, displayList->mMutableImages[0]->width());
+ EXPECT_EQ(20, displayList->mMutableImages[0]->height());
+}
+
class ContextFactory : public IContextFactory {
public:
virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
@@ -138,7 +163,7 @@ public:
}
};
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
+RENDERTHREAD_TEST(SkiaDisplayList, prepareListAndChildren) {
auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
ContextFactory contextFactory;
std::unique_ptr<CanvasContext> canvasContext(
@@ -197,7 +222,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
canvasContext->destroy();
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren_vdOffscreen) {
+RENDERTHREAD_TEST(SkiaDisplayList, prepareListAndChildren_vdOffscreen) {
auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
ContextFactory contextFactory;
std::unique_ptr<CanvasContext> canvasContext(
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 4d0595e03da6..3ded540c3152 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -42,7 +42,7 @@ using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
using namespace android::uirenderer::skiapipeline;
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
+RENDERTHREAD_TEST(SkiaPipeline, renderFrame) {
auto redNode = TestUtils::createSkiaNode(
0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
@@ -54,7 +54,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
bool opaque = true;
android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
- auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+ auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(1, 1));
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
@@ -62,7 +62,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
+RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckOpaque) {
auto halfGreenNode = TestUtils::createSkiaNode(
0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
Paint greenPaint;
@@ -76,7 +76,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
renderNodes.push_back(halfGreenNode);
android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
- auto surface = SkSurface::MakeRasterN32Premul(2, 2);
+ auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(2, 2));
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface,
@@ -89,7 +89,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
+RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
auto redNode = TestUtils::createSkiaNode(
0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
@@ -100,7 +100,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
renderNodes.push_back(redNode);
android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
- auto surface = SkSurface::MakeRasterN32Premul(2, 2);
+ auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(2, 2));
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface,
@@ -111,12 +111,12 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
ASSERT_EQ(TestUtils::getColor(surface, 1, 1), SK_ColorRED);
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
+RENDERTHREAD_TEST(SkiaPipeline, renderLayer) {
auto redNode = TestUtils::createSkiaNode(
0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
});
- auto surfaceLayer1 = SkSurface::MakeRasterN32Premul(1, 1);
+ auto surfaceLayer1 = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(1, 1));
surfaceLayer1->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorWHITE);
redNode->setLayerSurface(surfaceLayer1);
@@ -127,7 +127,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) {
blueCanvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
});
- auto surfaceLayer2 = SkSurface::MakeRasterN32Premul(2, 2);
+ auto surfaceLayer2 = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(2, 2));
surfaceLayer2->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorWHITE);
blueNode->setLayerSurface(surfaceLayer2);
@@ -154,7 +154,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
blueNode->setLayerSurface(sk_sp<SkSurface>());
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) {
+RENDERTHREAD_TEST(SkiaPipeline, renderOverdraw) {
ScopedProperty<bool> prop(Properties::debugOverdraw, true);
auto whiteNode = TestUtils::createSkiaNode(
@@ -169,7 +169,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) {
// empty contentDrawBounds is avoiding backdrop/content logic, which would lead to less overdraw
android::uirenderer::Rect contentDrawBounds(0, 0, 0, 0);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
- auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+ auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(1, 1));
// Initialize the canvas to blue.
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
@@ -227,7 +227,7 @@ public:
};
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, deferRenderNodeScene) {
+RENDERTHREAD_TEST(SkiaPipeline, deferRenderNodeScene) {
class DeferTestCanvas : public SkCanvas {
public:
DeferTestCanvas() : SkCanvas(800, 600) {}
@@ -297,7 +297,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, deferRenderNodeScene) {
EXPECT_EQ(4, surface->canvas()->mDrawCounter);
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped) {
+RENDERTHREAD_TEST(SkiaPipeline, clipped) {
static const int CANVAS_WIDTH = 200;
static const int CANVAS_HEIGHT = 200;
class ClippedTestCanvas : public SkCanvas {
@@ -330,7 +330,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped) {
}
// Test renderFrame with a dirty clip and a pre-transform matrix.
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped_rotated) {
+RENDERTHREAD_TEST(SkiaPipeline, clipped_rotated) {
static const int CANVAS_WIDTH = 200;
static const int CANVAS_HEIGHT = 100;
static const SkMatrix rotateMatrix = SkMatrix::MakeAll(0, -1, CANVAS_HEIGHT, 1, 0, 0, 0, 0, 1);
@@ -366,7 +366,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped_rotated) {
EXPECT_EQ(1, surface->canvas()->mDrawCounter);
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) {
+RENDERTHREAD_TEST(SkiaPipeline, clip_replace) {
static const int CANVAS_WIDTH = 50;
static const int CANVAS_HEIGHT = 50;
class ClipReplaceTestCanvas : public SkCanvas {
@@ -396,7 +396,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) {
EXPECT_EQ(1, surface->canvas()->mDrawCounter);
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {
+RENDERTHREAD_TEST(SkiaPipeline, context_lost) {
test::TestContext context;
auto surface = context.surface();
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
@@ -410,7 +410,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {
EXPECT_TRUE(pipeline->isSurfaceReady());
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, pictureCallback) {
+RENDERTHREAD_TEST(SkiaPipeline, pictureCallback) {
// create a pipeline and add a picture callback
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
int callbackCount = 0;
@@ -428,7 +428,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, pictureCallback) {
renderNodes.push_back(redNode);
bool opaque = true;
android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
- auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+ auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(1, 1));
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
SkMatrix::I());
diff --git a/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
index e1fb8b7069ff..5e8f13d261c7 100644
--- a/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
+++ b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
@@ -26,9 +26,15 @@
using namespace android;
using namespace android::uirenderer;
+#define ASSUME_GLES() \
+ if (WebViewFunctor_queryPlatformRenderMode() != RenderMode::OpenGL_ES) \
+ GTEST_SKIP() << "Not in GLES, skipping test"
+
TEST(WebViewFunctor, createDestroyGLES) {
+ ASSUME_GLES();
int functor = WebViewFunctor_create(
- nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ nullptr, TestUtils::createMockFunctorCallbacks(RenderMode::OpenGL_ES),
+ RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
WebViewFunctor_release(functor);
TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) {
@@ -41,8 +47,10 @@ TEST(WebViewFunctor, createDestroyGLES) {
}
TEST(WebViewFunctor, createSyncHandleGLES) {
+ ASSUME_GLES();
int functor = WebViewFunctor_create(
- nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ nullptr, TestUtils::createMockFunctorCallbacks(RenderMode::OpenGL_ES),
+ RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
auto handle = WebViewFunctorManager::instance().handleFor(functor);
ASSERT_TRUE(handle);
@@ -82,8 +90,10 @@ TEST(WebViewFunctor, createSyncHandleGLES) {
}
TEST(WebViewFunctor, createSyncDrawGLES) {
+ ASSUME_GLES();
int functor = WebViewFunctor_create(
- nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ nullptr, TestUtils::createMockFunctorCallbacks(RenderMode::OpenGL_ES),
+ RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
auto handle = WebViewFunctorManager::instance().handleFor(functor);
ASSERT_TRUE(handle);
@@ -108,9 +118,11 @@ TEST(WebViewFunctor, createSyncDrawGLES) {
EXPECT_EQ(1, counts.destroyed);
}
-TEST(WebViewFunctor, contextDestroyed) {
+TEST(WebViewFunctor, contextDestroyedGLES) {
+ ASSUME_GLES();
int functor = WebViewFunctor_create(
- nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ nullptr, TestUtils::createMockFunctorCallbacks(RenderMode::OpenGL_ES),
+ RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
auto handle = WebViewFunctorManager::instance().handleFor(functor);
ASSERT_TRUE(handle);
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
index 10c874ec3f12..76cbc8abc808 100644
--- a/libs/hwui/tests/unit/main.cpp
+++ b/libs/hwui/tests/unit/main.cpp
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
+#include <getopt.h>
+#include <signal.h>
#include "Properties.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
#include "hwui/Typeface.h"
#include "tests/common/LeakChecker.h"
-#include <signal.h>
-
using namespace std;
using namespace android;
using namespace android::uirenderer;
@@ -45,6 +45,57 @@ static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) {
raise(sig);
}
+// For options that only exist in long-form. Anything in the
+// 0-255 range is reserved for short options (which just use their ASCII value)
+namespace LongOpts {
+enum {
+ Reserved = 255,
+ Renderer,
+};
+}
+
+static const struct option LONG_OPTIONS[] = {
+ {"renderer", required_argument, nullptr, LongOpts::Renderer}, {0, 0, 0, 0}};
+
+static RenderPipelineType parseRenderer(const char* renderer) {
+ // Anything that's not skiavk is skiagl
+ if (!strcmp(renderer, "skiavk")) {
+ return RenderPipelineType::SkiaVulkan;
+ }
+ return RenderPipelineType::SkiaGL;
+}
+
+struct Options {
+ RenderPipelineType renderer = RenderPipelineType::SkiaGL;
+};
+
+Options parseOptions(int argc, char* argv[]) {
+ int c;
+ opterr = 0;
+ Options opts;
+
+ while (true) {
+ /* getopt_long stores the option index here. */
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "", LONG_OPTIONS, &option_index);
+
+ if (c == -1) break;
+
+ switch (c) {
+ case 0:
+ // Option set a flag, don't need to do anything
+ // (although none of the current LONG_OPTIONS do this...)
+ break;
+
+ case LongOpts::Renderer:
+ opts.renderer = parseRenderer(optarg);
+ break;
+ }
+ }
+ return opts;
+}
+
class TypefaceEnvironment : public testing::Environment {
public:
virtual void SetUp() { Typeface::setRobotoTypefaceForTest(); }
@@ -64,8 +115,9 @@ int main(int argc, char* argv[]) {
// Avoid talking to SF
Properties::isolatedProcess = true;
- // Default to GLES (Vulkan-aware tests will override this)
- Properties::overrideRenderPipelineType(RenderPipelineType::SkiaGL);
+
+ auto opts = parseOptions(argc, argv);
+ Properties::overrideRenderPipelineType(opts.renderer);
// Run the tests
testing::InitGoogleTest(&argc, argv);
diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp
index db495cfbf7e1..d344a981ecea 100644
--- a/libs/incident/src/IncidentReportArgs.cpp
+++ b/libs/incident/src/IncidentReportArgs.cpp
@@ -133,13 +133,12 @@ IncidentReportArgs::readFromParcel(const Parcel* in)
mSections.insert(section);
}
- int32_t headerCount;
- err = in->readInt32(&headerCount);
+ err = in->resizeOutVector<vector<uint8_t>>(&mHeaders);
if (err != NO_ERROR) {
return err;
}
- mHeaders.resize(headerCount);
- for (int i=0; i<headerCount; i++) {
+
+ for (int i=0; i<mHeaders.size(); i++) {
err = in->readByteVector(&mHeaders[i]);
if (err != NO_ERROR) {
return err;
diff --git a/libs/input/OWNERS b/libs/input/OWNERS
index d701f23cb9b8..4c20c4dc9d35 100644
--- a/libs/input/OWNERS
+++ b/libs/input/OWNERS
@@ -1 +1 @@
-include /core/java/android/hardware/input/OWNERS
+include /INPUT_OWNERS
diff --git a/libs/services/Android.bp b/libs/services/Android.bp
index f656ebfc3b77..0b7e7d37718d 100644
--- a/libs/services/Android.bp
+++ b/libs/services/Android.bp
@@ -26,8 +26,6 @@ package {
cc_library_shared {
name: "libservices",
srcs: [
- ":IDropBoxManagerService.aidl",
- ":ILogcatManagerService_aidl",
"src/content/ComponentName.cpp",
"src/os/DropBoxManager.cpp",
],
@@ -42,7 +40,10 @@ cc_library_shared {
"libbase_headers",
],
aidl: {
- include_dirs: ["frameworks/base/core/java/"],
+ libs: [
+ "ILogcatManagerService_aidl",
+ "IDropBoxManagerService_aidl",
+ ],
},
export_include_dirs: ["include"],