summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt16
-rw-r--r--core/java/android/app/Activity.java5
-rw-r--r--core/java/android/hardware/camera2/CaptureFailure.java9
-rw-r--r--core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java76
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java2
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java5
-rw-r--r--core/java/android/view/AttachedSurfaceControl.java35
-rw-r--r--core/java/android/view/SurfaceControl.java70
-rw-r--r--core/java/android/view/SurfaceView.java6
-rw-r--r--core/java/android/view/ViewRootImpl.java29
-rw-r--r--core/java/android/view/translation/UiTranslationController.java14
-rw-r--r--core/java/android/widget/TextViewTranslationCallback.java8
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogGroup.java1
-rw-r--r--core/res/res/values-de/strings.xml2
-rw-r--r--core/res/res/values-mr/strings.xml4
-rw-r--r--data/etc/services.core.protolog.json87
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java153
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java1
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java81
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java22
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt12
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt118
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt65
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt59
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt48
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt66
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt33
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt9
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt9
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/bg.pngbin0 -> 1966 bytes
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_bubble.xml31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_message.xml26
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_bubble.xml48
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml48
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleActivity.java77
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java178
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java12
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java82
-rw-r--r--libs/hwui/Android.bp2
-rw-r--r--libs/hwui/Properties.cpp3
-rw-r--r--libs/hwui/renderthread/EglManager.cpp7
-rw-r--r--libs/hwui/renderthread/RenderEffectCapabilityQuery.cpp39
-rw-r--r--libs/hwui/renderthread/RenderEffectCapabilityQuery.h35
-rw-r--r--libs/hwui/tests/unit/EglManagerTests.cpp14
-rw-r--r--libs/hwui/tests/unit/RenderEffectCapabilityQueryTests.cpp52
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java6
-rw-r--r--packages/SystemUI/docs/keyguard.md34
-rw-r--r--packages/SystemUI/docs/keyguard/aod.md1
-rw-r--r--packages/SystemUI/docs/keyguard/bouncer.md6
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java15
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java3
-rw-r--r--packages/SystemUI/res/drawable/media_output_dialog_button_background.xml29
-rw-r--r--packages/SystemUI/res/layout/media_output_dialog.xml41
-rw-r--r--packages/SystemUI/res/layout/media_output_list_item.xml89
-rw-r--r--packages/SystemUI/res/values-af/strings.xml1
-rw-r--r--packages/SystemUI/res/values-am/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml1
-rw-r--r--packages/SystemUI/res/values-as/strings.xml1
-rw-r--r--packages/SystemUI/res/values-az/strings.xml1
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-be/strings.xml1
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml1
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml1
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml1
-rw-r--r--packages/SystemUI/res/values-da/strings.xml1
-rw-r--r--packages/SystemUI/res/values-de/strings.xml1
-rw-r--r--packages/SystemUI/res/values-el/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml1
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml1
-rw-r--r--packages/SystemUI/res/values-es/strings.xml1
-rw-r--r--packages/SystemUI/res/values-et/strings.xml1
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml1
-rw-r--r--packages/SystemUI/res/values-in/strings.xml1
-rw-r--r--packages/SystemUI/res/values-is/strings.xml1
-rw-r--r--packages/SystemUI/res/values-it/strings.xml1
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml1
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-km/strings.xml1
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml1
-rw-r--r--packages/SystemUI/res/values-my/strings.xml1
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml1
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-or/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml1
-rw-r--r--packages/SystemUI/res/values-si/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sw720dp-land/config.xml35
-rw-r--r--packages/SystemUI/res/values-sw720dp-port/config.xml33
-rw-r--r--packages/SystemUI/res/values-sw720dp/config.xml9
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml1
-rw-r--r--packages/SystemUI/res/values-te/strings.xml1
-rw-r--r--packages/SystemUI/res/values-th/strings.xml1
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml1
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml1
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml1
-rw-r--r--packages/SystemUI/res/values/dimens.xml6
-rw-r--r--packages/SystemUI/res/values/flags.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/res/values/styles.xml4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt91
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt153
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java51
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt96
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java48
-rw-r--r--services/core/java/com/android/server/audio/SpatializerHelper.java19
-rw-r--r--services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java25
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java26
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java17
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java1
-rw-r--r--services/core/java/com/android/server/wm/AnrController.java44
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java82
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java11
-rw-r--r--services/core/java/com/android/server/wm/EmbeddedWindowController.java27
-rw-r--r--services/core/java/com/android/server/wm/InputTarget.java40
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java39
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java2
-rw-r--r--services/core/java/com/android/server/wm/RemoteAnimationController.java6
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java47
-rw-r--r--services/core/java/com/android/server/wm/SurfaceFreezer.java43
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java71
-rw-r--r--services/core/java/com/android/server/wm/Transition.java24
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java5
-rw-r--r--services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java15
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java35
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java43
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerDebugConfig.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java75
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java71
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java67
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt38
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt52
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt8
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt8
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt8
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt153
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt8
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt10
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt248
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt32
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt5
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml10
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml27
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java5
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java44
255 files changed, 3818 insertions, 1037 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index a79df58c7916..f46c809f996c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -46912,15 +46912,15 @@ package android.view {
}
@UiThread public interface AttachedSurfaceControl {
- method public default void addOnSurfaceTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnSurfaceTransformHintChangedListener);
+ method public default void addOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction);
method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
- method public default int getSurfaceTransformHint();
- method public default void removeOnSurfaceTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnSurfaceTransformHintChangedListener);
+ method public default int getBufferTransformHint();
+ method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
}
- @UiThread public static interface AttachedSurfaceControl.OnSurfaceTransformHintChangedListener {
- method public void onSurfaceTransformHintChanged(int);
+ @UiThread public static interface AttachedSurfaceControl.OnBufferTransformHintChangedListener {
+ method public void onBufferTransformHintChanged(int);
}
public final class Choreographer {
@@ -48410,6 +48410,12 @@ package android.view {
method public void readFromParcel(android.os.Parcel);
method public void release();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BUFFER_TRANSFORM_IDENTITY = 0; // 0x0
+ field public static final int BUFFER_TRANSFORM_MIRROR_HORIZONTAL = 1; // 0x1
+ field public static final int BUFFER_TRANSFORM_MIRROR_VERTICAL = 2; // 0x2
+ field public static final int BUFFER_TRANSFORM_ROTATE_180 = 3; // 0x3
+ field public static final int BUFFER_TRANSFORM_ROTATE_270 = 7; // 0x7
+ field public static final int BUFFER_TRANSFORM_ROTATE_90 = 4; // 0x4
field @NonNull public static final android.os.Parcelable.Creator<android.view.SurfaceControl> CREATOR;
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 22091fcde86f..d229fd023e9f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -77,7 +77,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
import android.os.PersistableBundle;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -8804,9 +8803,7 @@ public class Activity extends ContextThemeWrapper
* the activity is visible after the screen is turned on when the lockscreen is up. In addition,
* if this flag is set and the activity calls {@link
* KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
- * the screen will turn on. If the screen is off and device is not secured, this flag can turn
- * screen on and dismiss keyguard to make this activity visible and resume, which can be used to
- * replace {@link PowerManager#ACQUIRE_CAUSES_WAKEUP}
+ * the screen will turn on.
*
* @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise.
*
diff --git a/core/java/android/hardware/camera2/CaptureFailure.java b/core/java/android/hardware/camera2/CaptureFailure.java
index 20ca4a338f01..032ed7e4db62 100644
--- a/core/java/android/hardware/camera2/CaptureFailure.java
+++ b/core/java/android/hardware/camera2/CaptureFailure.java
@@ -59,7 +59,7 @@ public class CaptureFailure {
private final CaptureRequest mRequest;
private final int mReason;
- private final boolean mDropped;
+ private final boolean mWasImageCaptured;
private final int mSequenceId;
private final long mFrameNumber;
private final String mErrorPhysicalCameraId;
@@ -68,10 +68,11 @@ public class CaptureFailure {
* @hide
*/
public CaptureFailure(CaptureRequest request, int reason,
- boolean dropped, int sequenceId, long frameNumber, String errorPhysicalCameraId) {
+ boolean wasImageCaptured, int sequenceId, long frameNumber,
+ String errorPhysicalCameraId) {
mRequest = request;
mReason = reason;
- mDropped = dropped;
+ mWasImageCaptured = wasImageCaptured;
mSequenceId = sequenceId;
mFrameNumber = frameNumber;
mErrorPhysicalCameraId = errorPhysicalCameraId;
@@ -141,7 +142,7 @@ public class CaptureFailure {
* @return boolean True if the image was captured, false otherwise.
*/
public boolean wasImageCaptured() {
- return !mDropped;
+ return mWasImageCaptured;
}
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 8da6551f3d15..b8443fb6d14b 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -873,21 +873,19 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
@Override
public int submitBurst(List<Request> requests, IRequestCallback callback) {
int seqId = -1;
- synchronized (mInterfaceLock) {
- try {
- CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
- ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
- for (Request request : requests) {
- captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
- mCameraConfigMap));
- }
- seqId = mCaptureSession.captureBurstRequests(captureRequests,
- new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
- } catch (CameraAccessException e) {
- Log.e(TAG, "Failed to submit capture requests!");
- } catch (IllegalStateException e) {
- Log.e(TAG, "Capture session closed!");
+ try {
+ CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+ ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
+ for (Request request : requests) {
+ captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
+ mCameraConfigMap));
}
+ seqId = mCaptureSession.captureBurstRequests(captureRequests,
+ new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Failed to submit capture requests!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Capture session closed!");
}
return seqId;
@@ -896,18 +894,16 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
@Override
public int setRepeating(Request request, IRequestCallback callback) {
int seqId = -1;
- synchronized (mInterfaceLock) {
- try {
- CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
- request, mCameraConfigMap);
- CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
- seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
- new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
- } catch (CameraAccessException e) {
- Log.e(TAG, "Failed to enable repeating request!");
- } catch (IllegalStateException e) {
- Log.e(TAG, "Capture session closed!");
- }
+ try {
+ CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
+ request, mCameraConfigMap);
+ CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+ seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
+ new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Failed to enable repeating request!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Capture session closed!");
}
return seqId;
@@ -915,27 +911,23 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
@Override
public void abortCaptures() {
- synchronized (mInterfaceLock) {
- try {
- mCaptureSession.abortCaptures();
- } catch (CameraAccessException e) {
- Log.e(TAG, "Failed during capture abort!");
- } catch (IllegalStateException e) {
- Log.e(TAG, "Capture session closed!");
- }
+ try {
+ mCaptureSession.abortCaptures();
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Failed during capture abort!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Capture session closed!");
}
}
@Override
public void stopRepeating() {
- synchronized (mInterfaceLock) {
- try {
- mCaptureSession.stopRepeating();
- } catch (CameraAccessException e) {
- Log.e(TAG, "Failed during repeating capture stop!");
- } catch (IllegalStateException e) {
- Log.e(TAG, "Capture session closed!");
- }
+ try {
+ mCaptureSession.stopRepeating();
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Failed during repeating capture stop!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Capture session closed!");
}
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 4708f3e0664f..88649392c23c 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -1867,7 +1867,7 @@ public class CameraDeviceImpl extends CameraDevice
final CaptureFailure failure = new CaptureFailure(
request,
reason,
- /*dropped*/ mayHaveBuffers,
+ mayHaveBuffers,
requestId,
frameNumber,
errorPhysicalCameraId);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c0f008122b4f..9721279bcd24 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -790,11 +790,6 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
- if (Trace.isEnabled()) {
- Binder.enableTracing();
- } else {
- Binder.disableTracing();
- }
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
ImeTracing.getInstance().triggerServiceDump(
"InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this,
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index b2fc9a0c85fc..69af2a5ce7fb 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
+import android.hardware.HardwareBuffer;
/**
* Provides an interface to the root-Surface of a View Hierarchy or Window. This
@@ -84,41 +85,43 @@ public interface AttachedSurfaceControl {
* Note, when using ANativeWindow APIs in conjunction with a NativeActivity Surface or
* SurfaceView Surface, the buffer producer will already have access to the transform hint and
* no additional work is needed.
+ *
+ * @see HardwareBuffer
*/
- default @Surface.Rotation int getSurfaceTransformHint() {
- return Surface.ROTATION_0;
+ default @SurfaceControl.BufferTransform int getBufferTransformHint() {
+ return SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
}
/**
- * Surface transform hint change listener.
- * @see #getSurfaceTransformHint
+ * Buffer transform hint change listener.
+ * @see #getBufferTransformHint
*/
@UiThread
- interface OnSurfaceTransformHintChangedListener {
+ interface OnBufferTransformHintChangedListener {
/**
* @param hint new surface transform hint
- * @see #getSurfaceTransformHint
+ * @see #getBufferTransformHint
*/
- void onSurfaceTransformHintChanged(@Surface.Rotation int hint);
+ void onBufferTransformHintChanged(@SurfaceControl.BufferTransform int hint);
}
/**
- * Registers a surface transform hint changed listener to receive notifications about when
+ * Registers a {@link OnBufferTransformHintChangedListener} to receive notifications about when
* the transform hint changes.
*
- * @see #getSurfaceTransformHint
- * @see #removeOnSurfaceTransformHintChangedListener
+ * @see #getBufferTransformHint
+ * @see #removeOnBufferTransformHintChangedListener
*/
- default void addOnSurfaceTransformHintChangedListener(
- @NonNull OnSurfaceTransformHintChangedListener listener) {
+ default void addOnBufferTransformHintChangedListener(
+ @NonNull OnBufferTransformHintChangedListener listener) {
}
/**
- * Unregisters a surface transform hint changed listener.
+ * Unregisters a {@link OnBufferTransformHintChangedListener}.
*
- * @see #addOnSurfaceTransformHintChangedListener
+ * @see #addOnBufferTransformHintChangedListener
*/
- default void removeOnSurfaceTransformHintChangedListener(
- @NonNull OnSurfaceTransformHintChangedListener listener) {
+ default void removeOnBufferTransformHintChangedListener(
+ @NonNull OnBufferTransformHintChangedListener listener) {
}
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index c786f0f3cc68..f1434c3ae772 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -245,6 +245,76 @@ public final class SurfaceControl implements Parcelable {
private static native int nativeGetTransformHint(long nativeObject);
private static native int nativeGetLayerId(long nativeObject);
+ /**
+ * Transforms that can be applied to buffers as they are displayed to a window.
+ *
+ * Supported transforms are any combination of horizontal mirror, vertical mirror, and
+ * clock-wise 90 degree rotation, in that order. Rotations of 180 and 270 degrees are made up
+ * of those basic transforms.
+ * Mirrors {@code ANativeWindowTransform} definitions.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"BUFFER_TRANSFORM_"},
+ value = {BUFFER_TRANSFORM_IDENTITY, BUFFER_TRANSFORM_MIRROR_HORIZONTAL,
+ BUFFER_TRANSFORM_MIRROR_VERTICAL, BUFFER_TRANSFORM_ROTATE_90,
+ BUFFER_TRANSFORM_ROTATE_180, BUFFER_TRANSFORM_ROTATE_270,
+ BUFFER_TRANSFORM_MIRROR_HORIZONTAL | BUFFER_TRANSFORM_ROTATE_90,
+ BUFFER_TRANSFORM_MIRROR_VERTICAL | BUFFER_TRANSFORM_ROTATE_90})
+ public @interface BufferTransform {
+ }
+
+ /**
+ * Identity transform.
+ *
+ * These transforms that can be applied to buffers as they are displayed to a window.
+ * @see HardwareBuffer
+ *
+ * Supported transforms are any combination of horizontal mirror, vertical mirror, and
+ * clock-wise 90 degree rotation, in that order. Rotations of 180 and 270 degrees are
+ * made up of those basic transforms.
+ */
+ public static final int BUFFER_TRANSFORM_IDENTITY = 0x00;
+ /**
+ * Mirror horizontally. Can be combined with {@link #BUFFER_TRANSFORM_MIRROR_VERTICAL}
+ * and {@link #BUFFER_TRANSFORM_ROTATE_90}.
+ */
+ public static final int BUFFER_TRANSFORM_MIRROR_HORIZONTAL = 0x01;
+ /**
+ * Mirror vertically. Can be combined with {@link #BUFFER_TRANSFORM_MIRROR_HORIZONTAL}
+ * and {@link #BUFFER_TRANSFORM_ROTATE_90}.
+ */
+ public static final int BUFFER_TRANSFORM_MIRROR_VERTICAL = 0x02;
+ /**
+ * Rotate 90 degrees clock-wise. Can be combined with {@link
+ * #BUFFER_TRANSFORM_MIRROR_HORIZONTAL} and {@link #BUFFER_TRANSFORM_MIRROR_VERTICAL}.
+ */
+ public static final int BUFFER_TRANSFORM_ROTATE_90 = 0x04;
+ /**
+ * Rotate 180 degrees clock-wise. Cannot be combined with other transforms.
+ */
+ public static final int BUFFER_TRANSFORM_ROTATE_180 =
+ BUFFER_TRANSFORM_MIRROR_HORIZONTAL | BUFFER_TRANSFORM_MIRROR_VERTICAL;
+ /**
+ * Rotate 270 degrees clock-wise. Cannot be combined with other transforms.
+ */
+ public static final int BUFFER_TRANSFORM_ROTATE_270 =
+ BUFFER_TRANSFORM_ROTATE_180 | BUFFER_TRANSFORM_ROTATE_90;
+
+ /**
+ * @hide
+ */
+ public static @BufferTransform int rotationToBufferTransform(@Surface.Rotation int rotation) {
+ switch (rotation) {
+ case Surface.ROTATION_0: return BUFFER_TRANSFORM_IDENTITY;
+ case Surface.ROTATION_90: return BUFFER_TRANSFORM_ROTATE_90;
+ case Surface.ROTATION_180: return BUFFER_TRANSFORM_ROTATE_180;
+ case Surface.ROTATION_270: return BUFFER_TRANSFORM_ROTATE_270;
+ }
+ Log.e(TAG, "Trying to convert unknown rotation=" + rotation);
+ return BUFFER_TRANSFORM_IDENTITY;
+ }
+
@Nullable
@GuardedBy("mLock")
private ArrayList<OnReparentListener> mReparentListeners;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 60bb99d37c39..63757e373795 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1104,7 +1104,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|| mWindowSpaceTop != mLocation[1];
final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
|| getHeight() != mScreenRect.height();
- final boolean hintChanged = (viewRoot.getSurfaceTransformHint() != mTransformHint)
+ final boolean hintChanged = (viewRoot.getBufferTransformHint() != mTransformHint)
&& mRequestedVisible;
if (creating || formatChanged || sizeChanged || visibleChanged ||
@@ -1130,7 +1130,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mSurfaceHeight = myHeight;
mFormat = mRequestedFormat;
mLastWindowVisibility = mWindowVisibility;
- mTransformHint = viewRoot.getSurfaceTransformHint();
+ mTransformHint = viewRoot.getBufferTransformHint();
mScreenRect.left = mWindowSpaceLeft;
mScreenRect.top = mWindowSpaceTop;
@@ -1362,7 +1362,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
if (mBlastBufferQueue != null) {
mBlastBufferQueue.destroy();
}
- mTransformHint = viewRoot.getSurfaceTransformHint();
+ mTransformHint = viewRoot.getBufferTransformHint();
mBlastSurfaceControl.setTransformHint(mTransformHint);
mBlastBufferQueue = new BLASTBufferQueue(name, mBlastSurfaceControl, mSurfaceWidth,
mSurfaceHeight, mFormat);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c45b27a8a2c2..8b791a4941f4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -312,7 +312,7 @@ public final class ViewRootImpl implements ViewParent,
static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>();
static boolean sFirstDrawComplete = false;
- private ArrayList<OnSurfaceTransformHintChangedListener> mTransformHintListeners =
+ private ArrayList<OnBufferTransformHintChangedListener> mTransformHintListeners =
new ArrayList<>();
private @Surface.Rotation int mPreviousTransformHint = Surface.ROTATION_0;
/**
@@ -7872,7 +7872,8 @@ public final class ViewRootImpl implements ViewParent,
int transformHint = mSurfaceControl.getTransformHint();
if (mPreviousTransformHint != transformHint) {
mPreviousTransformHint = transformHint;
- dispatchTransformHintChanged(transformHint);
+ dispatchTransformHintChanged(
+ SurfaceControl.rotationToBufferTransform(transformHint));
}
} else {
destroySurface();
@@ -10499,38 +10500,38 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
- public @Surface.Rotation int getSurfaceTransformHint() {
- return mSurfaceControl.getTransformHint();
+ public @SurfaceControl.BufferTransform int getBufferTransformHint() {
+ return SurfaceControl.rotationToBufferTransform(mSurfaceControl.getTransformHint());
}
@Override
- public void addOnSurfaceTransformHintChangedListener(
- OnSurfaceTransformHintChangedListener listener) {
+ public void addOnBufferTransformHintChangedListener(
+ OnBufferTransformHintChangedListener listener) {
Objects.requireNonNull(listener);
if (mTransformHintListeners.contains(listener)) {
throw new IllegalArgumentException(
- "attempt to call addOnSurfaceTransformHintChangedListener() "
+ "attempt to call addOnBufferTransformHintChangedListener() "
+ "with a previously registered listener");
}
mTransformHintListeners.add(listener);
}
@Override
- public void removeOnSurfaceTransformHintChangedListener(
- OnSurfaceTransformHintChangedListener listener) {
+ public void removeOnBufferTransformHintChangedListener(
+ OnBufferTransformHintChangedListener listener) {
Objects.requireNonNull(listener);
mTransformHintListeners.remove(listener);
}
- private void dispatchTransformHintChanged(@Surface.Rotation int hint) {
+ private void dispatchTransformHintChanged(@SurfaceControl.BufferTransform int hint) {
if (mTransformHintListeners.isEmpty()) {
return;
}
- ArrayList<OnSurfaceTransformHintChangedListener> listeners =
- (ArrayList<OnSurfaceTransformHintChangedListener>) mTransformHintListeners.clone();
+ ArrayList<OnBufferTransformHintChangedListener> listeners =
+ (ArrayList<OnBufferTransformHintChangedListener>) mTransformHintListeners.clone();
for (int i = 0; i < listeners.size(); i++) {
- OnSurfaceTransformHintChangedListener listener = listeners.get(i);
- listener.onSurfaceTransformHintChanged(hint);
+ OnBufferTransformHintChangedListener listener = listeners.get(i);
+ listener.onBufferTransformHintChanged(hint);
}
}
}
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index 60402eb30ba7..aa73ed7c8908 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -426,15 +426,19 @@ public class UiTranslationController {
continue;
}
mActivity.runOnUiThread(() -> {
+ ViewTranslationCallback callback = view.getViewTranslationCallback();
if (view.getViewTranslationResponse() != null
&& view.getViewTranslationResponse().equals(response)) {
- if (DEBUG) {
- Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
- + ". Ignoring.");
+ if (callback instanceof TextViewTranslationCallback) {
+ if (((TextViewTranslationCallback) callback).isShowingTranslation()) {
+ if (DEBUG) {
+ Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
+ + ". Ignoring.");
+ }
+ return;
+ }
}
- return;
}
- ViewTranslationCallback callback = view.getViewTranslationCallback();
if (callback == null) {
if (view instanceof TextView) {
// developer doesn't provide their override, we set the default TextView
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index 152405bf4d37..4a78f3ee6fac 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -64,6 +64,12 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
*/
@Override
public boolean onShowTranslation(@NonNull View view) {
+ if (mIsShowingTranslation) {
+ if (DEBUG) {
+ Log.d(TAG, view + " is already showing translated text.");
+ }
+ return false;
+ }
ViewTranslationResponse response = view.getViewTranslationResponse();
if (response == null) {
Log.e(TAG, "onShowTranslation() shouldn't be called before "
@@ -152,7 +158,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
return true;
}
- boolean isShowingTranslation() {
+ public boolean isShowingTranslation() {
return mIsShowingTranslation;
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index db019a67772f..954204fe781c 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -84,6 +84,7 @@ public enum ProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM),
WM_DEBUG_LAYER_MIRRORING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM),
+ WM_DEBUG_WALLPAPER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM),
TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
private final boolean mEnabled;
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 67b2ee45d8c0..a974e90736dd 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -336,7 +336,7 @@
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Legt die Zoom-Stufe und -Position auf dem Display fest."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Touch-Gesten möglich"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Tippen, Wischen, Zusammenziehen und andere Touch-Gesten möglich."</string>
- <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gesten auf dem Fingerabdrucksensor"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gesten auf dem Fin­gerabdrucksensor"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Erfasst Touch-Gesten auf dem Fingerabdrucksensor des Geräts."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Screenshot erstellen"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Es kann ein Screenshot des Displays erstellt werden."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4bb06bb0145d..eaed8c835bc1 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -100,7 +100,7 @@
<string name="peerTtyModeHco" msgid="5626377160840915617">"समवयस्क व्यक्तीने TTY मोड HCO ची विनंती केली"</string>
<string name="peerTtyModeVco" msgid="572208600818270944">"समवयस्क व्यक्तीने TTY मोड VCO ची विनंती केली"</string>
<string name="peerTtyModeOff" msgid="2420380956369226583">"समवयस्क व्यक्तीने TTY मोड बंद ची विनंती केली"</string>
- <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+ <string name="serviceClassVoice" msgid="2065556932043454987">"व्हॉइस"</string>
<string name="serviceClassData" msgid="4148080018967300248">"डेटा"</string>
<string name="serviceClassFAX" msgid="2561653371698904118">"फॅक्स"</string>
<string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
@@ -306,7 +306,7 @@
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"आपल्या संपर्कांवर प्रवेश"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"स्थान"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"या डिव्हाइसच्या स्थानावर प्रवेश"</string>
- <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+ <string name="permgrouplab_calendar" msgid="6426860926123033230">"कॅलेंडर"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"आपल्या कॅलेंडरवर प्रवेश"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS मेसेज पाठवणे आणि पाहणे हे"</string>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 909ca3988c5d..95736074a3ef 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -595,6 +595,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-1478175541": {
+ "message": "No longer animating wallpaper targets!",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/WallpaperController.java"
+ },
"-1474602871": {
"message": "Launch on display check: disallow launch on virtual display for not-embedded activity.",
"level": "DEBUG",
@@ -1621,6 +1627,12 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "-360208282": {
+ "message": "Animating wallpapers: old: %s hidden=%b new: %s hidden=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/WallpaperController.java"
+ },
"-354571697": {
"message": "Existence Changed in transition %d: %s",
"level": "VERBOSE",
@@ -1675,6 +1687,12 @@
"group": "WM_DEBUG_LAYER_MIRRORING",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-304728471": {
+ "message": "New wallpaper: target=%s prev=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/WallpaperController.java"
+ },
"-302468788": {
"message": "Expected target rootTask=%s to be top most but found rootTask=%s",
"level": "WARN",
@@ -1693,6 +1711,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-275077723": {
+ "message": "New animation: %s old animation: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/WallpaperController.java"
+ },
"-262984451": {
"message": "Relaunch failed %s",
"level": "INFO",
@@ -1747,6 +1771,12 @@
"group": "WM_DEBUG_LAYER_MIRRORING",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-182877285": {
+ "message": "Wallpaper layer changed: assigning layers + relayout",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-177040661": {
"message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
"level": "DEBUG",
@@ -2005,6 +2035,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "114070759": {
+ "message": "New wallpaper target: %s prevTarget: %s caller=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/WallpaperController.java"
+ },
"115358443": {
"message": "Focus changing: %s -> %s",
"level": "INFO",
@@ -2347,6 +2383,12 @@
"group": "WM_DEBUG_RESIZE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "422634333": {
+ "message": "First draw done in potential wallpaper target %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"424524729": {
"message": "Attempted to add wallpaper window with unknown token %s. Aborting.",
"level": "WARN",
@@ -2371,12 +2413,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "457951957": {
- "message": "\tNot visible=%s",
- "level": "DEBUG",
- "group": "WM_DEBUG_REMOTE_ANIMATIONS",
- "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
- },
"463993897": {
"message": "Aborted waiting for drawn: %s",
"level": "WARN",
@@ -2425,6 +2461,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowContainerThumbnail.java"
},
+ "535103992": {
+ "message": "Wallpaper may change! Adjusting",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"539077569": {
"message": "Clear freezing of %s force=%b",
"level": "VERBOSE",
@@ -2653,6 +2695,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "733466617": {
+ "message": "Wallpaper token %s visible=%b",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
+ },
"736692676": {
"message": "Config is relaunching %s",
"level": "VERBOSE",
@@ -2989,6 +3037,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "1178653181": {
+ "message": "Old wallpaper still the target.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/WallpaperController.java"
+ },
"1186730970": {
"message": " no common mode yet, so set it",
"level": "VERBOSE",
@@ -3667,6 +3721,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowAnimator.java"
},
+ "1984843251": {
+ "message": "Hiding wallpaper %s from %s target=%s prev=%s callers=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WALLPAPER",
+ "at": "com\/android\/server\/wm\/WallpaperController.java"
+ },
"1995093920": {
"message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s",
"level": "VERBOSE",
@@ -3697,6 +3757,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "2024493888": {
+ "message": "\tWallpaper of display=%s is not visible",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+ "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+ },
"2028163120": {
"message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s",
"level": "VERBOSE",
@@ -3721,12 +3787,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
- "2057434754": {
- "message": "\tvisible=%s",
- "level": "DEBUG",
- "group": "WM_DEBUG_REMOTE_ANIMATIONS",
- "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
- },
"2060978050": {
"message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d",
"level": "WARN",
@@ -3867,6 +3927,9 @@
"WM_DEBUG_TASKS": {
"tag": "WindowManager"
},
+ "WM_DEBUG_WALLPAPER": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_WINDOW_INSETS": {
"tag": "WindowManager"
},
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index 06f6228623d8..194b6330d92c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -16,7 +16,8 @@
package androidx.window.extensions.embedding;
-import android.graphics.Point;
+import static android.graphics.Matrix.MSCALE_X;
+
import android.graphics.Rect;
import android.view.Choreographer;
import android.view.RemoteAnimationTarget;
@@ -25,58 +26,151 @@ import android.view.animation.Animation;
import android.view.animation.Transformation;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
/**
* Wrapper to handle the TaskFragment animation update in one {@link SurfaceControl.Transaction}.
+ *
+ * The base adapter can be used for {@link RemoteAnimationTarget} that is simple open/close.
*/
class TaskFragmentAnimationAdapter {
- private final Animation mAnimation;
- private final RemoteAnimationTarget mTarget;
- private final SurfaceControl mLeash;
- private final boolean mSizeChanged;
- private final Point mPosition;
- private final Transformation mTransformation = new Transformation();
- private final float[] mMatrix = new float[9];
- private final float[] mVecs = new float[4];
- private final Rect mRect = new Rect();
+ final Animation mAnimation;
+ final RemoteAnimationTarget mTarget;
+ final SurfaceControl mLeash;
+
+ final Transformation mTransformation = new Transformation();
+ final float[] mMatrix = new float[9];
private boolean mIsFirstFrame = true;
TaskFragmentAnimationAdapter(@NonNull Animation animation,
@NonNull RemoteAnimationTarget target) {
- this(animation, target, target.leash, false /* sizeChanged */, null /* position */);
+ this(animation, target, target.leash);
}
/**
- * @param sizeChanged whether the surface size needs to be changed.
+ * @param leash the surface to animate.
*/
TaskFragmentAnimationAdapter(@NonNull Animation animation,
- @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash,
- boolean sizeChanged, @Nullable Point position) {
+ @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash) {
mAnimation = animation;
mTarget = target;
mLeash = leash;
- mSizeChanged = sizeChanged;
- mPosition = position != null
- ? position
- : new Point(target.localBounds.left, target.localBounds.top);
}
/** Called on frame update. */
- void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
+ final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
if (mIsFirstFrame) {
t.show(mLeash);
mIsFirstFrame = false;
}
- currentPlayTime = Math.min(currentPlayTime, mAnimation.getDuration());
- mAnimation.getTransformation(currentPlayTime, mTransformation);
- mTransformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
+ // Extract the transformation to the current time.
+ mAnimation.getTransformation(Math.min(currentPlayTime, mAnimation.getDuration()),
+ mTransformation);
+ t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+ onAnimationUpdateInner(t);
+ }
+
+ /** To be overridden by subclasses to adjust the animation surface change. */
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ mTransformation.getMatrix().postTranslate(
+ mTarget.localBounds.left, mTarget.localBounds.top);
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
t.setAlpha(mLeash, mTransformation.getAlpha());
- t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+ }
+
+ /** Called after animation finished. */
+ final void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
+ onAnimationUpdate(t, mAnimation.getDuration());
+ }
+
+ final long getDurationHint() {
+ return mAnimation.computeDurationHint();
+ }
+
+ /**
+ * Should be used when the {@link RemoteAnimationTarget} is in split with others, and want to
+ * animate together as one. This adapter will offset the animation leash to make the animate of
+ * two windows look like a single window.
+ */
+ static class SplitAdapter extends TaskFragmentAnimationAdapter {
+ private final boolean mIsLeftHalf;
+ private final int mWholeAnimationWidth;
+
+ /**
+ * @param isLeftHalf whether this is the left half of the animation.
+ * @param wholeAnimationWidth the whole animation windows width.
+ */
+ SplitAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target,
+ boolean isLeftHalf, int wholeAnimationWidth) {
+ super(animation, target);
+ mIsLeftHalf = isLeftHalf;
+ mWholeAnimationWidth = wholeAnimationWidth;
+ if (wholeAnimationWidth == 0) {
+ throw new IllegalArgumentException("SplitAdapter must provide wholeAnimationWidth");
+ }
+ }
+
+ @Override
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ float posX = mTarget.localBounds.left;
+ final float posY = mTarget.localBounds.top;
+ // This window is half of the whole animation window. Offset left/right to make it
+ // look as one with the other half.
+ mTransformation.getMatrix().getValues(mMatrix);
+ final int targetWidth = mTarget.localBounds.width();
+ final float scaleX = mMatrix[MSCALE_X];
+ final float totalOffset = mWholeAnimationWidth * (1 - scaleX) / 2;
+ final float curOffset = targetWidth * (1 - scaleX) / 2;
+ final float offsetDiff = totalOffset - curOffset;
+ if (mIsLeftHalf) {
+ posX += offsetDiff;
+ } else {
+ posX -= offsetDiff;
+ }
+ mTransformation.getMatrix().postTranslate(posX, posY);
+ t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
+ t.setAlpha(mLeash, mTransformation.getAlpha());
+ }
+ }
+
+ /**
+ * Should be used for the animation of the snapshot of a {@link RemoteAnimationTarget} that has
+ * size change.
+ */
+ static class SnapshotAdapter extends TaskFragmentAnimationAdapter {
+
+ SnapshotAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
+ // Start leash is the snapshot of the starting surface.
+ super(animation, target, target.startLeash);
+ }
+
+ @Override
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ // Snapshot should always be placed at the top left of the animation leash.
+ mTransformation.getMatrix().postTranslate(0, 0);
+ t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
+ t.setAlpha(mLeash, mTransformation.getAlpha());
+ }
+ }
+
+ /**
+ * Should be used for the animation of the {@link RemoteAnimationTarget} that has size change.
+ */
+ static class BoundsChangeAdapter extends TaskFragmentAnimationAdapter {
+ private final float[] mVecs = new float[4];
+ private final Rect mRect = new Rect();
+
+ BoundsChangeAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
+ super(animation, target);
+ }
+
+ @Override
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ mTransformation.getMatrix().postTranslate(
+ mTarget.localBounds.left, mTarget.localBounds.top);
+ t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
+ t.setAlpha(mLeash, mTransformation.getAlpha());
- if (mSizeChanged) {
// 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;
@@ -92,13 +186,4 @@ class TaskFragmentAnimationAdapter {
t.setWindowCrop(mLeash, mRect);
}
}
-
- /** Called after animation finished. */
- void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
- onAnimationUpdate(t, mAnimation.getDuration());
- }
-
- long getDurationHint() {
- return mAnimation.computeDurationHint();
- }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
index 65797667687e..535dac1a5101 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
@@ -29,7 +29,6 @@ import android.window.TaskFragmentOrganizer;
class TaskFragmentAnimationController {
private static final String TAG = "TaskFragAnimationCtrl";
- // TODO(b/196173550) turn off when finalize
static final boolean DEBUG = false;
private final TaskFragmentOrganizer mOrganizer;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 3980d077a7dd..412559e34070 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -23,7 +23,7 @@ import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import android.animation.Animator;
import android.animation.ValueAnimator;
-import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -40,6 +40,7 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.BiFunction;
/** To run the TaskFragment animations. */
class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
@@ -167,42 +168,86 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
private List<TaskFragmentAnimationAdapter> createOpenAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
- final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
- for (RemoteAnimationTarget target : targets) {
- final Animation animation =
- mAnimationSpec.loadOpenAnimation(target.mode != MODE_CLOSING /* isEnter */);
- adapters.add(new TaskFragmentAnimationAdapter(animation, target));
- }
- return adapters;
+ return createOpenCloseAnimationAdapters(targets,
+ mAnimationSpec::loadOpenAnimation);
}
private List<TaskFragmentAnimationAdapter> createCloseAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
- final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
+ return createOpenCloseAnimationAdapters(targets,
+ mAnimationSpec::loadCloseAnimation);
+ }
+
+ private List<TaskFragmentAnimationAdapter> createOpenCloseAnimationAdapters(
+ @NonNull RemoteAnimationTarget[] targets,
+ @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider) {
+ // We need to know if the target window is only a partial of the whole animation screen.
+ // If so, we will need to adjust it to make the whole animation screen looks like one.
+ final List<RemoteAnimationTarget> openingTargets = new ArrayList<>();
+ final List<RemoteAnimationTarget> closingTargets = new ArrayList<>();
+ final Rect openingWholeScreenBounds = new Rect();
+ final Rect closingWholeScreenBounds = new Rect();
for (RemoteAnimationTarget target : targets) {
- final Animation animation =
- mAnimationSpec.loadCloseAnimation(target.mode != MODE_CLOSING /* isEnter */);
- adapters.add(new TaskFragmentAnimationAdapter(animation, target));
+ if (target.mode != MODE_CLOSING) {
+ openingTargets.add(target);
+ openingWholeScreenBounds.union(target.localBounds);
+ } else {
+ closingTargets.add(target);
+ closingWholeScreenBounds.union(target.localBounds);
+ }
+ }
+
+ final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
+ for (RemoteAnimationTarget target : openingTargets) {
+ adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
+ openingWholeScreenBounds));
+ }
+ for (RemoteAnimationTarget target : closingTargets) {
+ adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
+ closingWholeScreenBounds));
}
return adapters;
}
+ private TaskFragmentAnimationAdapter createOpenCloseAnimationAdapter(
+ @NonNull RemoteAnimationTarget target,
+ @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider,
+ @NonNull Rect wholeAnimationBounds) {
+ final Animation animation = animationProvider.apply(target, wholeAnimationBounds);
+ final Rect targetBounds = target.localBounds;
+ if (targetBounds.left == wholeAnimationBounds.left
+ && targetBounds.right != wholeAnimationBounds.right) {
+ // This is the left split of the whole animation window.
+ return new TaskFragmentAnimationAdapter.SplitAdapter(animation, target,
+ true /* isLeftHalf */, wholeAnimationBounds.width());
+ } else if (targetBounds.left != wholeAnimationBounds.left
+ && targetBounds.right == wholeAnimationBounds.right) {
+ // This is the right split of the whole animation window.
+ return new TaskFragmentAnimationAdapter.SplitAdapter(animation, target,
+ false /* isLeftHalf */, wholeAnimationBounds.width());
+ }
+ // Open/close window that fills the whole animation.
+ return new TaskFragmentAnimationAdapter(animation, target);
+ }
+
private List<TaskFragmentAnimationAdapter> createChangeAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
for (RemoteAnimationTarget target : targets) {
if (target.startBounds != null) {
+ // This is the target with bounds change.
final Animation[] animations =
mAnimationSpec.createChangeBoundsChangeAnimations(target);
- // The snapshot surface will always be at (0, 0) of its parent.
- adapters.add(new TaskFragmentAnimationAdapter(animations[0], target,
- target.startLeash, false /* sizeChanged */, new Point(0, 0)));
- // The end surface will have size change for scaling.
- adapters.add(new TaskFragmentAnimationAdapter(animations[1], target,
- target.leash, true /* sizeChanged */, null /* position */));
+ // Adapter for the starting snapshot leash.
+ adapters.add(new TaskFragmentAnimationAdapter.SnapshotAdapter(
+ animations[0], target));
+ // Adapter for the ending bounds changed leash.
+ adapters.add(new TaskFragmentAnimationAdapter.BoundsChangeAdapter(
+ animations[1], target));
continue;
}
+ // These are the other targets that don't have bounds change in the same transition.
final Animation animation;
if (target.hasAnimatingParent) {
// No-op if it will be covered by the changing parent window.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
index 11a79b2f4a27..c0908a548501 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -176,18 +176,28 @@ class TaskFragmentAnimationSpec {
return new Animation[]{startSet, endSet};
}
- Animation loadOpenAnimation(boolean isEnter) {
- // TODO(b/196173550) We need to customize the animation to handle two open window as one.
- return mTransitionAnimation.loadDefaultAnimationAttr(isEnter
+ Animation loadOpenAnimation(@NonNull RemoteAnimationTarget target,
+ @NonNull Rect wholeAnimationBounds) {
+ final boolean isEnter = target.mode != MODE_CLOSING;
+ final Animation animation = mTransitionAnimation.loadDefaultAnimationAttr(isEnter
? R.styleable.WindowAnimation_activityOpenEnterAnimation
: R.styleable.WindowAnimation_activityOpenExitAnimation);
+ animation.initialize(target.localBounds.width(), target.localBounds.height(),
+ wholeAnimationBounds.width(), wholeAnimationBounds.height());
+ animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+ return animation;
}
- Animation loadCloseAnimation(boolean isEnter) {
- // TODO(b/196173550) We need to customize the animation to handle two open window as one.
- return mTransitionAnimation.loadDefaultAnimationAttr(isEnter
+ Animation loadCloseAnimation(@NonNull RemoteAnimationTarget target,
+ @NonNull Rect wholeAnimationBounds) {
+ final boolean isEnter = target.mode != MODE_CLOSING;
+ final Animation animation = mTransitionAnimation.loadDefaultAnimationAttr(isEnter
? R.styleable.WindowAnimation_activityCloseEnterAnimation
: R.styleable.WindowAnimation_activityCloseExitAnimation);
+ animation.initialize(target.localBounds.width(), target.localBounds.height(),
+ wholeAnimationBounds.width(), wholeAnimationBounds.height());
+ animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+ return animation;
}
private class SettingsObserver extends ContentObserver {
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
index e6d32ff1166f..06df9568e01a 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
@@ -42,6 +42,9 @@
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
<!-- ATM.removeRootTasksWithActivityTypes() -->
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
+ <!-- Enable bubble notification-->
+ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
+
<!-- Allow the test to write directly to /sdcard/ -->
<application android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
index c1ec324e9ab1..9e20bbbc1a1b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
@@ -20,13 +20,11 @@ import android.app.Instrumentation
import android.content.Context
import android.platform.test.annotations.Presubmit
import android.system.helpers.ActivityHelper
-import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
@@ -179,15 +177,9 @@ abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter)
@Presubmit
@Test
- open fun navBarLayerRotatesAndScales() {
- testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0,
- testSpec.config.endRotation)
- }
+ open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- open fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
- testSpec.config.endRotation)
- }
+ open fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
} \ No newline at end of file
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
new file mode 100644
index 000000000000..322d8b5e4dac
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021 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.bubble
+
+import android.app.INotificationManager
+import android.app.Instrumentation
+import android.app.NotificationManager
+import android.content.Context
+import android.os.ServiceManager
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE
+import com.android.server.wm.flicker.repetitions
+import com.android.wm.shell.flicker.helpers.LaunchBubbleHelper
+import org.junit.Test
+import org.junit.runners.Parameterized
+
+/**
+ * Base configurations for Bubble flicker tests
+ */
+abstract class BaseBubbleScreen(protected val testSpec: FlickerTestParameter) {
+
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val context: Context = instrumentation.context
+ protected val testApp = LaunchBubbleHelper(instrumentation)
+
+ protected val notifyManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE))
+
+ protected val packageManager = context.getPackageManager()
+ protected val uid = packageManager.getApplicationInfo(
+ testApp.component.packageName, 0).uid
+
+ protected lateinit var addBubbleBtn: UiObject2
+ protected lateinit var cancelAllBtn: UiObject2
+
+ protected abstract val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+
+ @JvmOverloads
+ protected open fun buildTransition(
+ extraSpec: FlickerBuilder.(Map<String, Any?>) -> Unit = {}
+ ): FlickerBuilder.(Map<String, Any?>) -> Unit {
+ return { configuration ->
+
+ setup {
+ test {
+ notifyManager.setBubblesAllowed(testApp.component.packageName,
+ uid, NotificationManager.BUBBLE_PREFERENCE_ALL)
+ testApp.launchViaIntent(wmHelper)
+ addBubbleBtn = device.wait(Until.findObject(
+ By.text("Add Bubble")), FIND_OBJECT_TIMEOUT)
+ cancelAllBtn = device.wait(Until.findObject(
+ By.text("Cancel All Bubble")), FIND_OBJECT_TIMEOUT)
+ }
+ }
+
+ teardown {
+ notifyManager.setBubblesAllowed(testApp.component.packageName,
+ uid, NotificationManager.BUBBLE_PREFERENCE_NONE)
+ testApp.exit()
+ }
+
+ extraSpec(this, configuration)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun testAppIsAlwaysVisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.component)
+ }
+ }
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ repeat { testSpec.config.repetitions }
+ transition(this, testSpec.config)
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 5)
+ }
+
+ const val FIND_OBJECT_TIMEOUT = 2000L
+ 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/DismissBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
new file mode 100644
index 000000000000..bfdcb363a818
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 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.bubble
+
+import android.content.Context
+import android.graphics.Point
+import android.util.DisplayMetrics
+import android.view.WindowManager
+import androidx.test.filters.RequiresDevice
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching a new activity from bubble.
+ *
+ * To run this test: `atest WMShellFlickerTests:DismissBubbleScreen`
+ *
+ * Actions:
+ * Dismiss a bubble notification
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+class DismissBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+
+ val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+ val displaySize = DisplayMetrics()
+
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition() {
+ setup {
+ eachRun {
+ addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Add Bubble not found")
+ }
+ }
+ transitions {
+ wm?.run { wm.getDefaultDisplay().getMetrics(displaySize) } ?: error("WM not found")
+ val dist = Point((displaySize.widthPixels / 2), displaySize.heightPixels)
+ val showBubble = device.wait(Until.findObject(
+ By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)), FIND_OBJECT_TIMEOUT)
+ showBubble?.run { drag(dist, 1000) } ?: error("Show bubble not found")
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
new file mode 100644
index 000000000000..42eeadf3ddd9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 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.bubble
+
+import androidx.test.filters.RequiresDevice
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching a new activity from bubble.
+ *
+ * To run this test: `atest WMShellFlickerTests:ExpandBubbleScreen`
+ *
+ * Actions:
+ * Launch an app and enable app's bubble notification
+ * Send a bubble notification
+ * The activity for the bubble is launched
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+class ExpandBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition() {
+ setup {
+ test {
+ addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Bubble widget not found")
+ }
+ }
+ transitions {
+ val showBubble = device.wait(Until.findObject(
+ By.res("com.android.systemui", "bubble_view")), FIND_OBJECT_TIMEOUT)
+ showBubble?.run { showBubble.click() } ?: error("Bubble notify not found")
+ device.pressBack()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
new file mode 100644
index 000000000000..47e8c0c047a8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 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.bubble
+
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test creating a bubble notification
+ *
+ * To run this test: `atest WMShellFlickerTests:LaunchBubbleScreen`
+ *
+ * Actions:
+ * Launch an app and enable app's bubble notification
+ * Send a bubble notification
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition() {
+ transitions {
+ addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Bubble widget not found")
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
new file mode 100644
index 000000000000..194e28fd6e8a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 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.bubble
+
+import android.os.SystemClock
+import androidx.test.filters.RequiresDevice
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching a new activity from bubble.
+ *
+ * To run this test: `atest WMShellFlickerTests:MultiBubblesScreen`
+ *
+ * Actions:
+ * Switch in different bubble notifications
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+class MultiBubblesScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition() {
+ setup {
+ test {
+ for (i in 1..3) {
+ addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Add Bubble not found")
+ }
+ val showBubble = device.wait(Until.findObject(
+ By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)), FIND_OBJECT_TIMEOUT)
+ showBubble?.run { showBubble.click() } ?: error("Show bubble not found")
+ SystemClock.sleep(1000)
+ }
+ }
+ transitions {
+ val bubbles = device.wait(Until.findObjects(
+ By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)), FIND_OBJECT_TIMEOUT)
+ for (entry in bubbles) {
+ entry?.run { entry.click() } ?: error("Bubble not found")
+ SystemClock.sleep(1000)
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt
new file mode 100644
index 000000000000..6695c17ed514
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 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.helpers
+
+import android.app.Instrumentation
+import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.wm.shell.flicker.testapp.Components
+
+class LaunchBubbleHelper(instrumentation: Instrumentation) : BaseAppHelper(
+ instrumentation,
+ Components.LaunchBubbleActivity.LABEL,
+ Components.LaunchBubbleActivity.COMPONENT.toFlickerComponent()
+) {
+
+ companion object {
+ const val TEST_REPETITIONS = 1
+ const val TIMEOUT_MS = 3_000L
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index b6680d96e2a2..2ccd03bf1d6a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -107,13 +107,11 @@ class LegacySplitScreenToLauncher(
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.endRotation)
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation)
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index 14b006ee046e..58e1def6f37a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -27,7 +27,6 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
@@ -133,12 +132,10 @@ class ResizeLegacySplitScreen(
fun entireScreenCovered() = testSpec.entireScreenCovered()
@Test
- fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.endRotation)
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Test
- fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation)
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Test
fun topAppLayerIsAlwaysVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
index 8a2b55b6fce0..8a50bc0b20cf 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
@@ -25,7 +25,6 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -75,15 +74,11 @@ class RotateOneLaunchedAppAndEnterSplitScreen(
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
- testSpec.config.endRotation)
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
- testSpec.config.endRotation)
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
index b3251573c942..84676a9186be 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
@@ -25,7 +25,6 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -74,13 +73,11 @@ class RotateOneLaunchedAppInSplitScreenMode(
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(
- testSpec.config.startRotation, testSpec.config.endRotation)
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(
- testSpec.config.startRotation, testSpec.config.endRotation)
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
index 56933c371aa8..2abdca9216f9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
@@ -24,7 +24,6 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
@@ -83,14 +82,11 @@ class RotateTwoLaunchedAppAndEnterSplitScreen(
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
- testSpec.config.endRotation)
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(
- testSpec.config.startRotation, testSpec.config.endRotation)
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
index 5782f145c00f..fe9b9f514015 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
@@ -25,7 +25,6 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
@@ -89,15 +88,11 @@ class RotateTwoLaunchedAppInSplitScreenMode(
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
- testSpec.config.endRotation)
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
- testSpec.config.endRotation)
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@FlakyTest
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 2aa1ed868ff2..c8c3f4d64294 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -111,8 +111,7 @@ class EnterPipToOtherOrientationTest(
*/
@FlakyTest
@Test
- override fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_90, Surface.ROTATION_0)
+ override fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks that the [FlickerComponentName.STATUS_BAR] has the correct position at
@@ -120,8 +119,7 @@ class EnterPipToOtherOrientationTest(
*/
@Presubmit
@Test
- override fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(Surface.ROTATION_90, Surface.ROTATION_0)
+ override fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
/**
* Checks that all parts of the screen are covered at the start and end of the transition
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
index e3d099f6fdb5..73626c23065a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -25,7 +24,6 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -62,14 +60,6 @@ class ExitPipWithDismissButtonTest(testSpec: FlickerTestParameter) : ExitPipTran
}
}
- @Postsubmit
- @Test
- override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
-
- @Postsubmit
- @Test
- override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
-
companion object {
/**
* Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 2cdfc2bf0654..9e43deef8d99 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -25,7 +25,6 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import org.junit.FixMethodOrder
import org.junit.Test
@@ -97,8 +96,7 @@ class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransiti
@Presubmit
@Test
- override fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ override fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
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 ce840efcab88..d0fee9a82093 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
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -90,7 +89,7 @@ class ExpandPipOnDoubleClickTest(testSpec: FlickerTestParameter) : PipTransition
/**
* Checks [pipApp] window remains visible throughout the animation
*/
- @Postsubmit
+ @Presubmit
@Test
fun pipWindowIsAlwaysVisible() {
testSpec.assertWm {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 08d52095e499..669f37ad1e72 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -95,18 +95,14 @@ class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec)
*/
@FlakyTest
@Test
- override fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
- testSpec.config.endRotation)
+ override fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks the position of the status bar at the start and end of the transition
*/
@Presubmit
@Test
- override fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
- testSpec.config.endRotation)
+ override fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
/**
* Checks that [fixedApp] layer is within [screenBoundsStart] at the start of the transition
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 ce89fb6af67d..e8a61e8a1dae 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
@@ -177,13 +177,11 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- open fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- open fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ open fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
index 5549330df766..2cdbffa7589c 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
@@ -107,5 +107,20 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity
+ android:name=".LaunchBubbleActivity"
+ android:label="LaunchBubbleApp"
+ android:exported="true"
+ android:launchMode="singleTop">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.VIEW" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".BubbleActivity"
+ android:label="BubbleApp"
+ android:exported="false"
+ android:resizeableActivity="true" />
</application>
</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/bg.png b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/bg.png
new file mode 100644
index 000000000000..d424a17b4157
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/bg.png
Binary files differ
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_bubble.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_bubble.xml
new file mode 100644
index 000000000000..b43f31da748d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_bubble.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 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.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7.2,14.4m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M14.8,18m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M15.2,8.8m-4.8,0a4.8,4.8 0,1 1,9.6 0a4.8,4.8 0,1 1,-9.6 0"/>
+</vector>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_message.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_message.xml
new file mode 100644
index 000000000000..0e8c7a0fe64a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 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="M12,4c-4.97,0 -9,3.58 -9,8c0,1.53 0.49,2.97 1.33,4.18c0.12,0.18 0.2,0.46 0.1,0.66c-0.33,0.68 -0.79,1.52 -1.38,2.39c-0.12,0.17 0.01,0.41 0.21,0.39c0.63,-0.05 1.86,-0.26 3.38,-0.91c0.17,-0.07 0.36,-0.06 0.52,0.03C8.55,19.54 10.21,20 12,20c4.97,0 9,-3.58 9,-8S16.97,4 12,4zM16.94,11.63l-3.29,3.29c-0.13,0.13 -0.34,0.04 -0.34,-0.14v-1.57c0,-0.11 -0.1,-0.21 -0.21,-0.2c-2.19,0.06 -3.65,0.65 -5.14,1.95c-0.15,0.13 -0.38,0 -0.33,-0.19c0.7,-2.57 2.9,-4.57 5.5,-4.75c0.1,-0.01 0.18,-0.09 0.18,-0.19V8.2c0,-0.18 0.22,-0.27 0.34,-0.14l3.29,3.29C17.02,11.43 17.02,11.55 16.94,11.63z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_bubble.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_bubble.xml
new file mode 100644
index 000000000000..f8b0ca3da26e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_bubble.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <Button
+ android:id="@+id/button_finish"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginStart="8dp"
+ android:text="Finish" />
+ <Button
+ android:id="@+id/button_new_task"
+ android:layout_width="wrap_content"
+ android:layout_height="46dp"
+ android:layout_marginStart="8dp"
+ android:text="New Task" />
+ <Button
+ android:id="@+id/button_new_bubble"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:text="New Bubble" />
+
+ <Button
+ android:id="@+id/button_activity_for_result"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:layout_marginStart="8dp"
+ android:text="Activity For Result" />
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml
new file mode 100644
index 000000000000..f23c46455c63
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:background="@android:color/black">
+
+ <Button
+ android:id="@+id/button_create"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:text="Add Bubble" />
+
+ <Button
+ android:id="@+id/button_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/button_create"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="20dp"
+ android:text="Cancel Bubble" />
+
+ <Button
+ android:id="@+id/button_cancel_all"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/button_cancel"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="20dp"
+ android:text="Cancel All Bubble" />
+</RelativeLayout>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleActivity.java
new file mode 100644
index 000000000000..bc3bc75ab903
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleActivity.java
@@ -0,0 +1,77 @@
+/*
+ * 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.flicker.testapp;
+
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.Toast;
+
+public class BubbleActivity extends Activity {
+ private int mNotifId = 0;
+
+ public BubbleActivity() {
+ super();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent = getIntent();
+ if (intent != null) {
+ mNotifId = intent.getIntExtra(BubbleHelper.EXTRA_BUBBLE_NOTIF_ID, -1);
+ } else {
+ mNotifId = -1;
+ }
+
+ setContentView(R.layout.activity_bubble);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ String result = resultCode == Activity.RESULT_OK ? "OK" : "CANCELLED";
+ Toast.makeText(this, "Activity result: " + result, Toast.LENGTH_SHORT).show();
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java
new file mode 100644
index 000000000000..d743dffd3c9e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2021 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.testapp;
+
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Person;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Point;
+import android.graphics.drawable.Icon;
+import android.os.SystemClock;
+import android.service.notification.StatusBarNotification;
+import android.view.WindowManager;
+
+import java.util.HashMap;
+
+public class BubbleHelper {
+
+ static final String EXTRA_BUBBLE_NOTIF_ID = "EXTRA_BUBBLE_NOTIF_ID";
+ static final String CHANNEL_ID = "bubbles";
+ static final String CHANNEL_NAME = "Bubbles";
+ static final int DEFAULT_HEIGHT_DP = 300;
+
+ private static BubbleHelper sInstance;
+
+ private final Context mContext;
+ private NotificationManager mNotificationManager;
+ private float mDisplayHeight;
+
+ private HashMap<Integer, BubbleInfo> mBubbleMap = new HashMap<>();
+
+ private int mNextNotifyId = 0;
+ private int mColourIndex = 0;
+
+ public static class BubbleInfo {
+ public int id;
+ public int height;
+ public Icon icon;
+
+ public BubbleInfo(int id, int height, Icon icon) {
+ this.id = id;
+ this.height = height;
+ this.icon = icon;
+ }
+ }
+
+ public static BubbleHelper getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new BubbleHelper(context);
+ }
+ return sInstance;
+ }
+
+ private BubbleHelper(Context context) {
+ mContext = context;
+ mNotificationManager = context.getSystemService(NotificationManager.class);
+
+ NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
+ NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setDescription("Channel that posts bubbles");
+ channel.setAllowBubbles(true);
+ mNotificationManager.createNotificationChannel(channel);
+
+ Point p = new Point();
+ WindowManager wm = context.getSystemService(WindowManager.class);
+ wm.getDefaultDisplay().getRealSize(p);
+ mDisplayHeight = p.y;
+
+ }
+
+ private int getNextNotifyId() {
+ int id = mNextNotifyId;
+ mNextNotifyId++;
+ return id;
+ }
+
+ private Icon getIcon() {
+ return Icon.createWithResource(mContext, R.drawable.bg);
+ }
+
+ public int addNewBubble(boolean autoExpand, boolean suppressNotif) {
+ int id = getNextNotifyId();
+ BubbleInfo info = new BubbleInfo(id, DEFAULT_HEIGHT_DP, getIcon());
+ mBubbleMap.put(info.id, info);
+
+ Notification.BubbleMetadata data = getBubbleBuilder(info)
+ .setSuppressNotification(suppressNotif)
+ .setAutoExpandBubble(false)
+ .build();
+ Notification notification = getNotificationBuilder(info.id)
+ .setBubbleMetadata(data).build();
+
+ mNotificationManager.notify(info.id, notification);
+ return info.id;
+ }
+
+ private Notification.Builder getNotificationBuilder(int id) {
+ Person chatBot = new Person.Builder()
+ .setBot(true)
+ .setName("BubbleBot")
+ .setImportant(true)
+ .build();
+
+ RemoteInput remoteInput = new RemoteInput.Builder("key")
+ .setLabel("Reply")
+ .build();
+
+ String shortcutId = "BubbleChat";
+ return new Notification.Builder(mContext, CHANNEL_ID)
+ .setChannelId(CHANNEL_ID)
+ .setShortcutId(shortcutId)
+ .setContentIntent(PendingIntent.getActivity(mContext, 0,
+ new Intent(mContext, LaunchBubbleActivity.class),
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .setStyle(new Notification.MessagingStyle(chatBot)
+ .setConversationTitle("Bubble Chat")
+ .addMessage("Hello? This is bubble: " + id,
+ SystemClock.currentThreadTimeMillis() - 300000, chatBot)
+ .addMessage("Is it me, " + id + ", you're looking for?",
+ SystemClock.currentThreadTimeMillis(), chatBot)
+ )
+ .setSmallIcon(R.drawable.ic_bubble);
+ }
+
+ private Notification.BubbleMetadata.Builder getBubbleBuilder(BubbleInfo info) {
+ Intent target = new Intent(mContext, BubbleActivity.class);
+ target.putExtra(EXTRA_BUBBLE_NOTIF_ID, info.id);
+ PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, info.id, target,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ return new Notification.BubbleMetadata.Builder()
+ .setIntent(bubbleIntent)
+ .setIcon(info.icon)
+ .setDesiredHeight(info.height);
+ }
+
+ public void cancel(int id) {
+ mNotificationManager.cancel(id);
+ }
+
+ public void cancelAll() {
+ mNotificationManager.cancelAll();
+ }
+
+ public void cancelLast() {
+ StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications();
+ if (activeNotifications.length > 0) {
+ mNotificationManager.cancel(
+ activeNotifications[activeNotifications.length - 1].getId());
+ }
+ }
+
+ public void cancelFirst() {
+ StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications();
+ if (activeNotifications.length > 0) {
+ mNotificationManager.cancel(activeNotifications[0].getId());
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java
index 0ead91bb37de..0ed59bdafd1d 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java
@@ -87,4 +87,16 @@ public class Components {
public static final ComponentName COMPONENT = new ComponentName(PACKAGE_NAME,
PACKAGE_NAME + ".SplitScreenSecondaryActivity");
}
+
+ public static class LaunchBubbleActivity {
+ public static final String LABEL = "LaunchBubbleApp";
+ public static final ComponentName COMPONENT = new ComponentName(PACKAGE_NAME,
+ PACKAGE_NAME + ".LaunchBubbleActivity");
+ }
+
+ public static class BubbleActivity {
+ public static final String LABEL = "BubbleApp";
+ public static final ComponentName COMPONENT = new ComponentName(PACKAGE_NAME,
+ PACKAGE_NAME + ".BubbleActivity");
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java
new file mode 100644
index 000000000000..71fa66d8a61c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 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.testapp;
+
+
+import android.app.Activity;
+import android.app.Person;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.view.View;
+
+import java.util.Arrays;
+
+public class LaunchBubbleActivity extends Activity {
+
+ private BubbleHelper mBubbleHelper;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addInboxShortcut(getApplicationContext());
+ mBubbleHelper = BubbleHelper.getInstance(this);
+ setContentView(R.layout.activity_main);
+ findViewById(R.id.button_create).setOnClickListener(this::add);
+ findViewById(R.id.button_cancel).setOnClickListener(this::cancel);
+ findViewById(R.id.button_cancel_all).setOnClickListener(this::cancelAll);
+ }
+
+ private void add(View v) {
+ mBubbleHelper.addNewBubble(false /* autoExpand */, false /* suppressNotif */);
+ }
+
+ private void cancel(View v) {
+ mBubbleHelper.cancelLast();
+ }
+
+ private void cancelAll(View v) {
+ mBubbleHelper.cancelAll();
+ }
+
+ private void addInboxShortcut(Context context) {
+ Icon icon = Icon.createWithResource(this, R.drawable.bg);
+ Person[] persons = new Person[4];
+ for (int i = 0; i < persons.length; i++) {
+ persons[i] = new Person.Builder()
+ .setBot(false)
+ .setIcon(icon)
+ .setName("google" + i)
+ .setImportant(true)
+ .build();
+ }
+
+ ShortcutInfo shortcut = new ShortcutInfo.Builder(context, "BubbleChat")
+ .setShortLabel("BubbleChat")
+ .setLongLived(true)
+ .setIntent(new Intent(Intent.ACTION_VIEW))
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_message))
+ .setPersons(persons)
+ .build();
+ ShortcutManager scmanager = context.getSystemService(ShortcutManager.class);
+ scmanager.addDynamicShortcuts(Arrays.asList(shortcut));
+ }
+
+}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 2c299fa32315..2b31bcf78890 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -570,6 +570,7 @@ cc_defaults {
"renderthread/DrawFrameTask.cpp",
"renderthread/EglManager.cpp",
"renderthread/ReliableSurface.cpp",
+ "renderthread/RenderEffectCapabilityQuery.cpp",
"renderthread/VulkanManager.cpp",
"renderthread/VulkanSurface.cpp",
"renderthread/RenderProxy.cpp",
@@ -696,6 +697,7 @@ cc_test {
"tests/unit/MatrixTests.cpp",
"tests/unit/OpBufferTests.cpp",
"tests/unit/PathInterpolatorTests.cpp",
+ "tests/unit/RenderEffectCapabilityQueryTests.cpp",
"tests/unit/RenderNodeDrawableTests.cpp",
"tests/unit/RenderNodeTests.cpp",
"tests/unit/RenderPropertiesTests.cpp",
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 35449875d324..475fd700ccc9 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -50,7 +50,8 @@ bool Properties::showDirtyRegions = false;
bool Properties::skipEmptyFrames = true;
bool Properties::useBufferAge = true;
bool Properties::enablePartialUpdates = true;
-bool Properties::enableRenderEffectCache = false;
+// Default true unless otherwise specified in RenderThread Configuration
+bool Properties::enableRenderEffectCache = true;
DebugLevel Properties::debugLevel = kDebugDisabled;
OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 383c79b27918..c7d7a17a23eb 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -28,6 +28,7 @@
#include "Frame.h"
#include "Properties.h"
+#include "RenderEffectCapabilityQuery.h"
#include "utils/Color.h"
#include "utils/StringUtils.h"
@@ -148,7 +149,11 @@ void EglManager::initialize() {
mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension;
auto* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
- Properties::enableRenderEffectCache = (strcmp(vendor, "Qualcomm") != 0);
+ auto* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
+ Properties::enableRenderEffectCache = supportsRenderEffectCache(
+ vendor, version);
+ ALOGV("RenderEffectCache supported %d on driver version %s",
+ Properties::enableRenderEffectCache, version);
}
EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
diff --git a/libs/hwui/renderthread/RenderEffectCapabilityQuery.cpp b/libs/hwui/renderthread/RenderEffectCapabilityQuery.cpp
new file mode 100644
index 000000000000..a003988575c8
--- /dev/null
+++ b/libs/hwui/renderthread/RenderEffectCapabilityQuery.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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 <stdio.h>
+#include <string.h>
+#include <utils/Log.h>
+
+bool supportsRenderEffectCache(const char* vendor, const char* version) {
+ if (strcmp(vendor, "Qualcomm") != 0) {
+ return true;
+ }
+
+ int major;
+ int minor;
+ int driverMajor;
+ int driverMinor;
+ int n = sscanf(version,"OpenGL ES %d.%d V@%d.%d",
+ &major,
+ &minor,
+ &driverMajor,
+ &driverMinor);
+ // Ensure we have parsed the vendor string properly and we have either
+ // a newer major driver version, or the minor version is rev'ed
+ // Based on b/198227600#comment5 it appears that the corresponding fix
+ // is in driver version 571.0
+ return n == 4 && driverMajor >= 571;
+} \ No newline at end of file
diff --git a/libs/hwui/renderthread/RenderEffectCapabilityQuery.h b/libs/hwui/renderthread/RenderEffectCapabilityQuery.h
new file mode 100644
index 000000000000..ea673dd0386d
--- /dev/null
+++ b/libs/hwui/renderthread/RenderEffectCapabilityQuery.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 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
+
+/**
+ * Verify if the provided vendor and version supports RenderEffect caching
+ * behavior.
+ *
+ * Certain Open GL Driver implementations run into blocking scenarios
+ * with Fence::waitForever without a corresponding signal to unblock
+ * This happens during attempts to cache SkImage instances across frames
+ * especially in circumstances using RenderEffect/SkImageFilter internally.
+ * So detect the corresponding GL Vendor and driver version to determine if
+ * caching SkImage instances across frames is supported.
+ * See b/197263715 & b/193145089
+ * @param vendor Vendor of the GL driver
+ * @param version Version of the GL driver from the given vendor
+ * @return True if a RenderEffect result can be cached across frames,
+ * false otherwise
+ */
+bool supportsRenderEffectCache(const char* vendor, const char* version);
diff --git a/libs/hwui/tests/unit/EglManagerTests.cpp b/libs/hwui/tests/unit/EglManagerTests.cpp
index f7f240663397..7f2e1589ae6c 100644
--- a/libs/hwui/tests/unit/EglManagerTests.cpp
+++ b/libs/hwui/tests/unit/EglManagerTests.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include "renderthread/EglManager.h"
+#include "renderthread/RenderEffectCapabilityQuery.h"
#include "tests/common/TestContext.h"
using namespace android;
@@ -41,4 +42,17 @@ TEST(EglManager, doesSurfaceLeak) {
}
eglManager.destroy();
+}
+
+TEST(EglManager, verifyRenderEffectCacheSupported) {
+ EglManager eglManager;
+ eglManager.initialize();
+ auto* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+ auto* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
+ // Make sure that EglManager initializes Properties::enableRenderEffectCache
+ // based on the given gl vendor and version within EglManager->initialize()
+ bool renderEffectCacheSupported = supportsRenderEffectCache(vendor, version);
+ EXPECT_EQ(renderEffectCacheSupported,
+ Properties::enableRenderEffectCache);
+ eglManager.destroy();
} \ No newline at end of file
diff --git a/libs/hwui/tests/unit/RenderEffectCapabilityQueryTests.cpp b/libs/hwui/tests/unit/RenderEffectCapabilityQueryTests.cpp
new file mode 100644
index 000000000000..0ee654929b3b
--- /dev/null
+++ b/libs/hwui/tests/unit/RenderEffectCapabilityQueryTests.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 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 <gtest/gtest.h>
+#include "renderthread/RenderEffectCapabilityQuery.h"
+#include "tests/common/TestContext.h"
+
+TEST(RenderEffectCapabilityQuery, testSupportedVendor) {
+ ASSERT_TRUE(supportsRenderEffectCache("Google", "OpenGL ES 1.4 V@0.0"));
+}
+
+TEST(RenderEffectCapabilityQuery, testSupportedVendorWithDifferentVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Google", "OpenGL ES 1.3 V@571.0"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithSupportedVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.5 V@571.0"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithSupportedPatchVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.5 V@571.1"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithNewerThanSupportedMajorVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.5 V@572.0"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithNewerThanSupportedMinorVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.5 V@571.2"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithUnsupportedMajorVersion) {
+ ASSERT_FALSE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.0 V@570.1"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithUnsupportedVersion) {
+ ASSERT_FALSE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.1 V@570.0"));
+}
+
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
index 27658824933a..a3d924fbad60 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -200,10 +200,10 @@ public class Interpolators {
/**
* Interpolate alpha for notifications background scrim during shade expansion.
* @param fraction Shade expansion fraction
- * @param forNotification If we want the alpha of the notification shade or the scrim.
+ * @param forUiContent If we want the alpha of the scrims, or ui that's on top of them.
*/
- public static float getNotificationScrimAlpha(float fraction, boolean forNotification) {
- if (forNotification) {
+ public static float getNotificationScrimAlpha(float fraction, boolean forUiContent) {
+ if (forUiContent) {
fraction = MathUtils.constrainedMap(0f, 1f, 0.3f, 1f, fraction);
} else {
fraction = MathUtils.constrainedMap(0f, 1f, 0f, 0.5f, fraction);
diff --git a/packages/SystemUI/docs/keyguard.md b/packages/SystemUI/docs/keyguard.md
index e3d48aee96e4..5e7bc1c8cad2 100644
--- a/packages/SystemUI/docs/keyguard.md
+++ b/packages/SystemUI/docs/keyguard.md
@@ -8,5 +8,39 @@ Keyguard is responsible for:
Keyguard is the first screen available when turning on the device, as long as the user has not specified a security method of NONE.
+## Critical User Journeys
+
+The journeys below generally refer to Keyguard's portion of the overall flow, especially regarding use of the power button. Power button key interpretation (short press, long press, very long press, multi press) is done in [PhoneWindowManager][4], with calls to [PowerManagerService][2] to sleep or wake up, if needed.
+
+### Power On - AOD enabled or disabled
+
+Begins with the device in low power mode, with the display active for [AOD][3] or inactive. [PowerManagerService][2] can be directed to wake up on various user-configurable signals, such as lift to wake, screen taps, among others. [AOD][2], whether visibly enabled or not, handles these signals to transition AOD to full Lockscreen content. See more in [AOD][3].
+
+### Power Off
+
+An indication to power off the device most likely comes from one of two signals: the user presses the power button or the screen timeout has passed. This may [lock the device](#How-the-device-locks)
+
+#### On Lockscreen
+
+#### On Lockscreen, occluded by an activity
+
+#### Device unlocked, Keyguard has gone away
+
+### Pulsing (Incoming notifications while dozing)
+
+### How the device locks
+
+More coming
+* Screen timeout
+* Smart lock
+* Device policy
+* Power button instantly locks setting
+* Lock timeout after screen timeout setting
+
+
[1]: /frameworks/base/packages/SystemUI/docs/keyguard/bouncer.md
+[2]: /frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
+[3]: /frameworks/base/packages/SystemUI/docs/keyguard/aod.md
+[4]: /frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
+
diff --git a/packages/SystemUI/docs/keyguard/aod.md b/packages/SystemUI/docs/keyguard/aod.md
new file mode 100644
index 000000000000..6d76ed55174a
--- /dev/null
+++ b/packages/SystemUI/docs/keyguard/aod.md
@@ -0,0 +1 @@
+# Always-on Display (AOD)
diff --git a/packages/SystemUI/docs/keyguard/bouncer.md b/packages/SystemUI/docs/keyguard/bouncer.md
index a724966a639a..51f851608a34 100644
--- a/packages/SystemUI/docs/keyguard/bouncer.md
+++ b/packages/SystemUI/docs/keyguard/bouncer.md
@@ -7,9 +7,9 @@
The bouncer contains a hierarchy of controllers/views to render the user's security method and to manage the authentication attempts.
1. [KeyguardBouncer][1] - Entrypoint for managing the bouncer visibility.
- 1. [KeyguardHostViewController][2] - Intercepts media keys. Can most likely be merged with the next item.
- 1. [KeyguardSecurityContainerController][3] - Manages unlock attempt responses, one-handed use
- 1. [KeyguardSecurityViewFlipperController][4] - Based upon the [KeyguardSecurityModel#SecurityMode][5], will instantiate the required view and controller. PIN, Pattern, etc.
+ 1. [KeyguardHostViewController][2] - Intercepts media keys. Can most likely be merged with the next item.
+ 1. [KeyguardSecurityContainerController][3] - Manages unlock attempt responses, one-handed use
+ 1. [KeyguardSecurityViewFlipperController][4] - Based upon the [KeyguardSecurityModel#SecurityMode][5], will instantiate the required view and controller. PIN, Pattern, etc.
[1]: /frameworks/base/packages/SystemUI/com/android/systemui/statusbar/phone/KeyguardBouncer
[2]: /frameworks/base/packages/SystemUI/com/android/keyguard/KeyguardHostViewController
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index a03d84956ddc..757dc2ec807d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -52,7 +52,16 @@ public interface QS extends FragmentBase {
boolean isShowingDetail();
void closeDetail();
void animateHeaderSlidingOut();
- void setQsExpansion(float qsExpansionFraction, float headerTranslation);
+
+ /**
+ * Asks QS to update its presentation, according to {@code NotificationPanelViewController}.
+ *
+ * @param qsExpansionFraction How much each UI element in QS should be expanded (QQS to QS.)
+ * @param panelExpansionFraction Whats the expansion of the whole shade.
+ * @param headerTranslation How much we should vertically translate QS.
+ */
+ void setQsExpansion(float qsExpansionFraction, float panelExpansionFraction,
+ float headerTranslation);
void setHeaderListening(boolean listening);
void notifyCustomizeChanged();
void setContainerController(QSContainerController controller);
@@ -75,13 +84,13 @@ public interface QS extends FragmentBase {
/**
* If QS should translate as we pull it down, or if it should be static.
*/
- void setTranslateWhileExpanding(boolean shouldTranslate);
+ void setInSplitShade(boolean shouldTranslate);
/**
* Set the amount of pixels we have currently dragged down if we're transitioning to the full
* shade. 0.0f means we're not transitioning yet.
*/
- default void setTransitionToFullShadeAmount(float pxAmount, boolean animated) {}
+ default void setTransitionToFullShadeAmount(float pxAmount, float progress) {}
/**
* A rounded corner clipping that makes QS feel as if it were behind everything.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index 6c5c4ef94921..9829918a0302 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -109,9 +109,8 @@ public interface StatusBarStateController {
* Callback to be notified when the fullscreen or immersive state changes.
*
* @param isFullscreen if any of the system bar is hidden by the focused window.
- * @param isImmersive if the navigation bar can stay hidden when the display gets tapped.
*/
- default void onFullscreenStateChanged(boolean isFullscreen, boolean isImmersive) {}
+ default void onFullscreenStateChanged(boolean isFullscreen) {}
/**
* Callback to be notified when the pulsing state changes
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
new file mode 100644
index 000000000000..363a022efdac
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="?androidprv:attr/colorAccentPrimaryVariant"
+ android:width="1dp"/>
+ <corners android:radius="20dp"/>
+ <padding
+ android:left="16dp"
+ android:right="16dp"
+ android:top="8dp"
+ android:bottom="8dp" />
+ <solid android:color="@android:color/transparent" />
+</shape>
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index b33889469f48..cd6bc11bacf3 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -24,41 +24,44 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="94dp"
+ android:layout_height="96dp"
android:gravity="start|center_vertical"
android:paddingStart="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/header_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingEnd="@dimen/media_output_dialog_header_icon_padding"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:importantForAccessibility="no"/>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginEnd="16dp"
+ android:layout_height="match_parent"
+ android:paddingStart="16dp"
+ android:paddingTop="20dp"
+ android:paddingBottom="24dp"
+ android:paddingEnd="24dp"
android:orientation="vertical">
<TextView
android:id="@+id/header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
+ android:gravity="center_vertical"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="20sp"/>
-
<TextView
android:id="@+id/header_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:gravity="center_vertical"
android:ellipsize="end"
android:maxLines="1"
+ android:textColor="?android:attr/textColorTertiary"
android:fontFamily="roboto-regular"
- android:textSize="14sp"/>
-
+ android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>
@@ -81,21 +84,21 @@
android:overScrollMode="never"/>
</LinearLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider"/>
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="18dp"
+ android:layout_marginEnd="24dp"
android:orientation="horizontal">
<Button
android:id="@+id/stop"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ style="@style/MediaOutputRoundedOutlinedButton"
android:layout_width="wrap_content"
- android:layout_height="64dp"
+ android:layout_height="36dp"
+ android:minWidth="0dp"
android:text="@string/keyboard_key_media_stop"
android:visibility="gone"/>
@@ -106,10 +109,10 @@
<Button
android:id="@+id/done"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ style="@style/MediaOutputRoundedOutlinedButton"
android:layout_width="wrap_content"
- android:layout_height="64dp"
- android:layout_marginEnd="0dp"
+ android:layout_height="36dp"
+ android:minWidth="0dp"
android:text="@string/inline_done_button"/>
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index 16c03e124794..a5a7efa24f47 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -23,17 +23,20 @@
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="64dp">
+ android:layout_height="88dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="16dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="8dp">
<FrameLayout
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_gravity="center_vertical|start"
- android:layout_marginStart="16dp">
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical|start">
<ImageView
android:id="@+id/title_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:layout_gravity="center"/>
</FrameLayout>
@@ -42,49 +45,69 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="68dp"
+ android:layout_marginStart="64dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp"/>
+ android:textSize="16sp"/>
<RelativeLayout
android:id="@+id/two_line_layout"
android:layout_width="wrap_content"
android:layout_height="48dp"
- android:layout_marginStart="52dp"
- android:layout_marginEnd="69dp"
- android:layout_marginTop="10dp">
+ android:layout_marginStart="48dp">
<TextView
android:id="@+id/two_line_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
- android:layout_marginEnd="15dp"
+ android:layout_marginEnd="48dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp"/>
+ android:textSize="16sp"/>
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="15dp"
- android:layout_marginBottom="7dp"
+ android:layout_marginTop="4dp"
android:layout_alignParentBottom="true"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorSecondary"
- android:textSize="12sp"
+ android:textSize="14sp"
android:fontFamily="roboto-regular"
android:visibility="gone"/>
<SeekBar
android:id="@+id/volume_seekbar"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="8dp"
style="@*android:style/Widget.DeviceDefault.SeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
+ <ImageView
+ android:id="@+id/add_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="right"
+ android:layout_marginEnd="24dp"
+ android:layout_alignParentRight="true"
+ android:src="@drawable/ic_add"
+ android:tint="?android:attr/colorAccent"
+ />
+ <CheckBox
+ android:id="@+id/check_box"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="right"
+ android:layout_marginEnd="24dp"
+ android:layout_alignParentRight="true"
+ android:button="@drawable/ic_check_box"
+ android:visibility="gone"
+ />
</RelativeLayout>
<ProgressBar
@@ -92,47 +115,17 @@
style="@*android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="258dp"
android:layout_height="18dp"
- android:layout_marginStart="68dp"
- android:layout_marginTop="40dp"
+ android:layout_marginStart="64dp"
+ android:layout_marginTop="28dp"
android:indeterminate="true"
android:indeterminateOnly="true"
android:visibility="gone"/>
-
- <View
- android:id="@+id/end_divider"
- android:layout_width="1dp"
- android:layout_height="36dp"
- android:layout_marginEnd="68dp"
- android:layout_gravity="right|center_vertical"
- android:background="?android:attr/listDivider"
- android:visibility="gone"/>
-
- <ImageView
- android:id="@+id/add_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="right|center_vertical"
- android:layout_marginEnd="24dp"
- android:src="@drawable/ic_add"
- android:tint="?android:attr/colorAccent"
- android:visibility="gone"/>
-
- <CheckBox
- android:id="@+id/check_box"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="right|center_vertical"
- android:layout_marginEnd="24dp"
- android:button="@drawable/ic_check_box"
- android:visibility="gone"/>
</FrameLayout>
<View
android:id="@+id/bottom_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
android:layout_gravity="bottom"
android:background="?android:attr/listDivider"
android:visibility="gone"/>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index f589498c377a..522fcb299f96 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-fi sal vir nou nie outomaties koppel nie"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kies gebruiker"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e94dc688ac7c..432c557dc150 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi ለአሁን በራስ-ሰር አይገናኝም"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ሁሉንም ይመልከቱ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"አውታረ መረቦችን ለመቀየር፣ የኢተርኔት ግንኙነት ያቋርጡ"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ተጠቃሚን ይምረጡ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 14753dabb464..2728c980ad73 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1202,4 +1202,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‏لن يتم الاتصال بشبكة Wi-Fi تلقائيًا في الوقت الحالي."</string>
<string name="see_all_networks" msgid="3773666844913168122">"عرض الكل"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"للتبديل بين الشبكات، يجب فصل إيثرنت."</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"اختيار المستخدم"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index a50d8c10dd3f..e8158f12ee5a 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"এতিয়া ৱাই-ফাই স্বয়ংক্ৰিয়ভাৱে সংযুক্ত নহ’ব"</string>
<string name="see_all_networks" msgid="3773666844913168122">"আটাইবোৰ চাওক"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটৱৰ্ক সলনি কৰিবলৈ ইথাৰনেটৰ পৰা সংযোগ বিচ্ছিন্ন কৰক"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ব্যৱহাৰকাৰী বাছনি কৰক"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index e0ef1eca3282..02032883f9f0 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi hələlik avtomatik qoşulmayacaq"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Şəbəkəni dəyişmək üçün etherneti ayırın"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"İstifadəçi seçin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 31f8014e8b6c..60dee9e31fd8 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1184,4 +1184,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi trenutno ne može da se automatski poveže"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste promenili mrežu, prekinite eternet vezu"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Izaberite korisnika"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index b296aa63eedb..f234be4b020a 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1190,4 +1190,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Аўтаматычнае падключэнне да Wi-Fi адсутнічае"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Паказаць усе"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Каб падключыцца да сетак, выключыце Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выбар карыстальніка"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 84c22912a322..170a565419d3 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Засега Wi-Fi няма да се свързва автоматично"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Вижте всички"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За да превключите мрежите, прекъснете връзката с Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Избор на потребител"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 57e70a6772a0..f4b1935bfe7d 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"এখন ওয়াই-ফাই নিজে থেকে কানেক্ট হবে না"</string>
<string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটওয়ার্ক বদলাতে ইথারনেট ডিসকানেক্ট করুন"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ব্যবহারকারী বেছে নিন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index c8588ecd4cdd..4f5db012b0e9 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1184,4 +1184,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi se trenutno ne može automatski povezati"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da promijenite mrežu, isključite ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Odaberite korisnika"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index cfe70c2a22c9..ace47913916e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Per ara la Wi‑Fi no es connectarà automàticament"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per canviar de xarxa, desconnecta la connexió Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecciona un usuari"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 3d648cb03309..f4c055d18959 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1190,4 +1190,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi se prozatím nebude připojovat automaticky"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pokud chcete přepnout sítě, odpojte ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Zvolte uživatele"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index eb715aa8e7ca..3a6030e6b7fb 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Ingen automatisk forbindelse til Wi-Fi i øjeblikket"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Afbryd ethernetforbindelsen for at skifte netværk"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Vælg bruger"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index b8154923bd63..be501ca32eb1 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Zurzeit wird keine automatische WLAN-Verbindung hergestellt"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Trenne das Ethernetkabel, um das Netzwerk zu wechseln"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Nutzer auswählen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c6cc7f0d4212..145c72d3d83c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Δεν θα γίνεται προς το παρόν αυτόματη σύνδεση Wi-Fi."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Εμφάνιση όλων"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Για εναλλαγή δικτύων, αποσυνδέστε το ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Επιλογή χρήστη"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index e1006fc83780..590033a632dc 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string>
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 66b44d5ecf8b..ca7099fcc4cd 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string>
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index e1006fc83780..590033a632dc 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string>
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index e1006fc83780..590033a632dc 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string>
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 9af7322e8507..1a26024323af 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎Wi‑Fi won’t auto-connect for now‎‏‎‎‏‎"</string>
<string name="see_all_networks" msgid="3773666844913168122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎See all‎‏‎‎‏‎"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‎To switch networks, disconnect ethernet‎‏‎‎‏‎"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎Select user‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 8d53bb99f3e0..bfe22c20c69d 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora, el Wi-Fi no se conectará automáticamente"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconéctate de Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 8db8770f82bd..762c1bed1580 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora no se conectará automáticamente a redes Wi-Fi"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconecta el cable Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index c3cb5520db83..04874d21f35d 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi-ühendust ei looda praegu automaatselt"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Võrkude vahetamiseks katkestage Etherneti-ühendus"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kasutaja valimine"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 8df329a899e3..5c6fc3b0591d 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Oraingoz ez da automatikoki konektatuko wifira"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Sarea aldatzeko, deskonektatu Ethernet-a"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Hautatu erabiltzaile bat"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ae308b7ed434..ae8fab633bce 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‏فعلاً Wi-Fi به‌طور خودکار متصل نمی‌شود"</string>
<string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"برای تغییر شبکه، اترنت را قطع کنید"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"انتخاب کاربر"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index ee0cdb65a83d..9bd16bdfef60 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ei toistaiseksi yhdistä automaattisesti"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Irrota Ethernet-johto, jos haluat vaihtaa verkkoa"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Valitse käyttäjä"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 7fcbcfb6eb0b..d8b312fc6468 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connexion automatique au Wi-Fi impossible pour le moment"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, débranchez le câble Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Sélect. utilisateur"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 74e55fc90687..e897a699f9c1 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connexion automatique au Wi-Fi désactivée pour le moment"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, déconnectez l\'Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir utilisateur"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 3bcfcc8e6a88..328ac9c00140 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"De momento, a wifi non se conectará automaticamente"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de rede, desconecta a Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e713cb79f6dc..3524d85464dc 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"હમણાં પૂરતું વાઇ-ફાઇ ઑટોમૅટિક રીતે કનેક્ટ થશે નહીં"</string>
<string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"બીજા નેટવર્ક પર જવા માટે, ઇથરનેટ ડિસ્કનેક્ટ કરો"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"વપરાશકર્તા પસંદ કરો"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index edd7fc6799bf..3aec1f4d4bca 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"फ़िलहाल, वाई-फ़ाई अपने-आप कनेक्ट नहीं होगा"</string>
<string name="see_all_networks" msgid="3773666844913168122">"सभी देखें"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदलने के लिए, पहले ईथरनेट को डिसकनेक्ट करें"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"उपयोगकर्ता चुनें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b066191b021a..0b899030923e 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1184,4 +1184,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi se zasad neće automatski povezivati"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste se prebacili na drugu mrežu, odspojite Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Odabir korisnika"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 5880cf0abb02..573fa6e64a6a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A Wi-Fi-re történő csatlakozás jelenleg nem automatikus"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Hálózatváltáshoz válassza le az ethernetet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Felhasználóválasztás"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index ad3cf25467d9..c6be8c0ff3a4 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi-ն ավտոմատ չի միանա"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Տեսնել բոլորը"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Մի ցանցից մյուսին անցնելու համար անջատեք Ethernet-ը"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Ընտրեք օգտատեր"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index c42b143709c1..53c7e264b7bd 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tidak akan otomatis terhubung untuk saat ini"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk beralih jaringan, lepaskan kabel ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pilih pengguna"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 469228065c8d..76953ef56002 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tengist ekki sjálfkrafa eins og er"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aftengdu ethernet til að skipta um net"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Velja notanda"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 1d96598be708..d2467b183c6b 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connessione automatica rete Wi-Fi non attiva al momento"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per cambiare rete, scollega il cavo Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleziona utente"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 8fd2bb9abf22..b4566e891312 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1190,4 +1190,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‏ה-Wi-Fi לא יתחבר באופן אוטומטי בינתיים"</string>
<string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"כדי לעבור בין רשתות, צריך לנתק את האתרנט"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"בחירת משתמש"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 3134f73605c1..34f9c0ca89c7 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi に自動接続しません"</string>
<string name="see_all_networks" msgid="3773666844913168122">"すべて表示"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ネットワークを変更するにはイーサネット接続を解除してください"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ユーザーの選択"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index c4c73c5cb912..bead5fea3c93 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ინტერნეტს დროებით ავტომატურად არ დაუკავშირდება"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ყველას ნახვა"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ქსელების გადასართავად, გაწყვიტეთ Ethernet-თან კავშირი"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"მომხმარებლის არჩევა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index bccc0ab7d937..14e84565617f 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Әзірше Wi-Fi автоматты түрде қосылмайды."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Барлығын көру"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Желілерді ауыстыру үшін ethernet кабелін ажыратыңыз."</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Пайдаланушыны таңдау"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 7d79023c1c61..9bcc41a7b8eb 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi នឹងមិន​ភ្ជាប់ដោយស្វ័យ​ប្រវត្តិក្នុងពេលនេះទេ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ដើម្បី​ប្ដូរ​បណ្ដាញ សូមផ្ដាច់​អ៊ីសឺរណិត"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ជ្រើសរើសអ្នកប្រើប្រាស់"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index ca69a82a1295..cad8abb00467 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ಸದ್ಯದ ಮಟ್ಟಿಗೆ ವೈ-ಫೈ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕನೆಕ್ಟ್ ಆಗುವುದಿಲ್ಲ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಬದಲಿಸಲು, ಇಥರ್ನೆಟ್ ಅನ್ನು ಡಿಸ್‌ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ಬಳಕೆದಾರ ಆಯ್ಕೆಮಾಡಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 3a8657ba30a6..6541cbfddbb3 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"지금은 Wi-Fi가 자동으로 연결되지 않습니다."</string>
<string name="see_all_networks" msgid="3773666844913168122">"모두 보기"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"네트워크를 전환하려면 이더넷을 연결 해제하세요."</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"사용자 선택"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 9f242f34b300..1c6f3bee6934 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi азырынча автоматтык түрдө туташпайт"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Баарын көрүү"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Башка тармактарга которулуу үчүн Ethernet кабелин ажыратыңыз"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Колдонуучуну тандоо"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index afd914d738ae..dfe591625561 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ຈະບໍ່ເຊື່ອມຕໍ່ອັດຕະໂນມັດສຳລັບຕອນນີ້"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ເບິ່ງທັງໝົດ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ເພື່ອສະຫຼັບເຄືອຂ່າຍ, ໃຫ້ຕັດການເຊື່ອມຕໍ່ອີເທີເນັດກ່ອນ"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ເລືອກຜູ້ໃຊ້"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 233610f00cd0..57af3864216f 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1190,4 +1190,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"„Wi-Fi“ šiuo metu nebus prijungtas automatiškai"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Norėdami perjungti tinklus, atjunkite eternetą"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Naudotojo pasirinkimas"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 83e6d6e514ea..ced02b34b9b0 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1184,4 +1184,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi savienojums īslaicīgi netiks izveidots automātiski."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Lai pārslēgtu tīklus, atvienojiet tīkla Ethernet vadu."</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Lietotāja atlase"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e00108a7b9fb..7b54b631ff33 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi нема да се поврзува автоматски засега"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Прикажи ги сите"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За промена на мрежата, прекинете ја врската со етернетот"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Изберете корисник"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 49beea2dcb32..6e924aa32ee0 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"വൈഫൈ ഇപ്പോൾ സ്വയമേവ കണക്റ്റ് ചെയ്യില്ല"</string>
<string name="see_all_networks" msgid="3773666844913168122">"എല്ലാം കാണുക"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"മറ്റ് നെറ്റ്‌വർക്കുകളിലേക്ക് മാറാൻ, ഇതർനെറ്റ് വിച്ഛേദിക്കുക"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ഉപയോക്താവിനെ തിരഞ്ഞെടുക്കൂ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index f6dea18f0417..55126596f655 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi-г одоогоор автоматаар холбохгүй"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Сүлжээг сэлгэхийн тулд этернэтийг салгана уу"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Хэрэглэгч сонгох"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 6156cf592def..2864f326c8c8 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -848,7 +848,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"संगीत"</string>
<string name="keyboard_shortcut_group_applications_youtube" msgid="5078136084632450333">"YouTube"</string>
- <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"कॅलेंडर"</string>
<string name="tuner_full_zen_title" msgid="5120366354224404511">"आवाज नियंत्रणांसह दर्शवा"</string>
<string name="volume_and_do_not_disturb" msgid="502044092739382832">"व्यत्यय आणू नका"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"आवाजाच्या बटणांचा शार्टकट"</string>
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"सध्या वाय-फाय ऑटो-कनेक्ट होणार नाही"</string>
<string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क स्विच करण्यासाठी, इथरनेट केबल डिस्कनेक्ट करा"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"वापरकर्ता निवडा"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 9dde6b667bc5..96c7f893c9df 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tidak akan disambungkan secara automatik buat masa ini"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk menukar rangkaian, putuskan sambungan ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pilih pengguna"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 666f9edf8e59..1d521dcad5d6 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi က လောလောဆယ် အလိုအလျောက် ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"အားလုံးကြည့်ရန်"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ကွန်ရက်ပြောင်းရန် အီသာနက်ကို ချိတ်ဆက်မှုဖြုတ်ပါ"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"အသုံးပြုသူ ရွေးခြင်း"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index c25bec73adf7..32a37400deb7 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi kobles ikke til automatisk inntil videre"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Velg bruker"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index ce1787c26897..8b50929baa81 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"केही समयका लागि Wi-Fi स्वतः कनेक्ट हुँदैन"</string>
<string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदल्न इथरनेट डिस्कनेक्ट गर्नुहोस्"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"प्रयोगकर्ता चयन गर्नु…"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ad1403e664df..2c9b459f9b17 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi maakt momenteel niet automatisch verbinding"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Verbreek de ethernetverbinding om van netwerk te wisselen"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Gebruiker selecteren"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index e5c2a2b61825..a69c9a90e9d2 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ବର୍ତ୍ତମାନ ପାଇଁ ୱାଇ-ଫାଇ ସ୍ୱତଃ-ସଂଯୋଗ ହେବ ନାହିଁ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ନେଟୱାର୍କ ସ୍ୱିଚ୍ କରିବାକୁ, ଇଥରନେଟ୍ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ଉପଯୋଗକର୍ତ୍ତା ଚୟନ କର"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 48750cf95731..72882633541a 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ਫ਼ਿਲਹਾਲ ਵਾਈ-ਫਾਈ ਸਵੈ-ਕਨੈਕਟ ਨਹੀਂ ਹੋਵੇਗਾ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਈਥਰਨੈੱਟ ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ਵਰਤੋਂਕਾਰ ਚੁਣੋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 3635876b04da..b7fc15df8b55 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1190,4 +1190,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi nie będzie na razie włączać się automatycznie"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aby przełączać sieci, odłącz Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Wybierz użytkownika"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 8f499f7fbb04..ceb6ff58da96 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index b0c65d866b78..a103e416c947 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por agora, o Wi-Fi não irá estabelecer lig. automaticamente"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desligue a Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecione utilizador"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 8f499f7fbb04..ceb6ff58da96 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c143d5349ad4..dba5b7db65c1 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1184,4 +1184,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Deocamdată, Wi-Fi nu se poate conecta automat"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pentru a schimba rețeaua, deconectați ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Alegeți utilizatorul"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 752110ea59ec..808cb54d5af2 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1190,4 +1190,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Подключение по Wi-Fi не установится автоматически."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Показать все"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Чтобы переключиться между сетями, отключите кабель Ethernet."</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выберите профиль"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index b3a7a8e3cf7f..a81292ca95e5 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi දැනට ස්වයං-සබැඳි නොවනු ඇත"</string>
<string name="see_all_networks" msgid="3773666844913168122">"සියල්ල බලන්න"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ජාල මාරු කිරීමට, ඊතර්නෙට් විසන්ධි කරන්න"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"පරිශීලක තෝරන්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f45226b41ffc..a2cb0d6d8e08 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1190,4 +1190,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi sa teraz automaticky nepripojí"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ak chcete prepnúť siete, odpojte ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Vyberte používateľa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index ed753906d8f1..5092c030ae0b 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1190,4 +1190,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Vmesnik Wi-Fi trenutno ne bo samodejno vzpostavil povezave."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Če želite preklopiti omrežje, prekinite ethernetno povezavo."</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Izberite uporabnika"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index dc7e82564df0..adb773d168ed 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi nuk do të lidhet automatikisht për momentin"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Për të ndërruar rrjetet, shkëput Ethernet-in"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Zgjidh përdoruesin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index b486589b3bd5..a3f85c97801d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1184,4 +1184,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi тренутно не може да се аутоматски повеже"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Погледајте све"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Да бисте променили мрежу, прекините етернет везу"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Изаберите корисника"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 5db089bccc58..6073c7d1a49d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Du ansluts inte till wifi automatiskt för närvarande"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Koppla bort Ethernet för att växla nätverk"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Välj användare"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 60104f623848..5856a61924b4 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi haitaunganishwa kiotomatiki kwa sasa"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ili kubadili mitandao, tenganisha ethaneti"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Chagua mtumiaji"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-land/config.xml b/packages/SystemUI/res/values-sw720dp-land/config.xml
new file mode 100644
index 000000000000..e4573c651039
--- /dev/null
+++ b/packages/SystemUI/res/values-sw720dp-land/config.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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>
+ <!-- Max number of columns for quick controls area -->
+ <integer name="controls_max_columns">2</integer>
+
+ <!-- The maximum number of rows in the QuickQSPanel -->
+ <integer name="quick_qs_panel_max_rows">4</integer>
+
+ <!-- The maximum number of tiles in the QuickQSPanel -->
+ <integer name="quick_qs_panel_max_tiles">8</integer>
+
+ <!-- Whether to use the split 2-column notification shade -->
+ <bool name="config_use_split_notification_shade">true</bool>
+
+ <!-- The number of columns in the QuickSettings -->
+ <integer name="quick_settings_num_columns">2</integer>
+
+ <!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
+ <bool name="config_skinnyNotifsInLandscape">false</bool>
+</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-port/config.xml b/packages/SystemUI/res/values-sw720dp-port/config.xml
new file mode 100644
index 000000000000..12250861560b
--- /dev/null
+++ b/packages/SystemUI/res/values-sw720dp-port/config.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2021, 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <!-- The maximum number of tiles in the QuickQSPanel -->
+ <integer name="quick_qs_panel_max_tiles">6</integer>
+
+ <!-- The number of columns in the QuickSettings -->
+ <integer name="quick_settings_num_columns">3</integer>
+
+ <!-- The maximum number of rows in the QuickSettings -->
+ <integer name="quick_settings_max_rows">3</integer>
+
+</resources>
+
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index ac44251b2255..436f8d0998f5 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -22,14 +22,5 @@
<resources>
<integer name="status_bar_config_maxNotificationIcons">5</integer>
- <!-- The maximum number of tiles in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_tiles">6</integer>
-
- <!-- The number of columns in the QuickSettings -->
- <integer name="quick_settings_num_columns">3</integer>
-
- <!-- The maximum number of rows in the QuickSettings -->
- <integer name="quick_settings_max_rows">3</integer>
-
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 8cc4c8dd5336..8daa24f4731a 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"தற்போதைக்கு வைஃபை தானாக இணைக்கப்படாது"</string>
<string name="see_all_networks" msgid="3773666844913168122">"அனைத்தையும் காட்டு"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"நெட்வொர்க்குகளை மாற்ற ஈதர்நெட் இணைப்பைத் துண்டிக்கவும்"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"பயனரைத் தேர்வுசெய்க"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 95b8a63fa581..cab7b1c80ef2 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ప్రస్తుతానికి Wi-Fi ఆటోమేటిక్‌గా కనెక్ట్ అవ్వదు"</string>
<string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"నెట్‌వర్క్‌లను మార్చడానికి, ఈథర్‌నెట్‌ను డిస్‌కనెక్ట్ చేయండి"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"యూజర్‌ను ఎంచుకోండి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 91a24403f4d0..6da88882859f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi จะไม่เชื่อมต่ออัตโนมัติในตอนนี้"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ตัดการเชื่อมต่ออีเทอร์เน็ตเพื่อสลับเครือข่าย"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"เลือกผู้ใช้"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index dcde0fc67584..a9c588699311 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Hindi awtomatikong kokonekta ang Wi-Fi sa ngayon"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para lumipat ng network, idiskonekta ang ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pumili ng user"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 367d0bf3e372..8fe7862d1469 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Şu anda kablosuz ağa otomatik olarak bağlanılamıyor"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ağ değiştirmek için ethernet bağlantısını kesin"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kullanıcı seçin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index e692a36985b1..596ba953844e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1190,4 +1190,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Пристрій не підключатиметься до Wi-Fi автоматично"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Показати все"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Щоб вибрати іншу мережу, від’єднайте кабель Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Виберіть користувача"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 44b91ad7419e..f05c709d131b 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‏ابھی Wi-Fi خود کار طور پر منسلک نہیں ہوگا"</string>
<string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"نیٹ ورکس پر سوئچ کرنے کیلئے، ایتھرنیٹ غیر منسلک کریں"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"صارف منتخب کریں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index f0afb6cb704b..e9c20a92219f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi hozir avtomatik ulanmaydi"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Boshqa tarmoqqa almashish uchun Ethernet tarmogʻini uzing"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Foydalanuvchini tanlang"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index b0f1dcf31133..07a08ad1270c 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Tạm thời, Wi-Fi sẽ không tự động kết nối"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Để chuyển mạng, hãy rút cáp Ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Chọn người dùng"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 7caae5df46e5..377d15cba0e3 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WLAN 暂时无法自动连接"</string>
<string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切换网络,请断开以太网连接"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"选择用户"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 4a8567d7d29b..73df468c1aa2 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"目前系統不會自動連線至 Wi-Fi"</string>
<string name="see_all_networks" msgid="3773666844913168122">"顯示全部"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網絡,請中斷以太網連線"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"選取使用者"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index b444d4223b7f..f883b1091f7b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"目前不會自動連上 Wi-Fi"</string>
<string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網路,請中斷乙太網路連線"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"選取使用者"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 79884764562a..e1c1f6fa219b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1178,4 +1178,5 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"I-Wi-Fi ngeke ixhume ngokuzenzakalelayo okwamanje"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ukuze ushintshe amanethiwekhi, nqamula i-ethernet"</string>
+ <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Khetha umsebenzisi"</string>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 946bbc289a03..e8ebeddba7f9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1439,10 +1439,10 @@
<!-- Output switcher panel related dimensions -->
<dimen name="media_output_dialog_list_margin">12dp</dimen>
<dimen name="media_output_dialog_list_max_height">364dp</dimen>
- <dimen name="media_output_dialog_header_album_icon_size">52dp</dimen>
- <dimen name="media_output_dialog_header_back_icon_size">36dp</dimen>
+ <dimen name="media_output_dialog_header_album_icon_size">48dp</dimen>
+ <dimen name="media_output_dialog_header_back_icon_size">32dp</dimen>
<dimen name="media_output_dialog_header_icon_padding">16dp</dimen>
- <dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
+ <dimen name="media_output_dialog_icon_corner_radius">8dp</dimen>
<dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
<!-- Distance that the full shade transition takes in order for qs to fully transition to the
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index d6d98b9397ac..740e97c4e443 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -48,6 +48,8 @@
<bool name="flag_ongoing_call_in_immersive">false</bool>
+ <bool name="flag_ongoing_call_in_immersive_chip_tap">true</bool>
+
<bool name="flag_smartspace">false</bool>
<bool name="flag_smartspace_deduping">true</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ec63df5e0fe2..523b9c8c8f87 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2830,6 +2830,8 @@
<string name="controls_media_settings_button">Settings</string>
<!-- Description for media control's playing media item, including information for the media's title, the artist, and source app [CHAR LIMIT=NONE]-->
<string name="controls_media_playing_item_description"><xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> by <xliff:g id="artist_name" example="Various artists">%2$s</xliff:g> is playing from <xliff:g id="app_label" example="Spotify">%3$s</xliff:g></string>
+ <!-- Content description for media cotnrols progress bar [CHAR_LIMIT=NONE] -->
+ <string name="controls_media_seekbar_description"><xliff:g id="elapsed_time" example="1:30">%1$s</xliff:g> of <xliff:g id="total_time" example="3:00">%2$s</xliff:g></string>
<!-- Title for Smartspace recommendation card within media controls. The "Play" means the action to play a media [CHAR_LIMIT=10] -->
<string name="controls_media_smartspace_rec_title">Play</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 70749be9e4cf..ff299eae8cf2 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -515,6 +515,10 @@
<item name="android:background">@drawable/btn_borderless_rect</item>
</style>
+ <style name="MediaOutputRoundedOutlinedButton" parent="@android:style/Widget.Material.Button">
+ <item name="android:background">@drawable/media_output_dialog_button_background</item>
+ </style>
+
<style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
<item name="android:windowActionBar">false</item>
<item name="preferenceTheme">@style/TunerPreferenceTheme</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 8cfd225fc4df..9aa03a922c72 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -265,7 +265,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
boolean wasShowingUnlockIcon = mShowUnlockIcon;
mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen()
&& (!mUdfpsEnrolled || !mRunningFPS);
- mShowUnlockIcon = mCanDismissLockScreen && isLockScreen();
+ mShowUnlockIcon = (mCanDismissLockScreen || mUserUnlockedWithBiometric) && isLockScreen();
mShowAODFpIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS;
final CharSequence prevContentDescription = mView.getContentDescription();
@@ -477,13 +477,15 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@Override
public void onBiometricRunningStateChanged(boolean running,
BiometricSourceType biometricSourceType) {
+ final boolean wasRunningFps = mRunningFPS;
+ final boolean wasUserUnlockedWithBiometric = mUserUnlockedWithBiometric;
mUserUnlockedWithBiometric =
mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
KeyguardUpdateMonitor.getCurrentUser());
if (biometricSourceType == FINGERPRINT) {
mRunningFPS = running;
- if (!mRunningFPS) {
+ if (wasRunningFps && !mRunningFPS) {
if (mCancelDelayedUpdateVisibilityRunnable != null) {
mCancelDelayedUpdateVisibilityRunnable.run();
}
@@ -493,10 +495,14 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
// button in this case, so we delay updating the visibility by 50ms.
mCancelDelayedUpdateVisibilityRunnable =
mExecutor.executeDelayed(() -> updateVisibility(), 50);
- } else {
- updateVisibility();
+ return;
}
}
+
+ if (wasUserUnlockedWithBiometric != mUserUnlockedWithBiometric
+ || wasRunningFps != mRunningFPS) {
+ updateVisibility();
+ }
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index da69f4556547..f11dc9313852 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -824,12 +824,8 @@ public abstract class AuthBiometricView extends LinearLayout {
return new AuthDialog.LayoutParams(width, totalHeight);
}
- /**
- * Simple heuristic which should return true displays that are larger than a normal phone.
- * For example, tablet displays, or the unfolded display for foldables.
- */
- private boolean isLargeDisplay(int width, int height) {
- return width > 1200 && height > 1200;
+ private boolean isLargeDisplay() {
+ return com.android.systemui.util.Utils.shouldUseSplitNotificationShade(getResources());
}
@Override
@@ -837,12 +833,12 @@ public abstract class AuthBiometricView extends LinearLayout {
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int height = MeasureSpec.getSize(heightMeasureSpec);
- Log.d(TAG, "Width: " + width + ", height: " + height);
+ final boolean isLargeDisplay = isLargeDisplay();
final int newWidth;
- if (isLargeDisplay(width, height)) {
- // TODO: Unless we can come up with a one-size-fits-all equation, we may want to
- // consider moving this to an overlay.
+ if (isLargeDisplay) {
+ // TODO(b/201811580): Unless we can come up with a one-size-fits-all equation, we may
+ // want to consider moving this to an overlay.
newWidth = 2 * Math.min(width, height) / 3;
} else {
newWidth = Math.min(width, height);
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
index f81811ac0ffb..15072a52f531 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -166,6 +166,11 @@ public class FeatureFlags {
&& mFlagReader.isEnabled(R.bool.flag_ongoing_call_in_immersive);
}
+ public boolean isOngoingCallInImmersiveChipTapEnabled() {
+ return isOngoingCallInImmersiveEnabled()
+ && mFlagReader.isEnabled(R.bool.flag_ongoing_call_in_immersive_chip_tap);
+ }
+
public boolean isSmartspaceEnabled() {
return mFlagReader.isEnabled(R.bool.flag_smartspace);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 424f80177d9c..e73eb66a51bf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -55,6 +55,7 @@ import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.util.animation.TransitionLayout;
@@ -119,6 +120,7 @@ public class MediaControlPanel {
private int mSmartspaceMediaItemsCount;
private MediaCarouselController mMediaCarouselController;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
+ private final FalsingManager mFalsingManager;
/**
* Initialize a new control panel
@@ -131,7 +133,8 @@ public class MediaControlPanel {
ActivityStarter activityStarter, MediaViewController mediaViewController,
SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
KeyguardDismissUtil keyguardDismissUtil, MediaOutputDialogFactory
- mediaOutputDialogFactory, MediaCarouselController mediaCarouselController) {
+ mediaOutputDialogFactory, MediaCarouselController mediaCarouselController,
+ FalsingManager falsingManager) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
@@ -141,6 +144,7 @@ public class MediaControlPanel {
mKeyguardDismissUtil = keyguardDismissUtil;
mMediaOutputDialogFactory = mediaOutputDialogFactory;
mMediaCarouselController = mediaCarouselController;
+ mFalsingManager = falsingManager;
loadDimens();
mSeekBarViewModel.setLogSmartspaceClick(() -> {
@@ -235,10 +239,14 @@ public class MediaControlPanel {
}
});
mPlayerViewHolder.getCancel().setOnClickListener(v -> {
- closeGuts();
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ closeGuts();
+ }
});
mPlayerViewHolder.getSettings().setOnClickListener(v -> {
- mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ }
});
}
@@ -259,10 +267,14 @@ public class MediaControlPanel {
}
});
mRecommendationViewHolder.getCancel().setOnClickListener(v -> {
- closeGuts();
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ closeGuts();
+ }
});
mRecommendationViewHolder.getSettings().setOnClickListener(v -> {
- mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ }
});
}
@@ -299,6 +311,7 @@ public class MediaControlPanel {
PendingIntent clickIntent = data.getClickIntent();
if (clickIntent != null) {
mPlayerViewHolder.getPlayer().setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
if (mMediaViewController.isGutsVisible()) return;
logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
@@ -365,8 +378,12 @@ public class MediaControlPanel {
setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
seamlessView.setOnClickListener(
- v -> mMediaOutputDialogFactory.create(data.getPackageName(), true,
- mPlayerViewHolder.getSeamlessButton()));
+ v -> {
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ mMediaOutputDialogFactory.create(data.getPackageName(), true,
+ mPlayerViewHolder.getSeamlessButton());
+ }
+ });
ImageView iconView = mPlayerViewHolder.getSeamlessIcon();
TextView deviceName = mPlayerViewHolder.getSeamlessText();
@@ -417,9 +434,11 @@ public class MediaControlPanel {
} else {
button.setEnabled(true);
button.setOnClickListener(v -> {
- logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
- /* isRecommendationCard */ false);
- action.run();
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
+ /* isRecommendationCard */ false);
+ action.run();
+ }
});
}
boolean visibleInCompat = actionsWhenCollapsed.contains(i);
@@ -451,6 +470,8 @@ public class MediaControlPanel {
mPlayerViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
mPlayerViewHolder.getDismiss().setEnabled(isDismissible);
mPlayerViewHolder.getDismiss().setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
+
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
/* isRecommendationCard */ false);
@@ -633,6 +654,8 @@ public class MediaControlPanel {
mSmartspaceMediaItemsCount = uiComponentIndex;
// Set up long press to show guts setting panel.
mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
+
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
/* isRecommendationCard */ true);
closeGuts();
@@ -788,6 +811,8 @@ public class MediaControlPanel {
}
view.setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
+
logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
/* isRecommendationCard */ true,
interactedSubcardRank,
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index f17ad6f09128..33ef19ad040f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -50,6 +50,7 @@ class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarVi
holder.seekBar.setProgress(0)
holder.elapsedTimeView.setText("")
holder.totalTimeView.setText("")
+ holder.seekBar.contentDescription = ""
return
}
@@ -61,16 +62,22 @@ class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarVi
setVerticalPadding(seekBarEnabledVerticalPadding)
}
- data.duration?.let {
- holder.seekBar.setMax(it)
- holder.totalTimeView.setText(DateUtils.formatElapsedTime(
- it / DateUtils.SECOND_IN_MILLIS))
- }
+ holder.seekBar.setMax(data.duration)
+ val totalTimeString = DateUtils.formatElapsedTime(
+ data.duration / DateUtils.SECOND_IN_MILLIS)
+ holder.totalTimeView.setText(totalTimeString)
data.elapsedTime?.let {
holder.seekBar.setProgress(it)
- holder.elapsedTimeView.setText(DateUtils.formatElapsedTime(
- it / DateUtils.SECOND_IN_MILLIS))
+ val elapsedTimeString = DateUtils.formatElapsedTime(
+ it / DateUtils.SECOND_IN_MILLIS)
+ holder.elapsedTimeView.setText(elapsedTimeString)
+
+ holder.seekBar.contentDescription = holder.seekBar.context.getString(
+ R.string.controls_media_seekbar_description,
+ elapsedTimeString,
+ totalTimeString
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index d1b6548132a6..125b87b31e63 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -135,14 +135,11 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
if (currentlyConnected && mController.isActiveRemoteDevice(device)
&& mController.getSelectableMediaDevice().size() > 0) {
// Init active device layout
- mDivider.setVisibility(View.VISIBLE);
- mDivider.setTransitionAlpha(1);
mAddIcon.setVisibility(View.VISIBLE);
mAddIcon.setTransitionAlpha(1);
mAddIcon.setOnClickListener(this::onEndItemClick);
} else {
// Init non-active device layout
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
}
if (mCurrentActivePosition == position) {
@@ -181,7 +178,6 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
super.onBind(customizedItem, topMargin, bottomMargin);
if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
mCheckBox.setVisibility(View.GONE);
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
mBottomDivider.setVisibility(View.GONE);
setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
@@ -196,13 +192,10 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mBottomDivider.setVisibility(View.GONE);
mCheckBox.setVisibility(View.GONE);
if (mController.getSelectableMediaDevice().size() > 0) {
- mDivider.setVisibility(View.VISIBLE);
- mDivider.setTransitionAlpha(1);
mAddIcon.setVisibility(View.VISIBLE);
mAddIcon.setTransitionAlpha(1);
mAddIcon.setOnClickListener(this::onEndItemClick);
} else {
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
}
mTitleIcon.setImageDrawable(getSpeakerDrawable());
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 0890841eb4fb..1ffc2c4c35ba 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -121,7 +121,6 @@ public abstract class MediaOutputBaseAdapter extends
final ProgressBar mProgressBar;
final SeekBar mSeekBar;
final RelativeLayout mTwoLineLayout;
- final View mDivider;
final View mBottomDivider;
final CheckBox mCheckBox;
private String mDeviceId;
@@ -136,7 +135,6 @@ public abstract class MediaOutputBaseAdapter extends
mTitleIcon = view.requireViewById(R.id.title_icon);
mProgressBar = view.requireViewById(R.id.volume_indeterminate_progress);
mSeekBar = view.requireViewById(R.id.volume_seekbar);
- mDivider = view.requireViewById(R.id.end_divider);
mBottomDivider = view.requireViewById(R.id.bottom_divider);
mAddIcon = view.requireViewById(R.id.add_icon);
mCheckBox = view.requireViewById(R.id.check_box);
@@ -151,21 +149,12 @@ public abstract class MediaOutputBaseAdapter extends
return;
}
mTitleIcon.setImageIcon(icon);
- setMargin(topMargin, bottomMargin);
});
});
}
void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
- setMargin(topMargin, bottomMargin);
- }
-
- private void setMargin(boolean topMargin, boolean bottomMargin) {
- ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mContainerLayout
- .getLayoutParams();
- params.topMargin = topMargin ? mMargin : 0;
- params.bottomMargin = bottomMargin ? mMargin : 0;
- mContainerLayout.setLayoutParams(params);
+ // TODO (b/201718621): clean up method after adjustment
}
void setSingleLineLayout(CharSequence title, boolean bFocused) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 85d0802012ac..6895ef10fd07 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -175,7 +175,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
if (!mAdapter.isDragging() && !mAdapter.isAnimating()) {
int currentActivePosition = mAdapter.getCurrentActivePosition();
- if (currentActivePosition >= 0) {
+ if (currentActivePosition >= 0 && currentActivePosition < mAdapter.getItemCount()) {
mAdapter.notifyItemChanged(currentActivePosition);
} else {
mAdapter.notifyDataSetChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 437a0c85a6e0..42dd8862576b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -73,6 +73,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
private final String mPackageName;
private final Context mContext;
private final MediaSessionManager mMediaSessionManager;
+ private final LocalBluetoothManager mLocalBluetoothManager;
private final ShadeController mShadeController;
private final ActivityStarter mActivityStarter;
private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -85,7 +86,6 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
private MediaController mMediaController;
@VisibleForTesting
Callback mCallback;
- Callback mPreviousCallback;
@VisibleForTesting
LocalMediaManager mLocalMediaManager;
@@ -101,6 +101,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
+ mLocalBluetoothManager = lbm;
mShadeController = shadeController;
mActivityStarter = starter;
mAboveStatusbar = aboveStatusbar;
@@ -135,19 +136,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
}
return;
}
-
- if (mPreviousCallback != null) {
- Log.w(TAG,
- "Callback started when mPreviousCallback is not null, which is unexpected");
- mPreviousCallback.dismissDialog();
- }
-
- // If we start the output group dialog when the output dialog is shown, we need to keep a
- // reference to the output dialog to set it back as the callback once we dismiss the output
- // group dialog.
- mPreviousCallback = mCallback;
mCallback = cb;
-
mLocalMediaManager.unregisterCallback(this);
mLocalMediaManager.stopScan();
mLocalMediaManager.registerCallback(this);
@@ -163,15 +152,6 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mLocalMediaManager.stopScan();
}
mMediaDevices.clear();
-
- // If there was a previous callback, i.e. we just dismissed the output group dialog and are
- // now back on the output dialog, then we reset the callback to its previous value.
- mCallback = null;
- Callback previous = mPreviousCallback;
- mPreviousCallback = null;
- if (previous != null) {
- start(previous);
- }
}
@Override
@@ -480,7 +460,11 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
void launchMediaOutputGroupDialog(View mediaOutputDialog) {
// We show the output group dialog from the output dialog.
- MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar, this);
+ MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
+ mAboveStatusbar, mMediaSessionManager, mLocalBluetoothManager, mShadeController,
+ mActivityStarter, mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar,
+ controller);
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
index 968c3506f39f..11d76dba1423 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
@@ -96,7 +96,6 @@ public class MediaOutputGroupAdapter extends MediaOutputBaseAdapter {
@Override
void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
super.onBind(device, topMargin, bottomMargin, position);
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
mBottomDivider.setVisibility(View.GONE);
mCheckBox.setVisibility(View.VISIBLE);
@@ -135,7 +134,6 @@ public class MediaOutputGroupAdapter extends MediaOutputBaseAdapter {
mTitleIcon.setImageDrawable(getSpeakerDrawable());
mBottomDivider.setVisibility(View.VISIBLE);
mCheckBox.setVisibility(View.GONE);
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
initSessionSeekbar();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index bfb63ea5e7c3..90d3448ac1ef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -35,7 +35,6 @@ import com.android.systemui.qs.TouchAnimator.Builder;
import com.android.systemui.qs.TouchAnimator.Listener;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.tileimpl.HeightOverrideable;
-import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.wm.shell.animation.Interpolators;
@@ -170,19 +169,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
}
}
- void startAlphaAnimation(boolean show) {
- if (show == mToShowing) {
- return;
- }
- mToShowing = show;
- if (show) {
- CrossFadeHelper.fadeIn(mQs.getView(), QQS_FADE_IN_DURATION, 0 /* delay */);
- } else {
- CrossFadeHelper.fadeOut(mQs.getView(), QQS_FADE_OUT_DURATION, 0 /* delay */,
- null /* endRunnable */);
- }
- }
-
/**
* Sets whether or not the keyguard is currently being shown with a collapsed header.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index b8376da8a885..f300efca8a23 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -89,6 +89,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private int mLayoutDirection;
private QSFooter mFooter;
private float mLastQSExpansion = -1;
+ private float mLastPanelFraction;
private boolean mQsDisabled;
private ImageView mQsDragHandler;
@@ -120,7 +121,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
* When true, QS will translate from outside the screen. It will be clipped with parallax
* otherwise.
*/
- private boolean mTranslateWhileExpanding;
+ private boolean mInSplitShade;
private boolean mPulseExpanding;
/**
@@ -135,6 +136,12 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private DumpManager mDumpManager;
+ /**
+ * Progress of pull down from the center of the lock screen.
+ * @see com.android.systemui.statusbar.LockscreenShadeTransitionController
+ */
+ private float mFullShadeProgress;
+
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
InjectionInflationController injectionInflater, QSTileHost qsTileHost,
@@ -226,7 +233,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
boolean sizeChanged = (oldTop - oldBottom) != (top - bottom);
if (sizeChanged) {
- setQsExpansion(mLastQSExpansion, mLastHeaderTranslation);
+ setQsExpansion(mLastQSExpansion, mLastPanelFraction,
+ mLastHeaderTranslation);
}
});
mQSPanelController.setUsingHorizontalLayoutChangeListener(
@@ -408,7 +416,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mQSAnimator.setShowCollapsedOnKeyguard(showCollapsed);
}
if (!showCollapsed && isKeyguardState()) {
- setQsExpansion(mLastQSExpansion, 0);
+ setQsExpansion(mLastQSExpansion, mLastPanelFraction, 0);
}
}
}
@@ -476,33 +484,30 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
@Override
- public void setTranslateWhileExpanding(boolean shouldTranslate) {
- mTranslateWhileExpanding = shouldTranslate;
- mQSAnimator.setTranslateWhileExpanding(shouldTranslate);
+ public void setInSplitShade(boolean inSplitShade) {
+ mInSplitShade = inSplitShade;
+ mQSAnimator.setTranslateWhileExpanding(inSplitShade);
}
@Override
- public void setTransitionToFullShadeAmount(float pxAmount, boolean animated) {
+ public void setTransitionToFullShadeAmount(float pxAmount, float progress) {
boolean isTransitioningToFullShade = pxAmount > 0;
if (isTransitioningToFullShade != mTransitioningToFullShade) {
mTransitioningToFullShade = isTransitioningToFullShade;
updateShowCollapsedOnKeyguard();
- setQsExpansion(mLastQSExpansion, mLastHeaderTranslation);
}
+ mFullShadeProgress = progress;
+ setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation);
}
@Override
- public void setQsExpansion(float expansion, float proposedTranslation) {
- if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + proposedTranslation);
+ public void setQsExpansion(float expansion, float panelExpansionFraction,
+ float proposedTranslation) {
float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
- if (mQSAnimator != null) {
- final boolean showQSOnLockscreen = expansion > 0;
- final boolean showQSUnlocked = headerTranslation == 0 || !mTranslateWhileExpanding;
- mQSAnimator.startAlphaAnimation(showQSOnLockscreen || showQSUnlocked
- || mTransitioningToFullShade);
- }
+ float progress = mTransitioningToFullShade ? mFullShadeProgress : panelExpansionFraction;
+ setAlphaAnimationProgress(mInSplitShade ? progress : 1);
mContainer.setExpansion(expansion);
- final float translationScaleY = (mTranslateWhileExpanding
+ final float translationScaleY = (mInSplitShade
? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
boolean onKeyguardAndExpanded = isKeyguardState() && !mShowCollapsedOnKeyguard;
if (!mHeaderAnimating && !headerWillBeAnimating()) {
@@ -519,6 +524,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
return;
}
mLastHeaderTranslation = headerTranslation;
+ mLastPanelFraction = panelExpansionFraction;
mLastQSExpansion = expansion;
mLastKeyguardAndExpanded = onKeyguardAndExpanded;
mLastViewHeight = currentHeight;
@@ -560,6 +566,17 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
updateMediaPositions();
}
+ private void setAlphaAnimationProgress(float progress) {
+ final View view = getView();
+ if (progress == 0 && view.getVisibility() != View.INVISIBLE) {
+ view.setVisibility(View.INVISIBLE);
+ } else if (progress > 0 && view.getVisibility() != View.VISIBLE) {
+ view.setVisibility((View.VISIBLE));
+ }
+ float alpha = Interpolators.getNotificationScrimAlpha(progress, true /* uiContent */);
+ view.setAlpha(alpha);
+ }
+
private void updateQsBounds() {
if (mLastQSExpansion == 1.0f) {
// Fully expanded, let's set the layout bounds as clip bounds. This is necessary because
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 8a397199dc84..4f932a36504c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -819,12 +819,15 @@ public class KeyguardIndicationController {
}
}
- private void showTryFingerprintMsg(String a11yString) {
+ private void showTryFingerprintMsg(int msgId, String a11yString) {
if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
// if udfps available, there will always be a tappable affordance to unlock
// For example, the lock icon
if (mKeyguardBypassController.getUserHasDeviceEntryIntent()) {
showTransientIndication(R.string.keyguard_unlock_press);
+ } else if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
+ // since face is locked out, simply show "try fingerprint"
+ showTransientIndication(R.string.keyguard_try_fingerprint);
} else {
showTransientIndication(R.string.keyguard_face_failed_use_fp);
}
@@ -916,7 +919,7 @@ public class KeyguardIndicationController {
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
if (biometricSourceType == BiometricSourceType.FACE
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
- showTryFingerprintMsg(helpString);
+ showTryFingerprintMsg(msgId, helpString);
return;
}
showTransientIndication(helpString, false /* isError */, showActionToUnlock);
@@ -936,7 +939,7 @@ public class KeyguardIndicationController {
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()
&& !mStatusBarKeyguardViewManager.isBouncerShowing()
&& mKeyguardUpdateMonitor.isScreenOn()) {
- showTryFingerprintMsg(errString);
+ showTryFingerprintMsg(msgId, errString);
return;
}
if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
@@ -945,7 +948,7 @@ public class KeyguardIndicationController {
if (!mStatusBarKeyguardViewManager.isBouncerShowing()
&& mKeyguardUpdateMonitor.isUdfpsEnrolled()
&& mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
- showTryFingerprintMsg(errString);
+ showTryFingerprintMsg(msgId, errString);
} else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
mStatusBarKeyguardViewManager.showBouncerMessage(
mContext.getResources().getString(R.string.keyguard_unlock_press),
@@ -989,8 +992,8 @@ public class KeyguardIndicationController {
private boolean shouldSuppressFaceMsgAndShowTryFingerprintMsg() {
// For dual biometric, don't show face auth messages
return mKeyguardUpdateMonitor.isFingerprintDetectionRunning()
- && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
- true /* isStrongBiometric */);
+ && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+ true /* isStrongBiometric */);
}
private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 03d8e7e03c0f..77e329f94a36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -208,6 +208,11 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
lateinit var isScrimOpaqueChangedListener: Consumer<Boolean>
/**
+ * A runnable to call when the scrim has been fully revealed. This is only invoked once
+ */
+ var fullyRevealedRunnable: Runnable? = null
+
+ /**
* How much of the underlying views are revealed, in percent. 0 means they will be completely
* obscured and 1 means they'll be fully visible.
*/
@@ -218,10 +223,20 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
revealEffect.setRevealAmountOnScrim(value, this)
updateScrimOpaque()
+ maybeTriggerFullyRevealedRunnable()
invalidate()
}
}
+ private fun maybeTriggerFullyRevealedRunnable() {
+ if (revealAmount == 1.0f) {
+ fullyRevealedRunnable?.let {
+ it.run()
+ fullyRevealedRunnable = null
+ }
+ }
+ }
+
/**
* The [LightRevealEffect] used to manipulate the radial gradient whenever [revealAmount]
* changes.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index ca18b076b1e9..dca7f70d3470 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -298,9 +298,8 @@ class LockscreenShadeTransitionController @Inject constructor(
nsslController.setTransitionToFullShadeAmount(field)
notificationPanelController.setTransitionToFullShadeAmount(field,
false /* animate */, 0 /* delay */)
- // TODO: appear qs also in split shade
- val qsAmount = if (useSplitShade) 0f else field
- qS.setTransitionToFullShadeAmount(qsAmount, false /* animate */)
+ val progress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
+ qS.setTransitionToFullShadeAmount(field, progress)
// TODO: appear media also in split shade
val mediaAmount = if (useSplitShade) 0f else field
mediaHierarchyManager.setTransitionToFullShadeAmount(mediaAmount)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 7aa2dc7e0785..d4f54e1cd7b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -36,7 +36,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
-import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.PanelExpansionListener
import com.android.systemui.statusbar.phone.ScrimController
@@ -73,6 +72,10 @@ class NotificationShadeDepthController @Inject constructor(
private const val TAG = "DepthController"
}
+ /**
+ * Did we already unblur while dozing?
+ */
+ private var alreadyUnblurredWhileDozing = false
lateinit var root: View
private var blurRoot: View? = null
private var keyguardAnimator: Animator? = null
@@ -229,9 +232,11 @@ class NotificationShadeDepthController @Inject constructor(
private val keyguardStateCallback = object : KeyguardStateController.Callback {
override fun onKeyguardFadingAwayChanged() {
if (!keyguardStateController.isKeyguardFadingAway ||
- biometricUnlockController.mode != MODE_WAKE_AND_UNLOCK) {
+ !biometricUnlockController.isWakeAndUnlock) {
return
}
+ // When wakeAndUnlocking the screen remains dozing, so we have to manually trigger
+ // the unblur earlier
keyguardAnimator?.cancel()
keyguardAnimator = ValueAnimator.ofFloat(1f, 0f).apply {
@@ -253,6 +258,7 @@ class NotificationShadeDepthController @Inject constructor(
})
start()
}
+ alreadyUnblurredWhileDozing = statusBarStateController.dozeAmount != 0.0f
}
override fun onKeyguardShowingChanged() {
@@ -274,10 +280,24 @@ class NotificationShadeDepthController @Inject constructor(
if (isDozing) {
shadeAnimation.finishIfRunning()
brightnessMirrorSpring.finishIfRunning()
+
+ // unset this for safety, to be ready for the next wakeup
+ alreadyUnblurredWhileDozing = false
}
}
override fun onDozeAmountChanged(linear: Float, eased: Float) {
+ if (alreadyUnblurredWhileDozing) {
+ if (linear == 0.0f) {
+ // We finished waking up, let's reset
+ alreadyUnblurredWhileDozing = false
+ } else {
+ // We've already handled the unbluring from the keyguardAnimator above.
+ // if we would continue, we'd play another unzoom / blur animation from the
+ // dozing changing.
+ return
+ }
+ }
wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased)
scheduleUpdate()
}
@@ -435,6 +455,7 @@ class NotificationShadeDepthController @Inject constructor(
it.println("blursDisabledForAppLaunch: $blursDisabledForAppLaunch")
it.println("qsPanelExpansion: $qsPanelExpansion")
it.println("transitionToFullShadeProgress: $transitionToFullShadeProgress")
+ it.println("alreadyUnblurredWhileDozing: $alreadyUnblurredWhileDozing")
it.println("lastAppliedBlur: $lastAppliedBlur")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 19876ba063bb..cbb3aba5cc64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -446,7 +446,7 @@ public class StatusBarStateControllerImpl implements
mIsFullscreen = isFullscreen;
synchronized (mListeners) {
for (RankedListener rl : new ArrayList<>(mListeners)) {
- rl.mListener.onFullscreenStateChanged(isFullscreen, true /* isImmersive */);
+ rl.mListener.onFullscreenStateChanged(isFullscreen);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 0352212ced1b..5758ba41eb1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -69,6 +69,7 @@ import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.phone.SystemUIHostDialogProvider;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
+import com.android.systemui.statusbar.phone.ongoingcall.SwipeStatusBarAwayGestureHandler;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -255,15 +256,30 @@ public interface StatusBarDependenciesModule {
IActivityManager iActivityManager,
OngoingCallLogger logger,
DumpManager dumpManager,
- StatusBarWindowController statusBarWindowController) {
+ StatusBarWindowController statusBarWindowController,
+ SwipeStatusBarAwayGestureHandler swipeStatusBarAwayGestureHandler,
+ StatusBarStateController statusBarStateController) {
Optional<StatusBarWindowController> windowController =
featureFlags.isOngoingCallInImmersiveEnabled()
? Optional.of(statusBarWindowController)
: Optional.empty();
+ Optional<SwipeStatusBarAwayGestureHandler> gestureHandler =
+ featureFlags.isOngoingCallInImmersiveEnabled()
+ ? Optional.of(swipeStatusBarAwayGestureHandler)
+ : Optional.empty();
OngoingCallController ongoingCallController =
new OngoingCallController(
- notifCollection, featureFlags, systemClock, activityStarter, mainExecutor,
- iActivityManager, logger, dumpManager, windowController);
+ notifCollection,
+ featureFlags,
+ systemClock,
+ activityStarter,
+ mainExecutor,
+ iActivityManager,
+ logger,
+ dumpManager,
+ windowController,
+ gestureHandler,
+ statusBarStateController);
ongoingCallController.init();
return ongoingCallController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 27770c7e53b3..1dface6a5bc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -984,7 +984,7 @@ public class NotificationPanelViewController extends PanelViewController {
Utils.shouldUseSplitNotificationShade(mResources);
mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
if (mQs != null) {
- mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
+ mQs.setInSplitShade(mShouldUseSplitNotificationShade);
}
int topMargin = mShouldUseSplitNotificationShade ? mSplitShadeStatusBarHeight :
@@ -2202,7 +2202,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateQsExpansion() {
if (mQs == null) return;
float qsExpansionFraction = computeQsExpansionFraction();
- mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
+ mQs.setQsExpansion(qsExpansionFraction, getExpandedFraction(), getHeaderTranslation());
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction);
mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY);
@@ -3338,9 +3338,9 @@ public class NotificationPanelViewController extends PanelViewController {
* cases, such as if there's a heads-up notification.
*/
public void setPanelScrimMinFraction(float minFraction) {
- mBar.onPanelMinFractionChanged(minFraction);
mMinFraction = minFraction;
mDepthController.setPanelPullDownMinFraction(mMinFraction);
+ mScrimController.setPanelScrimMinFraction(mMinFraction);
}
public void clearNotificationEffects() {
@@ -3456,7 +3456,7 @@ public class NotificationPanelViewController extends PanelViewController {
mQs.setExpandClickListener(mOnClickListener);
mQs.setHeaderClickable(isQsExpansionEnabled());
mQs.setOverscrolling(mStackScrollerOverscrolling);
- mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
+ mQs.setInSplitShade(mShouldUseSplitNotificationShade);
// recompute internal state when qspanel height changes
mQs.getView().addOnLayoutChangeListener(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 1f1090d7168b..310fe73df1ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -146,11 +146,6 @@ public abstract class PanelBar extends FrameLayout {
}
/**
- * Percentage of panel expansion offset, caused by pulling down on a heads-up.
- */
- abstract void onPanelMinFractionChanged(float minFraction);
-
- /**
* @param frac the fraction from the expansion in [0, 1]
* @param expanded whether the panel is currently expanded; this is independent from the
* fraction as the panel also might be expanded if the fraction is 0
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 768567b8b474..c23577c523e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -385,11 +385,16 @@ public abstract class PanelViewController {
final boolean expand;
if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
- // If we get a cancel, put the shade back to the state it was in when the gesture
- // started
- if (onKeyguard) {
+ // If the keyguard is fading away, don't expand it again. This can happen if you're
+ // swiping to unlock, the app below the keyguard is in landscape, and the screen
+ // rotates while your finger is still down after the swipe to unlock.
+ if (mKeyguardStateController.isKeyguardFadingAway()) {
+ expand = false;
+ } else if (onKeyguard) {
expand = true;
} else {
+ // If we get a cancel, put the shade back to the state it was in when the
+ // gesture started
expand = !mPanelClosedOnDown;
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 1cca4777da0a..150d9c8fcce6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -18,8 +18,6 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
-import static java.lang.Float.isNaN;
-
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
@@ -57,7 +55,6 @@ public class PhoneStatusBarView extends PanelBar {
StatusBar mBar;
private ScrimController mScrimController;
- private float mMinFraction;
private Runnable mHideExpandedRunnable = new Runnable() {
@Override
public void run() {
@@ -268,20 +265,8 @@ public class PhoneStatusBarView extends PanelBar {
}
@Override
- public void onPanelMinFractionChanged(float minFraction) {
- if (isNaN(minFraction)) {
- throw new IllegalArgumentException("minFraction cannot be NaN");
- }
- if (mMinFraction != minFraction) {
- mMinFraction = minFraction;
- updateScrimFraction();
- }
- }
-
- @Override
public void panelExpansionChanged(float frac, boolean expanded) {
super.panelExpansionChanged(frac, expanded);
- updateScrimFraction();
if ((frac == 0 || frac == 1)) {
if (mPanelExpansionStateChangedListener != null) {
mPanelExpansionStateChangedListener.onPanelExpansionStateChanged();
@@ -302,15 +287,6 @@ public class PhoneStatusBarView extends PanelBar {
mPanelEnabledProvider = panelEnabledProvider;
}
- private void updateScrimFraction() {
- float scrimFraction = mPanelFraction;
- if (mMinFraction < 1.0f) {
- scrimFraction = Math.max((mPanelFraction - mMinFraction) / (1.0f - mMinFraction),
- 0);
- }
- mScrimController.setPanelExpansion(scrimFraction);
- }
-
public void updateResources() {
mCutoutSideNudge = getResources().getDimensionPixelSize(
R.dimen.display_cutout_margin_consumption);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index a564637aa510..371ec7a6ea96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -34,6 +34,7 @@ import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
+import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
@@ -183,8 +184,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private float mScrimBehindAlphaKeyguard = KEYGUARD_SCRIM_ALPHA;
private final float mDefaultScrimAlpha;
- // Assuming the shade is expanded during initialization
- private float mPanelExpansion = 1f;
+ private float mRawPanelExpansionFraction;
+ private float mPanelScrimMinFraction;
+ // Calculated based on mRawPanelExpansionFraction and mPanelScrimMinFraction
+ private float mPanelExpansionFraction = 1f; // Assume shade is expanded during initialization
private float mQsExpansion;
private boolean mQsBottomVisible;
@@ -483,14 +486,39 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
*
* The expansion fraction is tied to the scrim opacity.
*
- * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
+ * See {@link PanelBar#panelExpansionChanged}.
+ *
+ * @param rawPanelExpansionFraction From 0 to 1 where 0 means collapsed and 1 expanded.
*/
- public void setPanelExpansion(float fraction) {
- if (isNaN(fraction)) {
- throw new IllegalArgumentException("Fraction should not be NaN");
+ public void setRawPanelExpansionFraction(
+ @FloatRange(from = 0.0, to = 1.0) float rawPanelExpansionFraction) {
+ if (isNaN(rawPanelExpansionFraction)) {
+ throw new IllegalArgumentException("rawPanelExpansionFraction should not be NaN");
+ }
+ mRawPanelExpansionFraction = rawPanelExpansionFraction;
+ calculateAndUpdatePanelExpansion();
+ }
+
+ /** See {@link NotificationPanelViewController#setPanelScrimMinFraction(float)}. */
+ public void setPanelScrimMinFraction(float minFraction) {
+ if (isNaN(minFraction)) {
+ throw new IllegalArgumentException("minFraction should not be NaN");
}
- if (mPanelExpansion != fraction) {
- mPanelExpansion = fraction;
+ mPanelScrimMinFraction = minFraction;
+ calculateAndUpdatePanelExpansion();
+ }
+
+ private void calculateAndUpdatePanelExpansion() {
+ float panelExpansionFraction = mRawPanelExpansionFraction;
+ if (mPanelScrimMinFraction < 1.0f) {
+ panelExpansionFraction = Math.max(
+ (mRawPanelExpansionFraction - mPanelScrimMinFraction)
+ / (1.0f - mPanelScrimMinFraction),
+ 0);
+ }
+
+ if (mPanelExpansionFraction != panelExpansionFraction) {
+ mPanelExpansionFraction = panelExpansionFraction;
boolean relevantState = (mState == ScrimState.UNLOCKED
|| mState == ScrimState.KEYGUARD
@@ -892,7 +920,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
private float getInterpolatedFraction() {
- return Interpolators.getNotificationScrimAlpha(mPanelExpansion, false /* notification */);
+ return Interpolators.getNotificationScrimAlpha(
+ mPanelExpansionFraction, false /* notification */);
}
private void setScrimAlpha(ScrimView scrim, float alpha) {
@@ -1228,8 +1257,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
pw.println(mTracking);
pw.print(" mDefaultScrimAlpha=");
pw.println(mDefaultScrimAlpha);
- pw.print(" mExpansionFraction=");
- pw.println(mPanelExpansion);
+ pw.print(" mPanelExpansionFraction=");
+ pw.println(mPanelExpansionFraction);
pw.print(" mExpansionAffectsAlpha=");
pw.println(mExpansionAffectsAlpha);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 78ab0d7f8a2f..16c11e3553a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -336,6 +336,7 @@ public class StatusBar extends SystemUI implements
}
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private boolean mCallingFadingAwayAfterReveal;
private StatusBarCommandQueueCallbacks mCommandQueueCallbacks;
void setWindowState(int state) {
@@ -628,6 +629,7 @@ public class StatusBar extends SystemUI implements
private final Executor mUiBgExecutor;
protected boolean mDozing;
+ private boolean mIsFullscreen;
private final NotificationMediaManager mMediaManager;
private final NotificationLockscreenUserManager mLockscreenUserManager;
@@ -898,6 +900,8 @@ public class StatusBar extends SystemUI implements
lockscreenShadeTransitionController.setStatusbar(this);
mExpansionChangedListeners = new ArrayList<>();
+ addExpansionChangedListener(
+ (expansion, expanded) -> mScrimController.setRawPanelExpansionFraction(expansion));
mBubbleExpandListener =
(isExpanding, key) -> mContext.getMainExecutor().execute(() -> {
@@ -909,6 +913,9 @@ public class StatusBar extends SystemUI implements
mActivityLaunchAnimator = activityLaunchAnimator;
mDialogLaunchAnimator = dialogLaunchAnimator;
+ // The status bar background may need updating when the ongoing call status changes.
+ mOngoingCallController.addCallback((animate) -> maybeUpdateBarMode());
+
// TODO(b/190746471): Find a better home for this.
DateTimeView.setReceiverHandler(timeTickHandler);
@@ -1400,6 +1407,12 @@ public class StatusBar extends SystemUI implements
mDeviceProvisionedController.addCallback(mUserSetupObserver);
mUserSetupObserver.onUserSetupChanged();
+ for (ExpansionChangedListener listener : mExpansionChangedListeners) {
+ // The initial expansion amount comes from mNotificationPanelViewController, so we
+ // should send the amount once we've fully set up that controller.
+ sendInitialExpansionAmount(listener);
+ }
+
// disable profiling bars, since they overlap and clutter the output on app windows
ThreadedRenderer.overrideProperty("disableProfileBars", "true");
@@ -2242,7 +2255,7 @@ public class StatusBar extends SystemUI implements
if (!mTransientShown) {
mTransientShown = true;
mNoAnimationOnNextBarModeChange = true;
- handleTransientChanged();
+ maybeUpdateBarMode();
}
}
@@ -2250,11 +2263,11 @@ public class StatusBar extends SystemUI implements
void clearTransient() {
if (mTransientShown) {
mTransientShown = false;
- handleTransientChanged();
+ maybeUpdateBarMode();
}
}
- private void handleTransientChanged() {
+ private void maybeUpdateBarMode() {
final int barMode = barMode(mTransientShown, mAppearance);
if (updateBarMode(barMode)) {
mLightBarController.onStatusBarModeChanged(barMode);
@@ -2272,9 +2285,11 @@ public class StatusBar extends SystemUI implements
return false;
}
- private static @TransitionMode int barMode(boolean isTransient, int appearance) {
+ private @TransitionMode int barMode(boolean isTransient, int appearance) {
final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_STATUS_BARS;
- if (isTransient) {
+ if (mOngoingCallController.hasOngoingCall() && mIsFullscreen) {
+ return MODE_SEMI_TRANSPARENT;
+ } else if (isTransient) {
return MODE_SEMI_TRANSPARENT;
} else if ((appearance & lightsOutOpaque) == lightsOutOpaque) {
return MODE_LIGHTS_OUT;
@@ -3125,8 +3140,20 @@ public class StatusBar extends SystemUI implements
public void fadeKeyguardWhilePulsing() {
mNotificationPanelViewController.fadeOut(0, FADE_KEYGUARD_DURATION_PULSING,
()-> {
- hideKeyguard();
- mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ Runnable finishFading = () -> {
+ mCallingFadingAwayAfterReveal = false;
+ hideKeyguard();
+ mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ };
+ if (mLightRevealScrim.getRevealAmount() != 1.0f) {
+ mCallingFadingAwayAfterReveal = true;
+ // We're still revealing the Light reveal, let's only go to keyguard once
+ // that has finished and nothing moves anymore.
+ // Going there introduces lots of jank
+ mLightRevealScrim.setFullyRevealedRunnable(finishFading);
+ } else {
+ finishFading.run();
+ }
}).start();
}
@@ -4227,9 +4254,11 @@ public class StatusBar extends SystemUI implements
}
private void sendInitialExpansionAmount(ExpansionChangedListener expansionChangedListener) {
- expansionChangedListener.onExpansionChanged(
- mNotificationPanelViewController.getExpandedFraction(),
- mNotificationPanelViewController.isExpanded());
+ if (mNotificationPanelViewController != null) {
+ expansionChangedListener.onExpansionChanged(
+ mNotificationPanelViewController.getExpandedFraction(),
+ mNotificationPanelViewController.isExpanded());
+ }
}
public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
@@ -4285,7 +4314,7 @@ public class StatusBar extends SystemUI implements
+ "mStatusBarKeyguardViewManager was null");
return;
}
- if (mKeyguardStateController.isKeyguardFadingAway()) {
+ if (mKeyguardStateController.isKeyguardFadingAway() && !mCallingFadingAwayAfterReveal) {
mStatusBarKeyguardViewManager.onKeyguardFadedAway();
}
}
@@ -4476,6 +4505,12 @@ public class StatusBar extends SystemUI implements
updateReportRejectedTouchVisibility();
Trace.endSection();
}
+
+ @Override
+ public void onFullscreenStateChanged(boolean isFullscreen) {
+ mIsFullscreen = isFullscreen;
+ maybeUpdateBarMode();
+ }
};
private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index b708861ecc74..235a8e85a223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -208,9 +208,18 @@ public class StatusBarWindowController {
apply(mCurrentState);
}
- /** Sets whether there is currently an ongoing call. */
- public void setIsCallOngoing(boolean isCallOngoing) {
- mCurrentState.mIsCallOngoing = isCallOngoing;
+ /**
+ * Sets whether an ongoing process requires the status bar to be forced visible.
+ *
+ * This method is separate from {@link this#setForceStatusBarVisible} because the ongoing
+ * process **takes priority**. For example, if {@link this#setForceStatusBarVisible} is set to
+ * false but this method is set to true, then the status bar **will** be visible.
+ *
+ * TODO(b/195839150): We should likely merge this method and
+ * {@link this#setForceStatusBarVisible} together and use some sort of ranking system instead.
+ */
+ public void setOngoingProcessRequiresStatusBarVisible(boolean visible) {
+ mCurrentState.mOngoingProcessRequiresStatusBarVisible = visible;
apply(mCurrentState);
}
@@ -254,13 +263,14 @@ public class StatusBarWindowController {
private static class State {
boolean mForceStatusBarVisible;
boolean mIsLaunchAnimationRunning;
- boolean mIsCallOngoing;
+ boolean mOngoingProcessRequiresStatusBarVisible;
}
private void applyForceStatusBarVisibleFlag(State state) {
if (state.mForceStatusBarVisible
|| state.mIsLaunchAnimationRunning
- || state.mIsCallOngoing) {
+ // Don't force-show the status bar if the user has already dismissed it.
+ || state.mOngoingProcessRequiresStatusBarVisible) {
mLpChanged.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
} else {
mLpChanged.privateFlags &= ~PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 143aaba648da..f3f3325f49d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -4,10 +4,10 @@ import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
-import android.content.res.Configuration
import android.database.ContentObserver
import android.os.Handler
import android.provider.Settings
+import android.view.Surface
import android.view.View
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
@@ -239,10 +239,11 @@ class UnlockedScreenOffAnimationController @Inject constructor(
return false
}
- // If we're not allowed to rotate the keyguard, then only do the screen off animation if
- // we're in portrait. Otherwise, AOD will animate in sideways, which looks weird.
+ // If we're not allowed to rotate the keyguard, it can only be displayed in zero-degree
+ // portrait. If we're in another orientation, disable the screen off animation so we don't
+ // animate in the keyguard AOD UI sideways or upside down.
if (!keyguardStateController.isKeyguardScreenRotationAllowed &&
- context.resources.configuration.orientation != Configuration.ORIENTATION_PORTRAIT) {
+ context.display.rotation != Surface.ROTATION_0) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index b7c80def7dad..7d476bfbee04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -34,6 +34,7 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
@@ -60,8 +61,11 @@ class OngoingCallController @Inject constructor(
private val logger: OngoingCallLogger,
private val dumpManager: DumpManager,
private val statusBarWindowController: Optional<StatusBarWindowController>,
+ private val swipeStatusBarAwayGestureHandler: Optional<SwipeStatusBarAwayGestureHandler>,
+ private val statusBarStateController: StatusBarStateController,
) : CallbackController<OngoingCallListener>, Dumpable {
+ private var isFullscreen: Boolean = false
/** Non-null if there's an active call notification. */
private var callNotificationInfo: CallNotificationInfo? = null
/** True if the application managing the call is visible to the user. */
@@ -96,7 +100,8 @@ class OngoingCallController @Inject constructor(
entry.sbn.notification.contentIntent?.intent,
entry.sbn.uid,
entry.sbn.notification.extras.getInt(
- Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING
+ Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING,
+ statusBarSwipedAway = callNotificationInfo?.statusBarSwipedAway ?: false
)
if (newOngoingCallInfo == callNotificationInfo) {
return
@@ -122,6 +127,7 @@ class OngoingCallController @Inject constructor(
dumpManager.registerDumpable(this)
if (featureFlags.isOngoingCallStatusBarChipEnabled) {
notifCollection.addCollectionListener(notifListener)
+ statusBarStateController.addCallback(statusBarStateListener)
}
}
@@ -175,10 +181,8 @@ class OngoingCallController @Inject constructor(
val currentChipView = chipView
val timeView = currentChipView?.getTimeView()
- val backgroundView =
- currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background)
- if (currentChipView != null && timeView != null && backgroundView != null) {
+ if (currentChipView != null && timeView != null) {
if (currentCallNotificationInfo.hasValidStartTime()) {
timeView.setShouldHideText(false)
timeView.base = currentCallNotificationInfo.callStartTime -
@@ -189,22 +193,18 @@ class OngoingCallController @Inject constructor(
timeView.setShouldHideText(true)
timeView.stop()
}
+ updateChipClickListener()
- currentCallNotificationInfo.intent?.let { intent ->
- currentChipView.setOnClickListener {
- logger.logChipClicked()
- activityStarter.postStartActivityDismissingKeyguard(
- intent,
- 0,
- ActivityLaunchAnimator.Controller.fromView(
- backgroundView,
- InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP)
- )
+ setUpUidObserver(currentCallNotificationInfo)
+ if (!currentCallNotificationInfo.statusBarSwipedAway) {
+ statusBarWindowController.ifPresent {
+ it.setOngoingProcessRequiresStatusBarVisible(true)
+ }
+ // TODO(b/195839150): Only listen for the gesture when in immersive mode.
+ swipeStatusBarAwayGestureHandler.ifPresent {
+ it.addOnGestureDetectedCallback(TAG, this::onSwipeAwayGestureDetected)
}
}
-
- setUpUidObserver(currentCallNotificationInfo)
- statusBarWindowController.ifPresent { it.setIsCallOngoing(true) }
mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
} else {
// If we failed to update the chip, don't store the call info. Then [hasOngoingCall]
@@ -218,6 +218,30 @@ class OngoingCallController @Inject constructor(
}
}
+ private fun updateChipClickListener() {
+ if (callNotificationInfo == null) { return }
+ if (isFullscreen && !featureFlags.isOngoingCallInImmersiveChipTapEnabled) {
+ chipView?.setOnClickListener(null)
+ } else {
+ val currentChipView = chipView
+ val backgroundView =
+ currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background)
+ val intent = callNotificationInfo?.intent
+ if (currentChipView != null && backgroundView != null && intent != null) {
+ currentChipView.setOnClickListener {
+ logger.logChipClicked()
+ activityStarter.postStartActivityDismissingKeyguard(
+ intent,
+ 0,
+ ActivityLaunchAnimator.Controller.fromView(
+ backgroundView,
+ InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP)
+ )
+ }
+ }
+ }
+ }
+
/**
* Sets up an [IUidObserver] to monitor the status of the application managing the ongoing call.
*/
@@ -271,7 +295,8 @@ class OngoingCallController @Inject constructor(
private fun removeChip() {
callNotificationInfo = null
tearDownChipView()
- statusBarWindowController.ifPresent { it.setIsCallOngoing(false) }
+ statusBarWindowController.ifPresent { it.setOngoingProcessRequiresStatusBarVisible(false) }
+ swipeStatusBarAwayGestureHandler.ifPresent { it.removeOnGestureDetectedCallback(TAG) }
mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
if (uidObserver != null) {
iActivityManager.unregisterUidObserver(uidObserver)
@@ -286,13 +311,41 @@ class OngoingCallController @Inject constructor(
return this.findViewById(R.id.ongoing_call_chip_time)
}
+ /**
+ * If there's an active ongoing call, then we will force the status bar to always show, even if
+ * the user is in immersive mode. However, we also want to give users the ability to swipe away
+ * the status bar if they need to access the area under the status bar.
+ *
+ * This method updates the status bar window appropriately when the swipe away gesture is
+ * detected.
+ */
+ private fun onSwipeAwayGestureDetected() {
+ if (DEBUG) { Log.d(TAG, "Swipe away gesture detected") }
+ callNotificationInfo = callNotificationInfo?.copy(statusBarSwipedAway = true)
+ statusBarWindowController.ifPresent {
+ it.setOngoingProcessRequiresStatusBarVisible(false)
+ }
+ swipeStatusBarAwayGestureHandler.ifPresent {
+ it.removeOnGestureDetectedCallback(TAG)
+ }
+ }
+
+ private val statusBarStateListener = object : StatusBarStateController.StateListener {
+ override fun onFullscreenStateChanged(isFullscreen: Boolean) {
+ this@OngoingCallController.isFullscreen = isFullscreen
+ updateChipClickListener()
+ }
+ }
+
private data class CallNotificationInfo(
val key: String,
val callStartTime: Long,
val intent: Intent?,
val uid: Int,
/** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */
- val isOngoing: Boolean
+ val isOngoing: Boolean,
+ /** True if the user has swiped away the status bar while in this phone call. */
+ val statusBarSwipedAway: Boolean
) {
/**
* Returns true if the notification information has a valid call start time.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt
new file mode 100644
index 000000000000..c97cf14b743d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 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.systemui.statusbar.phone.ongoingcall
+
+import android.content.Context
+import android.os.Looper
+import android.util.Log
+import android.view.Choreographer
+import android.view.Display
+import android.view.InputEvent
+import android.view.MotionEvent
+import android.view.MotionEvent.*
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shared.system.InputChannelCompat
+import com.android.systemui.shared.system.InputMonitorCompat
+import com.android.systemui.statusbar.phone.StatusBarWindowController
+import javax.inject.Inject
+
+/**
+ * A class to detect when a user swipes away the status bar. To be notified when the swipe away
+ * gesture is detected, add a callback via [addOnGestureDetectedCallback].
+ */
+@SysUISingleton
+open class SwipeStatusBarAwayGestureHandler @Inject constructor(
+ context: Context,
+ private val statusBarWindowController: StatusBarWindowController,
+) {
+
+ /**
+ * Active callbacks, each associated with a tag. Gestures will only be monitored if
+ * [callbacks.size] > 0.
+ */
+ private val callbacks: MutableMap<String, () -> Unit> = mutableMapOf()
+
+ private var startY: Float = 0f
+ private var startTime: Long = 0L
+ private var monitoringCurrentTouch: Boolean = false
+
+ private var inputMonitor: InputMonitorCompat? = null
+ private var inputReceiver: InputChannelCompat.InputEventReceiver? = null
+
+ // TODO(b/195839150): Update this threshold when the config changes?
+ private var swipeDistanceThreshold: Int = context.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.system_gestures_start_threshold
+ )
+
+ /** Adds a callback that will be triggered when the swipe away gesture is detected. */
+ fun addOnGestureDetectedCallback(tag: String, callback: () -> Unit) {
+ val callbacksWasEmpty = callbacks.isEmpty()
+ callbacks[tag] = callback
+ if (callbacksWasEmpty) {
+ startGestureListening()
+ }
+ }
+
+ /** Removes the callback. */
+ fun removeOnGestureDetectedCallback(tag: String) {
+ callbacks.remove(tag)
+ if (callbacks.isEmpty()) {
+ stopGestureListening()
+ }
+ }
+
+ private fun onInputEvent(ev: InputEvent) {
+ if (ev !is MotionEvent) {
+ return
+ }
+
+ when (ev.actionMasked) {
+ ACTION_DOWN -> {
+ if (
+ // Gesture starts just below the status bar
+ // TODO(b/195839150): Is [statusBarHeight] the correct dimension to use for
+ // determining which down touches are valid?
+ ev.y >= statusBarWindowController.statusBarHeight
+ && ev.y <= 3 * statusBarWindowController.statusBarHeight
+ ) {
+ Log.d(TAG, "Beginning gesture detection, y=${ev.y}")
+ startY = ev.y
+ startTime = ev.eventTime
+ monitoringCurrentTouch = true
+ } else {
+ monitoringCurrentTouch = false
+ }
+ }
+ ACTION_MOVE -> {
+ if (!monitoringCurrentTouch) {
+ return
+ }
+ if (
+ // Gesture is up
+ ev.y < startY
+ // Gesture went far enough
+ && (startY - ev.y) >= swipeDistanceThreshold
+ // Gesture completed quickly enough
+ && (ev.eventTime - startTime) < SWIPE_TIMEOUT_MS
+ ) {
+ Log.i(TAG, "Gesture detected; notifying callbacks")
+ callbacks.values.forEach { it.invoke() }
+ monitoringCurrentTouch = false
+ }
+ }
+ ACTION_CANCEL, ACTION_UP -> {
+ monitoringCurrentTouch = false
+ }
+ }
+ }
+
+ /** Start listening for the swipe gesture. */
+ private fun startGestureListening() {
+ stopGestureListening()
+
+ if (DEBUG) { Log.d(TAG, "Input listening started") }
+ inputMonitor = InputMonitorCompat(TAG, Display.DEFAULT_DISPLAY).also {
+ inputReceiver = it.getInputReceiver(
+ Looper.getMainLooper(),
+ Choreographer.getInstance(),
+ this::onInputEvent
+ )
+ }
+ }
+
+ /** Stop listening for the swipe gesture. */
+ private fun stopGestureListening() {
+ inputMonitor?.let {
+ if (DEBUG) { Log.d(TAG, "Input listening stopped") }
+ inputMonitor = null
+ it.dispose()
+ }
+ inputReceiver?.let {
+ inputReceiver = null
+ it.dispose()
+ }
+ }
+}
+
+private const val SWIPE_TIMEOUT_MS: Long = 500
+private val TAG = SwipeStatusBarAwayGestureHandler::class.simpleName
+private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 0ba072e9e72f..f97f4d0edc24 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -31,7 +31,6 @@ import java.util.Arrays;
public class NotificationChannels extends SystemUI {
public static String ALERTS = "ALR";
- public static String SCREENSHOTS_LEGACY = "SCN";
public static String SCREENSHOTS_HEADSUP = "SCN_HEADSUP";
public static String GENERAL = "GEN";
public static String STORAGE = "DSK";
@@ -84,18 +83,11 @@ public class NotificationChannels extends SystemUI {
general,
storage,
createScreenshotChannel(
- context.getString(R.string.notification_channel_screenshot),
- nm.getNotificationChannel(SCREENSHOTS_LEGACY)),
+ context.getString(R.string.notification_channel_screenshot)),
batteryChannel,
hint
));
- // Delete older SS channel if present.
- // Screenshots promoted to heads-up in P, this cleans up the lower priority channel from O.
- // This line can be deleted in Q.
- nm.deleteNotificationChannel(SCREENSHOTS_LEGACY);
-
-
if (isTv(context)) {
// TV specific notification channel for TV PIP controls.
// Importance should be {@link NotificationManager#IMPORTANCE_MAX} to have the highest
@@ -113,7 +105,7 @@ public class NotificationChannels extends SystemUI {
* @return
*/
@VisibleForTesting static NotificationChannel createScreenshotChannel(
- String name, NotificationChannel legacySS) {
+ String name) {
NotificationChannel screenshotChannel = new NotificationChannel(SCREENSHOTS_HEADSUP,
name, NotificationManager.IMPORTANCE_HIGH); // pop on screen
@@ -121,24 +113,6 @@ public class NotificationChannels extends SystemUI {
new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build());
screenshotChannel.setBlockable(true);
- if (legacySS != null) {
- // Respect any user modified fields from the old channel.
- int userlock = legacySS.getUserLockedFields();
- if ((userlock & NotificationChannel.USER_LOCKED_IMPORTANCE) != 0) {
- screenshotChannel.setImportance(legacySS.getImportance());
- }
- if ((userlock & NotificationChannel.USER_LOCKED_SOUND) != 0) {
- screenshotChannel.setSound(legacySS.getSound(), legacySS.getAudioAttributes());
- }
- if ((userlock & NotificationChannel.USER_LOCKED_VIBRATION) != 0) {
- screenshotChannel.setVibrationPattern(legacySS.getVibrationPattern());
- }
- if ((userlock & NotificationChannel.USER_LOCKED_LIGHTS) != 0) {
- screenshotChannel.setLightColor(legacySS.getLightColor());
- }
- // skip show_badge, irrelevant for system channel
- }
-
return screenshotChannel;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
index 28cba8e16970..40982bb18023 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
@@ -18,8 +18,7 @@ package com.android.systemui.util.sensors;
import android.util.Log;
-import androidx.annotation.NonNull;
-
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
@@ -42,9 +41,9 @@ class PostureDependentProximitySensor extends ProximitySensorImpl {
PostureDependentProximitySensor(
@PrimaryProxSensor ThresholdSensor[] postureToPrimaryProxSensorMap,
@SecondaryProxSensor ThresholdSensor[] postureToSecondaryProxSensorMap,
- @NonNull DelayableExecutor delayableExecutor,
- @NonNull Execution execution,
- @NonNull DevicePostureController devicePostureController
+ @Main DelayableExecutor delayableExecutor,
+ Execution execution,
+ DevicePostureController devicePostureController
) {
super(
postureToPrimaryProxSensorMap[0],
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index c464cad3e0b2..ddf1d7033b82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -18,14 +18,18 @@ package com.android.systemui.keyguard;
import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Vibrator;
@@ -39,15 +43,18 @@ import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.LockIconView;
import com.android.keyguard.LockIconViewController;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -69,7 +76,10 @@ import java.util.List;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class LockIconViewControllerTest extends SysuiTestCase {
+ private static final String UNLOCKED_LABEL = "unlocked";
+
private @Mock LockIconView mLockIconView;
+ private @Mock AnimatedVectorDrawable mIconDrawable;
private @Mock Context mContext;
private @Mock Resources mResources;
private @Mock DisplayMetrics mDisplayMetrics;
@@ -97,6 +107,11 @@ public class LockIconViewControllerTest extends SysuiTestCase {
@Captor private ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor;
private AuthController.Callback mAuthControllerCallback;
+ @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback>
+ mKeyguardUpdateMonitorCallbackCaptor =
+ ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+ private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
+
@Captor private ArgumentCaptor<PointF> mPointCaptor;
@Before
@@ -108,6 +123,13 @@ public class LockIconViewControllerTest extends SysuiTestCase {
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
when(mLockIconView.findViewById(anyInt())).thenReturn(mAodFp);
+ when(mResources.getString(R.string.accessibility_unlock_button)).thenReturn(UNLOCKED_LABEL);
+ when(mResources.getDrawable(anyInt(), anyObject())).thenReturn(mIconDrawable);
+
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
mLockIconViewController = new LockIconViewController(
mLockIconView,
@@ -192,6 +214,29 @@ public class LockIconViewControllerTest extends SysuiTestCase {
verify(mLockIconView).setUseBackground(false);
}
+ @Test
+ public void testUnlockIconShows_biometricUnlockedTrue() {
+ // GIVEN UDFPS sensor location is available
+ setupUdfps();
+
+ // GIVEN lock icon controller is initialized and view is attached
+ mLockIconViewController.init();
+ captureAttachListener();
+ mAttachListener.onViewAttachedToWindow(mLockIconView);
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ reset(mLockIconView);
+
+ // WHEN face auth's biometric running state changes
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+
+ // THEN the unlock icon is shown
+ verify(mLockIconView).setContentDescription(UNLOCKED_LABEL);
+ }
+
private Pair<Integer, PointF> setupUdfps() {
final PointF udfpsLocation = new PointF(50, 75);
final int radius = 33;
@@ -220,4 +265,10 @@ public class LockIconViewControllerTest extends SysuiTestCase {
verify(mLockIconView).addOnAttachStateChangeListener(mAttachCaptor.capture());
mAttachListener = mAttachCaptor.getValue();
}
+
+ private void captureKeyguardUpdateMonitorCallback() {
+ verify(mKeyguardUpdateMonitor).registerCallback(
+ mKeyguardUpdateMonitorCallbackCaptor.capture());
+ mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 42629f545559..bf5a6e4086f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.FakeExecutor
@@ -95,6 +96,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var collapsedSet: ConstraintSet
@Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
@Mock private lateinit var mediaCarouselController: MediaCarouselController
+ @Mock private lateinit var falsingManager: FalsingManager
private lateinit var appIcon: ImageView
private lateinit var albumView: ImageView
private lateinit var titleText: TextView
@@ -131,8 +133,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
- seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil,
- mediaOutputDialogFactory, mediaCarouselController)
+ seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil,
+ mediaOutputDialogFactory, mediaCarouselController, falsingManager)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Mock out a view holder for the player to attach to.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index 7d8728e4acab..e77802f8db32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -76,6 +76,7 @@ public class SeekBarObserverTest : SysuiTestCase() {
assertThat(seekBarView.getThumb().getAlpha()).isEqualTo(0)
assertThat(elapsedTimeView.getText()).isEqualTo("")
assertThat(totalTimeView.getText()).isEqualTo("")
+ assertThat(seekBarView.contentDescription).isEqualTo("")
assertThat(seekBarView.maxHeight).isEqualTo(disabledHeight)
}
@@ -102,6 +103,9 @@ public class SeekBarObserverTest : SysuiTestCase() {
assertThat(seekBarView.max).isEqualTo(120000)
assertThat(elapsedTimeView.getText()).isEqualTo("00:03")
assertThat(totalTimeView.getText()).isEqualTo("02:00")
+
+ val desc = context.getString(R.string.controls_media_seekbar_description, "00:03", "02:00")
+ assertThat(seekBarView.contentDescription).isEqualTo(desc)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 25ca8c95500b..750600ad1387 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -119,7 +119,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
@@ -181,7 +180,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(mMediaDevices);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
}
@@ -190,7 +188,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(new ArrayList<>());
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
}
@@ -198,7 +195,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
public void onBindViewHolder_bindNonActiveConnectedDevice_verifyView() {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
@@ -215,7 +211,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaDevice2.isConnected()).thenReturn(false);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
@@ -231,7 +226,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
index 1f85112dfb74..ca5d570969c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
@@ -99,7 +99,6 @@ public class MediaOutputGroupAdapterTest extends SysuiTestCase {
assertThat(mGroupViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
@@ -114,7 +113,6 @@ public class MediaOutputGroupAdapterTest extends SysuiTestCase {
assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
@@ -141,7 +139,6 @@ public class MediaOutputGroupAdapterTest extends SysuiTestCase {
assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
@@ -167,7 +164,6 @@ public class MediaOutputGroupAdapterTest extends SysuiTestCase {
assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
@@ -186,7 +182,6 @@ public class MediaOutputGroupAdapterTest extends SysuiTestCase {
assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index c50296be94f3..793851160dc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -209,7 +209,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat())
verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
- verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyBoolean())
+ verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
}
@Test
@@ -220,7 +220,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(scrimController).setTransitionToFullShadeProgress(anyFloat())
verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
- verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyBoolean())
+ verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(depthController).transitionToFullShadeProgress = anyFloat()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 5ebe900b52d4..705112afa93f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -623,7 +623,7 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void transitionToUnlocked() {
- mScrimController.setPanelExpansion(0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
mScrimController.transitionTo(ScrimState.UNLOCKED);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
@@ -638,7 +638,7 @@ public class ScrimControllerTest extends SysuiTestCase {
));
// Back scrim should be visible after start dragging
- mScrimController.setPanelExpansion(0.3f);
+ mScrimController.setRawPanelExpansionFraction(0.3f);
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, SEMI_TRANSPARENT,
@@ -663,20 +663,20 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void panelExpansion() {
- mScrimController.setPanelExpansion(0f);
- mScrimController.setPanelExpansion(0.5f);
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setRawPanelExpansionFraction(0.5f);
mScrimController.transitionTo(ScrimState.UNLOCKED);
finishAnimationsImmediately();
reset(mScrimBehind);
- mScrimController.setPanelExpansion(0f);
- mScrimController.setPanelExpansion(1.0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
finishAnimationsImmediately();
assertEquals("Scrim alpha should change after setPanelExpansion",
mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f);
- mScrimController.setPanelExpansion(0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
finishAnimationsImmediately();
assertEquals("Scrim alpha should change after setPanelExpansion",
@@ -723,21 +723,21 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void panelExpansionAffectsAlpha() {
- mScrimController.setPanelExpansion(0f);
- mScrimController.setPanelExpansion(0.5f);
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setRawPanelExpansionFraction(0.5f);
mScrimController.transitionTo(ScrimState.UNLOCKED);
finishAnimationsImmediately();
final float scrimAlpha = mScrimBehind.getViewAlpha();
reset(mScrimBehind);
mScrimController.setExpansionAffectsAlpha(false);
- mScrimController.setPanelExpansion(0.8f);
+ mScrimController.setRawPanelExpansionFraction(0.8f);
verifyZeroInteractions(mScrimBehind);
assertEquals("Scrim opacity shouldn't change when setExpansionAffectsAlpha "
+ "is false", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);
mScrimController.setExpansionAffectsAlpha(true);
- mScrimController.setPanelExpansion(0.1f);
+ mScrimController.setRawPanelExpansionFraction(0.1f);
finishAnimationsImmediately();
Assert.assertNotEquals("Scrim opacity should change when setExpansionAffectsAlpha "
+ "is true", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);
@@ -747,7 +747,7 @@ public class ScrimControllerTest extends SysuiTestCase {
public void transitionToUnlockedFromOff() {
// Simulate unlock with fingerprint without AOD
mScrimController.transitionTo(ScrimState.OFF);
- mScrimController.setPanelExpansion(0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
finishAnimationsImmediately();
mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -769,7 +769,7 @@ public class ScrimControllerTest extends SysuiTestCase {
public void transitionToUnlockedFromAod() {
// Simulate unlock with fingerprint
mScrimController.transitionTo(ScrimState.AOD);
- mScrimController.setPanelExpansion(0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
finishAnimationsImmediately();
mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -948,7 +948,7 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testConservesExpansionOpacityAfterTransition() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.setPanelExpansion(0.5f);
+ mScrimController.setRawPanelExpansionFraction(0.5f);
finishAnimationsImmediately();
final float expandedAlpha = mScrimBehind.getViewAlpha();
@@ -1075,7 +1075,7 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testScrimsOpaque_whenShadeFullyExpanded() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.setPanelExpansion(1);
+ mScrimController.setRawPanelExpansionFraction(1);
// notifications scrim alpha change require calling setQsPosition
mScrimController.setQsPosition(0, 300);
finishAnimationsImmediately();
@@ -1089,7 +1089,7 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testScrimsVisible_whenShadeVisible() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.setPanelExpansion(0.3f);
+ mScrimController.setRawPanelExpansionFraction(0.3f);
// notifications scrim alpha change require calling setQsPosition
mScrimController.setQsPosition(0, 300);
finishAnimationsImmediately();
@@ -1124,7 +1124,7 @@ public class ScrimControllerTest extends SysuiTestCase {
public void testScrimsVisible_whenShadeVisible_clippingQs() {
mScrimController.setClipsQsScrim(true);
mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.setPanelExpansion(0.3f);
+ mScrimController.setRawPanelExpansionFraction(0.3f);
// notifications scrim alpha change require calling setQsPosition
mScrimController.setQsPosition(0.5f, 300);
finishAnimationsImmediately();
@@ -1150,7 +1150,7 @@ public class ScrimControllerTest extends SysuiTestCase {
public void testNotificationScrimTransparent_whenOnLockscreen() {
mScrimController.transitionTo(ScrimState.KEYGUARD);
// even if shade is not pulled down, panel has expansion of 1 on the lockscreen
- mScrimController.setPanelExpansion(1);
+ mScrimController.setRawPanelExpansionFraction(1);
mScrimController.setQsPosition(0f, /*qs panel bottom*/ 0);
assertScrimAlpha(Map.of(
@@ -1160,7 +1160,7 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testNotificationScrimVisible_afterOpeningShadeFromLockscreen() {
- mScrimController.setPanelExpansion(1);
+ mScrimController.setRawPanelExpansionFraction(1);
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
finishAnimationsImmediately();
@@ -1203,11 +1203,11 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testNotificationTransparency_followsTransitionToFullShade() {
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
- mScrimController.setPanelExpansion(1.0f);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
finishAnimationsImmediately();
float shadeLockedAlpha = mNotificationsScrim.getViewAlpha();
mScrimController.transitionTo(ScrimState.KEYGUARD);
- mScrimController.setPanelExpansion(1.0f);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
finishAnimationsImmediately();
float keyguardAlpha = mNotificationsScrim.getViewAlpha();
@@ -1227,7 +1227,7 @@ public class ScrimControllerTest extends SysuiTestCase {
}
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
- mScrimController.setPanelExpansion(expansion);
+ mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
// alpha is not changing linearly thus 0.2 of leeway when asserting
assertEquals(expectedAlpha, mNotificationsScrim.getViewAlpha(), 0.2);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index e97aba2816e1..ca6e1ee41c31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -36,6 +36,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -50,8 +51,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.nullable
+import org.mockito.ArgumentMatchers.*
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.eq
@@ -83,10 +83,13 @@ class OngoingCallControllerTest : SysuiTestCase() {
private lateinit var controller: OngoingCallController
private lateinit var notifCollectionListener: NotifCollectionListener
+ @Mock private lateinit var mockFeatureFlags: FeatureFlags
+ @Mock private lateinit var mockSwipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler
@Mock private lateinit var mockOngoingCallListener: OngoingCallListener
@Mock private lateinit var mockActivityStarter: ActivityStarter
@Mock private lateinit var mockIActivityManager: IActivityManager
@Mock private lateinit var mockStatusBarWindowController: StatusBarWindowController
+ @Mock private lateinit var mockStatusBarStateController: StatusBarStateController
private lateinit var chipView: View
@@ -98,13 +101,12 @@ class OngoingCallControllerTest : SysuiTestCase() {
}
MockitoAnnotations.initMocks(this)
- val featureFlags = mock(FeatureFlags::class.java)
- `when`(featureFlags.isOngoingCallStatusBarChipEnabled).thenReturn(true)
+ `when`(mockFeatureFlags.isOngoingCallStatusBarChipEnabled).thenReturn(true)
val notificationCollection = mock(CommonNotifCollection::class.java)
controller = OngoingCallController(
notificationCollection,
- featureFlags,
+ mockFeatureFlags,
clock,
mockActivityStarter,
mainExecutor,
@@ -112,7 +114,9 @@ class OngoingCallControllerTest : SysuiTestCase() {
OngoingCallLogger(uiEventLoggerFake),
DumpManager(),
Optional.of(mockStatusBarWindowController),
- )
+ Optional.of(mockSwipeStatusBarAwayGestureHandler),
+ mockStatusBarStateController,
+ )
controller.init()
controller.addCallback(mockOngoingCallListener)
controller.setChipView(chipView)
@@ -141,7 +145,15 @@ class OngoingCallControllerTest : SysuiTestCase() {
fun onEntryUpdated_isOngoingCallNotif_windowControllerUpdated() {
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
- verify(mockStatusBarWindowController).setIsCallOngoing(true)
+ verify(mockStatusBarWindowController).setOngoingProcessRequiresStatusBarVisible(true)
+ }
+
+ @Test
+ fun onEntryUpdated_isOngoingCallNotif_swipeGestureCallbackAdded() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ verify(mockSwipeStatusBarAwayGestureHandler)
+ .addOnGestureDetectedCallback(anyString(), any())
}
@Test
@@ -242,7 +254,18 @@ class OngoingCallControllerTest : SysuiTestCase() {
notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED)
- verify(mockStatusBarWindowController).setIsCallOngoing(false)
+ verify(mockStatusBarWindowController).setOngoingProcessRequiresStatusBarVisible(false)
+ }
+
+ @Test
+ fun onEntryUpdated_callNotifAddedThenRemoved_swipeGestureCallbackRemoved() {
+ val ongoingCallNotifEntry = createOngoingCallNotifEntry()
+ notifCollectionListener.onEntryAdded(ongoingCallNotifEntry)
+
+ notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED)
+
+ verify(mockSwipeStatusBarAwayGestureHandler)
+ .removeOnGestureDetectedCallback(anyString())
}
/** Regression test for b/188491504. */
@@ -435,6 +458,56 @@ class OngoingCallControllerTest : SysuiTestCase() {
// Other tests for notifyChipVisibilityChanged are in [OngoingCallLogger], since
// [OngoingCallController.notifyChipVisibilityChanged] just delegates to that class.
+ @Test
+ fun callNotificationAdded_chipIsClickable() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ assertThat(chipView.hasOnClickListeners()).isTrue()
+ }
+
+ @Test
+ fun fullscreenIsTrue_thenCallNotificationAdded_chipNotClickable() {
+ `when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(false)
+
+ getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ assertThat(chipView.hasOnClickListeners()).isFalse()
+ }
+
+ @Test
+ fun callNotificationAdded_thenFullscreenIsTrue_chipNotClickable() {
+ `when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(false)
+
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+ getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
+
+ assertThat(chipView.hasOnClickListeners()).isFalse()
+ }
+
+ @Test
+ fun fullscreenChangesToFalse_chipClickable() {
+ `when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(false)
+
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+ // First, update to true
+ getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
+ // Then, update to false
+ getStateListener().onFullscreenStateChanged(/* isFullscreen= */ false)
+
+ assertThat(chipView.hasOnClickListeners()).isTrue()
+ }
+
+ @Test
+ fun fullscreenIsTrue_butChipClickInImmersiveEnabled_chipClickable() {
+ `when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(true)
+
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+ getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
+
+ assertThat(chipView.hasOnClickListeners()).isTrue()
+ }
+
private fun createOngoingCallNotifEntry() = createCallNotifEntry(ongoingCallStyle)
private fun createScreeningCallNotifEntry() = createCallNotifEntry(screeningCallStyle)
@@ -459,6 +532,13 @@ class OngoingCallControllerTest : SysuiTestCase() {
}
private fun createNotCallNotifEntry() = NotificationEntryBuilder().build()
+
+ private fun getStateListener(): StatusBarStateController.StateListener {
+ val statusBarStateListenerCaptor = ArgumentCaptor.forClass(
+ StatusBarStateController.StateListener::class.java)
+ verify(mockStatusBarStateController).addCallback(statusBarStateListenerCaptor.capture())
+ return statusBarStateListenerCaptor.value!!
+ }
}
private val person = Person.Builder().setName("name").build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
index eebcbe63d004..3d554880ed58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
@@ -31,7 +31,6 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import java.lang.Exception
/**
* UsbPermissionActivityTest
@@ -54,7 +53,9 @@ class UsbPermissionActivityTest : SysuiTestCase() {
putExtra(Intent.EXTRA_INTENT, PendingIntent.getBroadcast(
mContext,
334,
- Intent("NO_ACTION"),
+ Intent("NO_ACTION").apply {
+ setPackage("com.android.systemui.tests")
+ },
PendingIntent.FLAG_MUTABLE))
putExtra(UsbManager.EXTRA_ACCESSORY, UsbAccessory(
"manufacturer",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
index f1c9980f12c4..c7bcdefdc4c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
@@ -22,7 +22,6 @@ import static org.mockito.Mockito.verify;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
-import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
@@ -68,51 +67,4 @@ public class ChannelsTest extends SysuiTestCase {
list.forEach((chan) -> assertTrue(ALL_CHANNELS.contains(chan.getId())));
}
- @Test
- public void testChannelSetup_noLegacyScreenshot() {
- // Assert old channel cleaned up.
- // TODO: remove that code + this test after P.
- NotificationChannels.createAll(mContext);
- ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
- verify(mMockNotificationManager).deleteNotificationChannel(
- NotificationChannels.SCREENSHOTS_LEGACY);
- }
-
- @Test
- public void testInheritFromLegacy_keepsUserLockedLegacySettings() {
- NotificationChannel legacyChannel = new NotificationChannel("id", "oldName",
- NotificationManager.IMPORTANCE_MIN);
- legacyChannel.setImportance(NotificationManager.IMPORTANCE_NONE);;
- legacyChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
- legacyChannel.getAudioAttributes());
- legacyChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE |
- NotificationChannel.USER_LOCKED_SOUND);
- NotificationChannel newChannel =
- NotificationChannels.createScreenshotChannel("newName", legacyChannel);
- // NONE importance user locked, so don't use HIGH for new channel.
- assertEquals(NotificationManager.IMPORTANCE_NONE, newChannel.getImportance());
- assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, newChannel.getSound());
- }
-
- @Test
- public void testInheritFromLegacy_dropsUnlockedLegacySettings() {
- NotificationChannel legacyChannel = new NotificationChannel("id", "oldName",
- NotificationManager.IMPORTANCE_MIN);
- NotificationChannel newChannel =
- NotificationChannels.createScreenshotChannel("newName", legacyChannel);
- assertEquals(null, newChannel.getSound());
- assertEquals("newName", newChannel.getName());
- // MIN importance not user locked, so HIGH wins out.
- assertEquals(NotificationManager.IMPORTANCE_HIGH, newChannel.getImportance());
- }
-
- @Test
- public void testInheritFromLegacy_noLegacyExists() {
- NotificationChannel newChannel =
- NotificationChannels.createScreenshotChannel("newName", null);
- assertEquals(null, newChannel.getSound());
- assertEquals("newName", newChannel.getName());
- assertEquals(NotificationManager.IMPORTANCE_HIGH, newChannel.getImportance());
- }
-
}
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index b2fa86b69cfc..16c858829913 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -213,6 +213,10 @@ public class SpatializerHelper {
postInitSensors(true);
}
}
+
+ public void onOutputChanged(int output) {
+ logd("SpatializerCallback.onOutputChanged output:" + output);
+ }
};
// spatializer head tracking callback from native
@@ -825,9 +829,18 @@ public class SpatializerHelper {
}
synchronized void onInitSensors(boolean init) {
- final int[] modes = getSupportedHeadTrackingModes();
- if (modes.length == 0) {
- Log.i(TAG, "not initializing sensors, no headtracking supported");
+ final String action = init ? "initializing" : "releasing";
+ if (mSpat == null) {
+ Log.e(TAG, "not " + action + " sensors, null spatializer");
+ return;
+ }
+ try {
+ if (!mSpat.isHeadTrackingSupported()) {
+ Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
return;
}
initSensors(init);
diff --git a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
index cc51cea05160..22a675ad39ab 100644
--- a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
@@ -105,15 +105,20 @@ public final class StationaryThrottlingLocationProvider extends DelegateLocation
synchronized (mLock) {
mDeviceIdleHelper.addListener(this);
- onDeviceIdleChanged(mDeviceIdleHelper.isDeviceIdle());
+ mDeviceIdle = mDeviceIdleHelper.isDeviceIdle();
+ mDeviceStationaryHelper.addListener(this);
+ mDeviceStationary = false;
+ mDeviceStationaryRealtimeMs = Long.MIN_VALUE;
+
+ onThrottlingChangedLocked(false);
}
}
@Override
protected void onStop() {
synchronized (mLock) {
+ mDeviceStationaryHelper.removeListener(this);
mDeviceIdleHelper.removeListener(this);
- onDeviceIdleChanged(false);
mIncomingRequest = ProviderRequest.EMPTY_REQUEST;
mOutgoingRequest = ProviderRequest.EMPTY_REQUEST;
@@ -146,27 +151,13 @@ public final class StationaryThrottlingLocationProvider extends DelegateLocation
}
mDeviceIdle = deviceIdle;
-
- if (deviceIdle) {
- // device stationary helper will deliver an immediate listener update
- mDeviceStationaryHelper.addListener(this);
- } else {
- mDeviceStationaryHelper.removeListener(this);
- mDeviceStationary = false;
- mDeviceStationaryRealtimeMs = Long.MIN_VALUE;
- onThrottlingChangedLocked(false);
- }
+ onThrottlingChangedLocked(false);
}
}
@Override
public void onDeviceStationaryChanged(boolean deviceStationary) {
synchronized (mLock) {
- if (!mDeviceIdle) {
- // stationary detection is only registered while idle - ignore late notifications
- return;
- }
-
if (mDeviceStationary == deviceStationary) {
return;
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index e59c82cfb6d0..cf9783fb9241 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -50,6 +50,7 @@ import android.accessibilityservice.AccessibilityTrace;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
@@ -134,6 +135,8 @@ final class AccessibilityController {
private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
new SparseArray<>();
+ private SparseArray<IBinder> mFocusedWindow = new SparseArray<>();
+ private int mFocusedDisplay = -1;
// Set to true if initializing window population complete.
private boolean mAllObserversInitialized = true;
@@ -603,6 +606,29 @@ final class AccessibilityController {
return display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null;
}
+ void onFocusChanged(InputTarget lastTarget, InputTarget newTarget) {
+ if (lastTarget != null) {
+ mFocusedWindow.remove(lastTarget.getDisplayId());
+ }
+ if (newTarget != null) {
+ int displayId = newTarget.getDisplayId();
+ IBinder clientBinder = newTarget.getIWindow().asBinder();
+ mFocusedWindow.put(displayId, clientBinder);
+ }
+ }
+
+ public void onDisplayRemoved(int displayId) {
+ mFocusedWindow.remove(displayId);
+ }
+
+ public void setFocusedDisplay(int focusedDisplayId) {
+ mFocusedDisplay = focusedDisplayId;
+ }
+
+ @Nullable IBinder getFocusedWindowToken() {
+ return mFocusedWindow.get(mFocusedDisplay);
+ }
+
/**
* This class encapsulates the functionality related to display magnification.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 68bc925c1a67..394ff755d252 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4890,8 +4890,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* @param visible {@code true} if this {@link ActivityRecord} should become visible, otherwise
* this should become invisible.
* @param performLayout if {@code true}, perform surface placement after committing visibility.
+ * @param fromTransition {@code true} if this is part of finishing a transition.
*/
- void commitVisibility(boolean visible, boolean performLayout) {
+ void commitVisibility(boolean visible, boolean performLayout, boolean fromTransition) {
// Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually
// been set by the app now.
mVisibleSetFromTransferredStartingWindow = false;
@@ -4941,7 +4942,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
mUseTransferredAnimation = false;
- postApplyAnimation(visible);
+ postApplyAnimation(visible, fromTransition);
+ }
+
+ void commitVisibility(boolean visible, boolean performLayout) {
+ commitVisibility(visible, performLayout, false /* fromTransition */);
}
/**
@@ -4952,8 +4957,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*
* @param visible {@code true} if this {@link ActivityRecord} has become visible, otherwise
* this has become invisible.
+ * @param fromTransition {@code true} if this call is part of finishing a transition. This is
+ * needed because the shell transition is no-longer active by the time
+ * commitVisibility is called.
*/
- private void postApplyAnimation(boolean visible) {
+ private void postApplyAnimation(boolean visible, boolean fromTransition) {
final boolean usingShellTransitions = mTransitionController.isShellTransitionsEnabled();
final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN,
ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION
@@ -4994,7 +5002,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final DisplayContent displayContent = getDisplayContent();
if (!displayContent.mClosingApps.contains(this)
- && !displayContent.mOpeningApps.contains(this)) {
+ && !displayContent.mOpeningApps.contains(this)
+ && !fromTransition) {
// Take the screenshot before possibly hiding the WSA, otherwise the screenshot
// will not be taken.
mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index b71ad2ea7102..6ad2f7cad3c2 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -501,6 +501,8 @@ public class ActivityStartController {
int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
@NonNull Intent activityIntent, @Nullable Bundle activityOptions,
@Nullable IBinder resultTo) {
+ final ActivityRecord caller =
+ resultTo != null ? ActivityRecord.forTokenLocked(resultTo) : null;
return obtainStarter(activityIntent, "startActivityInTaskFragment")
.setActivityOptions(activityOptions)
.setInTaskFragment(taskFragment)
@@ -508,6 +510,7 @@ public class ActivityStartController {
.setRequestCode(-1)
.setCallingUid(Binder.getCallingUid())
.setCallingPid(Binder.getCallingPid())
+ .setUserId(caller != null ? caller.mUserId : mService.getCurrentUserId())
.execute();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 170789569b3f..47467abf459b 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1979,7 +1979,7 @@ class ActivityStarter {
// Allowing the embedding if the task is owned by system.
final int hostUid = hostTask.effectiveUid;
- if (hostUid == Process.SYSTEM_UID) {
+ if (UserHandle.getAppId(hostUid) == Process.SYSTEM_UID) {
return true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a4f188c7ad74..60a514e4d612 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -991,6 +991,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
mWindowManager = wm;
mRootWindowContainer = wm.mRoot;
+ mWindowOrganizerController.setWindowManager(wm);
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
mConfigurationSeq = mTempConfig.seq = 1;
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index 892db9c33dbd..c881864dff25 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -31,7 +31,6 @@ import android.util.SparseArray;
import android.view.InputApplicationHandle;
import com.android.server.am.ActivityManagerService;
-import com.android.server.wm.EmbeddedWindowController.EmbeddedWindow;
import java.io.File;
import java.util.ArrayList;
@@ -81,21 +80,19 @@ class AnrController {
final boolean aboveSystem;
final ActivityRecord activity;
synchronized (mService.mGlobalLock) {
- WindowState windowState = mService.mInputToWindowMap.get(inputToken);
- if (windowState != null) {
- pid = windowState.mSession.mPid;
- activity = windowState.mActivityRecord;
- Slog.i(TAG_WM, "ANR in " + windowState.mAttrs.getTitle() + ". Reason:" + reason);
- } else {
- EmbeddedWindow embeddedWindow = mService.mEmbeddedWindowController.get(inputToken);
- if (embeddedWindow == null) {
- Slog.e(TAG_WM, "Unknown token, dropping notifyConnectionUnresponsive request");
- return;
- }
- pid = embeddedWindow.mOwnerPid;
- windowState = embeddedWindow.mHostWindowState;
- activity = null; // Don't blame the host process, instead blame the embedded pid.
+ InputTarget target = mService.getInputTargetFromToken(inputToken);
+ if (target == null) {
+ Slog.e(TAG_WM, "Unknown token, dropping notifyConnectionUnresponsive request");
+ return;
}
+
+ WindowState windowState = target.getWindowState();
+ pid = target.getPid();
+ // Blame the activity if the input token belongs to the window. If the target is
+ // embedded, then we will blame the pid instead.
+ activity = (windowState.mInputChannelToken == inputToken)
+ ? windowState.mActivityRecord : null;
+ Slog.i(TAG_WM, "ANR in " + target + ". Reason:" + reason);
aboveSystem = isWindowAboveSystem(windowState);
dumpAnrStateLocked(activity, windowState, reason);
}
@@ -109,19 +106,12 @@ class AnrController {
void notifyWindowResponsive(IBinder inputToken) {
final int pid;
synchronized (mService.mGlobalLock) {
- WindowState windowState = mService.mInputToWindowMap.get(inputToken);
- if (windowState != null) {
- pid = windowState.mSession.mPid;
- } else {
- // Check if the token belongs to an embedded window.
- EmbeddedWindow embeddedWindow = mService.mEmbeddedWindowController.get(inputToken);
- if (embeddedWindow == null) {
- Slog.e(TAG_WM,
- "Unknown token, dropping notifyWindowConnectionResponsive request");
- return;
- }
- pid = embeddedWindow.mOwnerPid;
+ InputTarget target = mService.getInputTargetFromToken(inputToken);
+ if (target == null) {
+ Slog.e(TAG_WM, "Unknown token, dropping notifyWindowConnectionResponsive request");
+ return;
}
+ pid = target.getPid();
}
mService.mAmInternal.inputDispatchingResumed(pid);
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index ffaf710523ee..535a061ee4ab 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -124,6 +124,7 @@ public class AppTransitionController {
@interface TransitContainerType {}
private final ArrayMap<WindowContainer, Integer> mTempTransitionReasons = new ArrayMap<>();
+ private final ArrayList<WindowContainer> mTempTransitionWindows = new ArrayList<>();
AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
@@ -523,26 +524,44 @@ public class AppTransitionController {
}
}
+ private boolean transitionMayContainNonAppWindows(@TransitionOldType int transit) {
+ // We don't want to have the client to animate any non-app windows.
+ // Having {@code transit} of those types doesn't mean it will contain non-app windows, but
+ // non-app windows will only be included with those transition types. And we don't currently
+ // have any use case of those for TaskFragment transition.
+ // @see NonAppWindowAnimationAdapter#startNonAppWindowAnimations
+ if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
+ || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
+ || transit == TRANSIT_OLD_TASK_OPEN || transit == TRANSIT_OLD_TASK_TO_FRONT
+ || transit == TRANSIT_OLD_WALLPAPER_CLOSE) {
+ return true;
+ }
+
+ // Check if the wallpaper is going to participate in the transition. We don't want to have
+ // the client to animate the wallpaper windows.
+ // @see WallpaperAnimationAdapter#startWallpaperAnimations
+ return mDisplayContent.mWallpaperController.isWallpaperVisible();
+ }
+
/**
- * Overrides the pending transition with the remote animation defined by the
- * {@link ITaskFragmentOrganizer} if all windows in the transition are children of
- * {@link TaskFragment} that are organized by the same organizer.
- *
- * @return {@code true} if the transition is overridden.
+ * Finds the common {@link android.window.TaskFragmentOrganizer} that organizes all app windows
+ * in the current transition.
+ * @return {@code null} if there is no such organizer, or if there are more than one.
*/
- private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
- ArraySet<Integer> activityTypes) {
- final ArrayList<WindowContainer> allWindows = new ArrayList<>();
- allWindows.addAll(mDisplayContent.mClosingApps);
- allWindows.addAll(mDisplayContent.mOpeningApps);
- allWindows.addAll(mDisplayContent.mChangingContainers);
+ @Nullable
+ private ITaskFragmentOrganizer findTaskFragmentOrganizerForAllWindows() {
+ mTempTransitionWindows.clear();
+ mTempTransitionWindows.addAll(mDisplayContent.mClosingApps);
+ mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps);
+ mTempTransitionWindows.addAll(mDisplayContent.mChangingContainers);
// It should only animated by the organizer if all windows are below the same leaf Task.
Task leafTask = null;
- for (int i = allWindows.size() - 1; i >= 0; i--) {
- final ActivityRecord r = getAppFromContainer(allWindows.get(i));
+ for (int i = mTempTransitionWindows.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = getAppFromContainer(mTempTransitionWindows.get(i));
if (r == null) {
- return false;
+ leafTask = null;
+ break;
}
// The activity may be a child of embedded Task, but we want to find the owner Task.
// As a result, find the organized TaskFragment first.
@@ -561,26 +580,31 @@ public class AppTransitionController {
? organizedTaskFragment.getTask()
: r.getTask();
if (task == null) {
- return false;
+ leafTask = null;
+ break;
}
// We don't want the organizer to handle transition of other non-embedded Task.
if (leafTask != null && leafTask != task) {
- return false;
+ leafTask = null;
+ break;
}
final ActivityRecord rootActivity = task.getRootActivity();
// We don't want the organizer to handle transition when the whole app is closing.
if (rootActivity == null) {
- return false;
+ leafTask = null;
+ break;
}
// We don't want the organizer to handle transition of non-embedded activity of other
// app.
if (r.getUid() != rootActivity.getUid() && !r.isEmbedded()) {
- return false;
+ leafTask = null;
+ break;
}
leafTask = task;
}
+ mTempTransitionWindows.clear();
if (leafTask == null) {
- return false;
+ return null;
}
// We don't support remote animation for Task with multiple TaskFragmentOrganizers.
@@ -599,12 +623,28 @@ public class AppTransitionController {
if (hasMultipleOrganizers) {
ProtoLog.e(WM_DEBUG_APP_TRANSITIONS, "We don't support remote animation for"
+ " Task with multiple TaskFragmentOrganizers.");
+ return null;
+ }
+ return organizer[0];
+ }
+
+ /**
+ * Overrides the pending transition with the remote animation defined by the
+ * {@link ITaskFragmentOrganizer} if all windows in the transition are children of
+ * {@link TaskFragment} that are organized by the same organizer.
+ *
+ * @return {@code true} if the transition is overridden.
+ */
+ private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
+ ArraySet<Integer> activityTypes) {
+ if (transitionMayContainNonAppWindows(transit)) {
return false;
}
- final RemoteAnimationDefinition definition = organizer[0] != null
+ final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizerForAllWindows();
+ final RemoteAnimationDefinition definition = organizer != null
? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
- .getRemoteAnimationDefinition(organizer[0])
+ .getRemoteAnimationDefinition(organizer)
: null;
final RemoteAnimationAdapter adapter = definition != null
? definition.getAdapter(transit, activityTypes)
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 46a4f8a26673..e14d30bf8447 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -91,6 +91,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LAYER_MIRRORING;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
@@ -127,7 +128,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -1003,8 +1003,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final boolean committed = winAnimator.commitFinishDrawingLocked();
if (isDefaultDisplay && committed) {
if (w.hasWallpaper()) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "First draw done in potential wallpaper target " + w);
+ ProtoLog.v(WM_DEBUG_WALLPAPER,
+ "First draw done in potential wallpaper target %s", w);
mWallpaperMayChange = true;
pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
if (DEBUG_LAYOUT_REPEATS) {
@@ -3099,6 +3099,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mOverlayLayer.release();
mInputMonitor.onDisplayRemoved();
mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this);
+ mWmService.mAccessibilityController.onDisplayRemoved(mDisplayId);
} finally {
mDisplayReady = false;
}
@@ -5155,9 +5156,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
onAppTransitionDone();
changes |= FINISH_LAYOUT_REDO_LAYOUT;
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG_WM, "Wallpaper layer changed: assigning layers + relayout");
- }
+ ProtoLog.v(WM_DEBUG_WALLPAPER, "Wallpaper layer changed: assigning layers + relayout");
computeImeTarget(true /* updateImeTarget */);
mWallpaperMayChange = true;
// Since the window list has been rebuilt, focus might have to be recomputed since the
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index b08d6e1dff9e..fc317a1212d5 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -127,7 +127,7 @@ class EmbeddedWindowController {
}
}
- static class EmbeddedWindow {
+ static class EmbeddedWindow implements InputTarget {
final IWindow mClient;
@Nullable final WindowState mHostWindowState;
@Nullable final ActivityRecord mHostActivityRecord;
@@ -166,7 +166,8 @@ class EmbeddedWindowController {
mDisplayId = displayId;
}
- String getName() {
+ @Override
+ public String toString() {
final String hostWindowName = (mHostWindowState != null)
? mHostWindowState.getWindowTag().toString() : "Internal";
return "EmbeddedWindow{ u" + UserHandle.getUserId(mOwnerUid) + " " + hostWindowName
@@ -183,7 +184,7 @@ class EmbeddedWindowController {
}
InputChannel openInputChannel() {
- final String name = getName();
+ final String name = toString();
mInputChannel = mWmService.mInputManager.createInputChannel(name);
return mInputChannel;
}
@@ -195,5 +196,25 @@ class EmbeddedWindowController {
mInputChannel = null;
}
}
+
+ @Override
+ public WindowState getWindowState() {
+ return mHostWindowState;
+ }
+
+ @Override
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ @Override
+ public IWindow getIWindow() {
+ return mClient;
+ }
+
+ @Override
+ public int getPid() {
+ return mOwnerPid;
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/InputTarget.java b/services/core/java/com/android/server/wm/InputTarget.java
new file mode 100644
index 000000000000..c7d328a2b18a
--- /dev/null
+++ b/services/core/java/com/android/server/wm/InputTarget.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 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.server.wm;
+
+import android.view.IWindow;
+
+/**
+ * Common interface between focusable objects.
+ *
+ * Both WindowState and EmbeddedWindows can receive input. This consolidates some common properties
+ * of both targets.
+ */
+interface InputTarget {
+ /* Get the WindowState associated with the target. */
+ WindowState getWindowState();
+
+ /* Display id of the target. */
+ int getDisplayId();
+
+ /* Client IWindow for the target. */
+ IWindow getIWindow();
+
+ /* Owning pid of the target. */
+ int getPid();
+}
+
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index c630e91ee306..bd41de3a9509 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -194,8 +194,7 @@ class KeyguardController {
if (keyguardChanged) {
// Irrelevant to AOD.
- dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */,
- false /* turningScreenOn */);
+ dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */);
mKeyguardGoingAway = false;
if (keyguardShowing) {
mDismissalRequested = false;
@@ -396,6 +395,8 @@ class KeyguardController {
mService.continueWindowLayout();
}
}
+ dismissMultiWindowModeForTaskIfNeeded(topActivity != null
+ ? topActivity.getRootTask() : null);
}
/**
@@ -421,21 +422,6 @@ class KeyguardController {
}
}
- /**
- * Called when somebody wants to turn screen on.
- */
- private void handleTurnScreenOn(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
-
- mTaskSupervisor.wakeUp("handleTurnScreenOn");
- if (mKeyguardShowing && canDismissKeyguard()) {
- mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
- mDismissalRequested = true;
- }
- }
-
boolean isDisplayOccluded(int displayId) {
return getDisplayState(displayId).mOccluded;
}
@@ -449,11 +435,9 @@ class KeyguardController {
}
private void dismissMultiWindowModeForTaskIfNeeded(
- @Nullable Task currentTaskControllingOcclusion, boolean turningScreenOn) {
- // If turningScreenOn is true, it means that the visibility state has changed from
- // currentTaskControllingOcclusion and we should update windowing mode.
+ @Nullable Task currentTaskControllingOcclusion) {
// TODO(b/113840485): Handle docked stack for individual display.
- if (!turningScreenOn && (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY))) {
+ if (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) {
return;
}
@@ -592,26 +576,17 @@ class KeyguardController {
&& controller.mWindowManager.isKeyguardSecure(
controller.mService.getCurrentUserId());
- boolean occludingChange = false;
- boolean turningScreenOn = false;
if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
&& mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
- && (mRequestDismissKeyguard || occludedByActivity
- || controller.canDismissKeyguard())) {
- turningScreenOn = true;
- controller.handleTurnScreenOn(mDisplayId);
+ && (mRequestDismissKeyguard || occludedByActivity)) {
+ controller.mTaskSupervisor.wakeUp("handleTurnScreenOn");
mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
if (lastOccluded != mOccluded) {
- occludingChange = true;
controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
}
-
- if (occludingChange || turningScreenOn) {
- controller.dismissMultiWindowModeForTaskIfNeeded(task, turningScreenOn);
- }
}
/**
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index a663c62b40e5..22c84590fcfc 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -793,7 +793,7 @@ public class RecentsAnimationController implements DeathRecipient {
private RemoteAnimationTarget[] createWallpaperAnimations() {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "createWallpaperAnimations()");
- return WallpaperAnimationAdapter.startWallpaperAnimations(mService, 0L, 0L,
+ return WallpaperAnimationAdapter.startWallpaperAnimations(mDisplayContent, 0L, 0L,
adapter -> {
synchronized (mService.mGlobalLock) {
// If the wallpaper animation is canceled, continue with the recents
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 16a45fe7cec7..ca1aed52fe04 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -207,7 +207,7 @@ class RemoteAnimationController implements DeathRecipient {
if (wrappers.mThumbnailAdapter != null
&& wrappers.mThumbnailAdapter.mCapturedFinishCallback != null) {
wrappers.mThumbnailAdapter.mCapturedFinishCallback
- .onAnimationFinished(wrappers.mAdapter.mAnimationType,
+ .onAnimationFinished(wrappers.mThumbnailAdapter.mAnimationType,
wrappers.mThumbnailAdapter);
}
mPendingAnimations.remove(i);
@@ -218,7 +218,7 @@ class RemoteAnimationController implements DeathRecipient {
private RemoteAnimationTarget[] createWallpaperAnimations() {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createWallpaperAnimations()");
- return WallpaperAnimationAdapter.startWallpaperAnimations(mService,
+ return WallpaperAnimationAdapter.startWallpaperAnimations(mDisplayContent,
mRemoteAnimationAdapter.getDuration(),
mRemoteAnimationAdapter.getStatusBarTransitionDelay(),
adapter -> {
@@ -260,7 +260,7 @@ class RemoteAnimationController implements DeathRecipient {
}
if (adapters.mThumbnailAdapter != null) {
adapters.mThumbnailAdapter.mCapturedFinishCallback
- .onAnimationFinished(adapters.mAdapter.mAnimationType,
+ .onAnimationFinished(adapters.mThumbnailAdapter.mAnimationType,
adapters.mThumbnailAdapter);
}
mPendingAnimations.remove(i);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 97ea41c2f228..0f7c6497ff72 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -48,6 +48,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_O
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST;
@@ -79,7 +80,6 @@ import static com.android.server.wm.Task.REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_INVISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -504,6 +504,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mTopFocusedDisplayId = topFocusedDisplayId;
mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);
mWmService.mPolicy.setTopFocusedDisplay(topFocusedDisplayId);
+ mWmService.mAccessibilityController.setFocusedDisplay(topFocusedDisplayId);
ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d", topFocusedDisplayId);
}
return changed;
@@ -893,7 +894,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
if (displayContent.mWallpaperMayChange) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change! Adjusting");
+ ProtoLog.v(WM_DEBUG_WALLPAPER, "Wallpaper may change! Adjusting");
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
if (DEBUG_LAYOUT_REPEATS) {
surfacePlacer.debugLayoutRepeats("WallpaperMayChange",
@@ -2150,6 +2151,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final Task rootTask;
if (singleActivity) {
rootTask = task;
+
+ // Apply the last recents animation leash transform to the task entering PIP
+ rootTask.maybeApplyLastRecentsAnimationTransaction();
} else {
// In the case of multiple activities, we will create a new task for it and then
// move the PIP activity into the task. Note that we explicitly defer the task
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index c7bf8ecfe949..d712bbf0fdef 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -57,8 +57,11 @@ class SurfaceAnimator {
@VisibleForTesting
SurfaceControl mLeash;
@VisibleForTesting
+ SurfaceFreezer.Snapshot mSnapshot;
+ @VisibleForTesting
final Animatable mAnimatable;
- private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
+ @VisibleForTesting
+ final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
/**
* Static callback to run on all animations started through this SurfaceAnimator
@@ -151,12 +154,14 @@ class SurfaceAnimator {
* @param animationFinishedCallback The callback being triggered when the animation finishes.
* @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
* cancel call to the underlying AnimationAdapter.
+ * @param snapshotAnim The animation to run for the snapshot. {@code null} if there is no
+ * snapshot.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback,
@Nullable Runnable animationCancelledCallback,
- @Nullable SurfaceFreezer freezer) {
+ @Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
mAnimation = anim;
mAnimationType = type;
@@ -181,12 +186,16 @@ class SurfaceAnimator {
return;
}
mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
+ if (snapshotAnim != null) {
+ mSnapshot = freezer.takeSnapshotForAnimation();
+ mSnapshot.startAnimation(t, snapshotAnim, type);
+ }
}
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type) {
startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */,
- null /* animationCancelledCallback */, null /* freezer */);
+ null /* animationCancelledCallback */, null /* snapshotAnim */, null /* freezer */);
}
/**
@@ -328,6 +337,7 @@ class SurfaceAnimator {
final OnAnimationFinishedCallback animationFinishedCallback =
mSurfaceAnimationFinishedCallback;
final Runnable animationCancelledCallback = mAnimationCancelledCallback;
+ final SurfaceFreezer.Snapshot snapshot = mSnapshot;
reset(t, false);
if (animation != null) {
if (!mAnimationStartDelayed && forwardCancel) {
@@ -346,9 +356,14 @@ class SurfaceAnimator {
}
}
- if (forwardCancel && leash != null) {
- t.remove(leash);
- mService.scheduleAnimationLocked();
+ if (forwardCancel) {
+ if (snapshot != null) {
+ snapshot.cancelAnimation(t, false /* restarting */);
+ }
+ if (leash != null) {
+ t.remove(leash);
+ mService.scheduleAnimationLocked();
+ }
}
if (!restarting) {
@@ -361,6 +376,12 @@ class SurfaceAnimator {
mAnimation = null;
mSurfaceAnimationFinishedCallback = null;
mAnimationType = ANIMATION_TYPE_NONE;
+ final SurfaceFreezer.Snapshot snapshot = mSnapshot;
+ mSnapshot = null;
+ if (snapshot != null) {
+ // Reset the mSnapshot reference before calling the callback to prevent circular reset.
+ snapshot.cancelAnimation(t, !destroyLeash);
+ }
if (mLeash == null) {
return;
}
@@ -377,11 +398,15 @@ class SurfaceAnimator {
boolean scheduleAnim = false;
final SurfaceControl surface = animatable.getSurfaceControl();
final SurfaceControl parent = animatable.getParentSurfaceControl();
+ final SurfaceControl curAnimationLeash = animatable.getAnimationLeash();
// If the surface was destroyed or the leash is invalid, we don't care to reparent it back.
// Note that we also set this variable to true even if the parent isn't valid anymore, in
// order to ensure onAnimationLeashLost still gets called in this case.
- final boolean reparent = surface != null;
+ // If the animation leash is set, and it is different from the removing leash, it means the
+ // surface now has a new animation surface. We don't want to reparent for that.
+ final boolean reparent = surface != null && (curAnimationLeash == null
+ || curAnimationLeash.equals(leash));
if (reparent) {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent: " + parent);
// We shouldn't really need these isValid checks but we do
@@ -608,6 +633,14 @@ class SurfaceAnimator {
void onAnimationLeashLost(Transaction t);
/**
+ * Gets the last created animation leash that has not lost yet.
+ */
+ @Nullable
+ default SurfaceControl getAnimationLeash() {
+ return null;
+ }
+
+ /**
* @return A new surface to be used for the animation leash, inserted at the correct
* position in the hierarchy.
*/
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index 89986cefb207..9a0cabebbdc6 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION;
import android.annotation.NonNull;
@@ -27,13 +26,11 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
-import android.view.Surface;
import android.view.SurfaceControl;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
-import java.util.function.Supplier;
-
/**
* This class handles "freezing" of an Animatable. The Animatable in question should implement
* Freezable.
@@ -54,7 +51,8 @@ class SurfaceFreezer {
private final Freezable mAnimatable;
private final WindowManagerService mWmService;
- private SurfaceControl mLeash;
+ @VisibleForTesting
+ SurfaceControl mLeash;
Snapshot mSnapshot = null;
final Rect mFreezeBounds = new Rect();
@@ -94,7 +92,7 @@ class SurfaceFreezer {
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
return;
}
- mSnapshot = new Snapshot(mWmService.mSurfaceFactory, t, screenshotBuffer, mLeash);
+ mSnapshot = new Snapshot(t, screenshotBuffer, mLeash);
}
}
@@ -109,12 +107,25 @@ class SurfaceFreezer {
}
/**
+ * Used by {@link SurfaceAnimator}. This "transfers" the snapshot leash to be used for
+ * animation. By transferring the leash, this will no longer try to clean-up the leash when
+ * finished.
+ */
+ @Nullable
+ Snapshot takeSnapshotForAnimation() {
+ final Snapshot out = mSnapshot;
+ mSnapshot = null;
+ return out;
+ }
+
+ /**
* Clean-up the snapshot and remove leash. If the leash was taken, this just cleans-up the
* snapshot.
*/
void unfreeze(SurfaceControl.Transaction t) {
if (mSnapshot != null) {
mSnapshot.cancelAnimation(t, false /* restarting */);
+ mSnapshot = null;
}
if (mLeash == null) {
return;
@@ -163,13 +174,12 @@ class SurfaceFreezer {
class Snapshot {
private SurfaceControl mSurfaceControl;
private AnimationAdapter mAnimation;
- private SurfaceAnimator.OnAnimationFinishedCallback mFinishedCallback;
/**
* @param t Transaction to create the thumbnail in.
* @param screenshotBuffer A thumbnail or placeholder for thumbnail to initialize with.
*/
- Snapshot(Supplier<Surface> surfaceFactory, SurfaceControl.Transaction t,
+ Snapshot(SurfaceControl.Transaction t,
SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
// We can't use a delegating constructor since we need to
// reference this::onAnimationFinished
@@ -211,19 +221,15 @@ class SurfaceFreezer {
* component responsible for running the animation. It runs the animation with
* {@link AnimationAdapter#startAnimation} once the hierarchy with
* the Leash has been set up.
- * @param animationFinishedCallback The callback being triggered when the animation
- * finishes.
*/
- void startAnimation(SurfaceControl.Transaction t, AnimationAdapter anim, int type,
- @Nullable SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback) {
+ void startAnimation(SurfaceControl.Transaction t, AnimationAdapter anim, int type) {
cancelAnimation(t, true /* restarting */);
mAnimation = anim;
- mFinishedCallback = animationFinishedCallback;
if (mSurfaceControl == null) {
cancelAnimation(t, false /* restarting */);
return;
}
- mAnimation.startAnimation(mSurfaceControl, t, type, animationFinishedCallback);
+ mAnimation.startAnimation(mSurfaceControl, t, type, null /* finishCallback */);
}
/**
@@ -235,18 +241,9 @@ class SurfaceFreezer {
void cancelAnimation(SurfaceControl.Transaction t, boolean restarting) {
final SurfaceControl leash = mSurfaceControl;
final AnimationAdapter animation = mAnimation;
- final SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback =
- mFinishedCallback;
mAnimation = null;
- mFinishedCallback = null;
if (animation != null) {
animation.onAnimationCancelled(leash);
- if (!restarting) {
- if (animationFinishedCallback != null) {
- animationFinishedCallback.onAnimationFinished(
- ANIMATION_TYPE_APP_TRANSITION, animation);
- }
- }
}
if (!restarting) {
destroy(t);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 5ce9938ff71d..ce93f2495c22 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -178,46 +178,49 @@ class TaskSnapshotController {
snapshotTasks(tasks, false /* allowSnapshotHome */);
}
- private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
- for (int i = tasks.size() - 1; i >= 0; i--) {
- final Task task = tasks.valueAt(i);
- final TaskSnapshot snapshot;
- final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
- if (snapshotHome) {
- snapshot = snapshotTask(task);
- } else {
- switch (getSnapshotMode(task)) {
- case SNAPSHOT_MODE_NONE:
- continue;
- case SNAPSHOT_MODE_APP_THEME:
- snapshot = drawAppThemeSnapshot(task);
- break;
- case SNAPSHOT_MODE_REAL:
- snapshot = snapshotTask(task);
- break;
- default:
- snapshot = null;
- break;
- }
+ void recordTaskSnapshot(Task task, boolean allowSnapshotHome) {
+ final TaskSnapshot snapshot;
+ final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
+ if (snapshotHome) {
+ snapshot = snapshotTask(task);
+ } else {
+ switch (getSnapshotMode(task)) {
+ case SNAPSHOT_MODE_NONE:
+ return;
+ case SNAPSHOT_MODE_APP_THEME:
+ snapshot = drawAppThemeSnapshot(task);
+ break;
+ case SNAPSHOT_MODE_REAL:
+ snapshot = snapshotTask(task);
+ break;
+ default:
+ snapshot = null;
+ break;
}
- if (snapshot != null) {
- final HardwareBuffer buffer = snapshot.getHardwareBuffer();
- if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
- buffer.close();
- Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
- + buffer.getHeight());
- } else {
- mCache.putSnapshot(task, snapshot);
- // Don't persist or notify the change for the temporal snapshot.
- if (!snapshotHome) {
- mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
- task.onSnapshotChanged(snapshot);
- }
+ }
+ if (snapshot != null) {
+ final HardwareBuffer buffer = snapshot.getHardwareBuffer();
+ if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
+ buffer.close();
+ Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
+ + buffer.getHeight());
+ } else {
+ mCache.putSnapshot(task, snapshot);
+ // Don't persist or notify the change for the temporal snapshot.
+ if (!snapshotHome) {
+ mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+ task.onSnapshotChanged(snapshot);
}
}
}
}
+ private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ recordTaskSnapshot(tasks.valueAt(i), allowSnapshotHome);
+ }
+ }
+
/**
* Retrieves a snapshot. If {@param restoreFromDisk} equals {@code true}, DO NOT HOLD THE WINDOW
* MANAGER LOCK WHEN CALLING THIS METHOD!
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index e50e8ef56778..e537c0afc147 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -415,7 +415,16 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (commitVisibility) {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
" Commit activity becoming invisible: %s", ar);
- ar.commitVisibility(false /* visible */, false /* performLayout */);
+ final Task task = ar.getTask();
+ if (task != null && !task.isVisibleRequested()
+ && mTransientLaunches != null) {
+ // If transition is transient, then snapshots are taken at end of
+ // transition.
+ mController.mTaskSnapshotController.recordTaskSnapshot(
+ task, false /* allowSnapshotHome */);
+ }
+ ar.commitVisibility(false /* visible */, false /* performLayout */,
+ true /* fromTransition */);
activitiesWentInvisible = true;
}
}
@@ -558,6 +567,19 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mVisibleAtTransitionEndTokens.add(wc.asWindowToken());
}
+ // Take task snapshots before the animation so that we can capture IME before it gets
+ // transferred. If transition is transient, IME won't be moved during the transition and
+ // the tasks are still live, so we take the snapshot at the end of the transition instead.
+ if (mTransientLaunches == null) {
+ for (int i = mParticipants.size() - 1; i >= 0; --i) {
+ final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
+ if (ar == null || ar.isVisibleRequested() || ar.getTask() == null
+ || ar.getTask().isVisibleRequested()) continue;
+ mController.mTaskSnapshotController.recordTaskSnapshot(
+ ar.getTask(), false /* allowSnapshotHome */);
+ }
+ }
+
mStartTransaction = transaction;
mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
buildFinishTransaction(mFinishTransaction, info.getRootLeash());
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index fc5423942dc3..ff4cc3d1b784 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -59,6 +59,7 @@ class TransitionController {
private ITransitionPlayer mTransitionPlayer;
final ActivityTaskManagerService mAtm;
+ final TaskSnapshotController mTaskSnapshotController;
private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners =
new ArrayList<>();
@@ -79,9 +80,11 @@ class TransitionController {
// TODO(b/188595497): remove when not needed.
final StatusBarManagerInternal mStatusBar;
- TransitionController(ActivityTaskManagerService atm) {
+ TransitionController(ActivityTaskManagerService atm,
+ TaskSnapshotController taskSnapshotController) {
mAtm = atm;
mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
+ mTaskSnapshotController = taskSnapshotController;
mTransitionPlayerDeath = () -> {
synchronized (mAtm.mGlobalLock) {
// Clean-up/finish any playing transitions.
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 25f7269effe8..0b20f37eea0f 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -64,18 +64,17 @@ class WallpaperAnimationAdapter implements AnimationAdapter {
*
* @return RemoteAnimationTarget[] targets for all the visible wallpaper windows
*/
- public static RemoteAnimationTarget[] startWallpaperAnimations(WindowManagerService service,
+ public static RemoteAnimationTarget[] startWallpaperAnimations(DisplayContent displayContent,
long durationHint, long statusBarTransitionDelay,
Consumer<WallpaperAnimationAdapter> animationCanceledRunnable,
ArrayList<WallpaperAnimationAdapter> adaptersOut) {
+ if (!displayContent.mWallpaperController.isWallpaperVisible()) {
+ ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
+ "\tWallpaper of display=%s is not visible", displayContent);
+ return new RemoteAnimationTarget[0];
+ }
final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
- service.mRoot.forAllWallpaperWindows(wallpaperWindow -> {
- if (!wallpaperWindow.getDisplayContent().mWallpaperController.isWallpaperVisible()) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tNot visible=%s", wallpaperWindow);
- return;
- }
-
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tvisible=%s", wallpaperWindow);
+ displayContent.forAllWallpaperWindows(wallpaperWindow -> {
final WallpaperAnimationAdapter wallpaperAdapter = new WallpaperAnimationAdapter(
wallpaperWindow, durationHint, statusBarTransitionDelay,
animationCanceledRunnable);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 0909462585af..a92e0883db37 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -24,12 +24,12 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT;
@@ -49,6 +49,8 @@ import android.view.WindowManager;
import android.view.animation.Animation;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.ProtoLogImpl;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import java.io.PrintWriter;
@@ -291,10 +293,11 @@ class WallpaperController {
for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
final WallpaperWindowToken token = mWallpaperTokens.get(i);
token.setVisibility(false);
- if (DEBUG_WALLPAPER_LIGHT && token.isVisible()) {
- Slog.d(TAG, "Hiding wallpaper " + token
- + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
- + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " "));
+ if (ProtoLogImpl.isEnabled(WM_DEBUG_WALLPAPER) && token.isVisible()) {
+ ProtoLog.d(WM_DEBUG_WALLPAPER,
+ "Hiding wallpaper %s from %s target=%s prev=%s callers=%s",
+ token, winGoingAway, mWallpaperTarget, mPrevWallpaperTarget,
+ Debug.getCallers(5));
}
}
}
@@ -544,15 +547,15 @@ class WallpaperController {
// Is it time to stop animating?
if (!mPrevWallpaperTarget.isAnimatingLw()) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!");
+ ProtoLog.v(WM_DEBUG_WALLPAPER, "No longer animating wallpaper targets!");
mPrevWallpaperTarget = null;
mWallpaperTarget = wallpaperTarget;
}
return;
}
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "New wallpaper target: " + wallpaperTarget + " prevTarget: " + mWallpaperTarget);
+ ProtoLog.v(WM_DEBUG_WALLPAPER, "New wallpaper target: %s prevTarget: %s caller=%s",
+ wallpaperTarget, mWallpaperTarget, Debug.getCallers(5));
mPrevWallpaperTarget = null;
@@ -570,8 +573,8 @@ class WallpaperController {
// then we are in our super special mode!
boolean oldAnim = prevWallpaperTarget.isAnimatingLw();
boolean foundAnim = wallpaperTarget.isAnimatingLw();
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "New animation: " + foundAnim + " old animation: " + oldAnim);
+ ProtoLog.v(WM_DEBUG_WALLPAPER, "New animation: %s old animation: %s",
+ foundAnim, oldAnim);
if (!foundAnim || !oldAnim) {
return;
@@ -586,14 +589,14 @@ class WallpaperController {
final boolean oldTargetHidden = prevWallpaperTarget.mActivityRecord != null
&& !prevWallpaperTarget.mActivityRecord.mVisibleRequested;
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: "
- + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget
- + " hidden=" + newTargetHidden);
+ ProtoLog.v(WM_DEBUG_WALLPAPER, "Animating wallpapers: "
+ + "old: %s hidden=%b new: %s hidden=%b",
+ prevWallpaperTarget, oldTargetHidden, wallpaperTarget, newTargetHidden);
mPrevWallpaperTarget = prevWallpaperTarget;
if (newTargetHidden && !oldTargetHidden) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target.");
+ ProtoLog.v(WM_DEBUG_WALLPAPER, "Old wallpaper still the target.");
// Use the old target if new target is hidden but old target
// is not. If they're both hidden, still use the new target.
mWallpaperTarget = prevWallpaperTarget;
@@ -661,8 +664,8 @@ class WallpaperController {
/* x= */ 0, /* y= */ 0, /* z= */ 0, /* extras= */ null, /* sync= */ false);
}
- if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
- + " prev=" + mPrevWallpaperTarget);
+ ProtoLog.d(WM_DEBUG_WALLPAPER, "New wallpaper: target=%s prev=%s",
+ mWallpaperTarget, mPrevWallpaperTarget);
}
boolean processWallpaperDrawPendingTimeout() {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 75c84c44c48e..3a639f50603f 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -20,7 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -28,7 +28,6 @@ import android.annotation.Nullable;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Slog;
import android.view.DisplayInfo;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -107,8 +106,8 @@ class WallpaperWindowToken extends WindowToken {
void updateWallpaperWindows(boolean visible) {
if (isVisible() != visible) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
- "Wallpaper token " + token + " visible=" + visible);
+ ProtoLog.d(WM_DEBUG_WALLPAPER, "Wallpaper token %s visible=%b",
+ token, visible);
setVisibility(visible);
}
final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 9a4bf6318249..51ecce0ec9ec 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -111,6 +111,7 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -178,6 +179,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
*/
protected final SurfaceAnimator mSurfaceAnimator;
+ /** The parent leash added for animation. */
+ @Nullable
+ private SurfaceControl mAnimationLeash;
+
final SurfaceFreezer mSurfaceFreezer;
protected final WindowManagerService mWmService;
final TransitionController mTransitionController;
@@ -2561,11 +2566,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* @param animationFinishedCallback The callback being triggered when the animation finishes.
* @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
* cancel call to the underlying AnimationAdapter.
+ * @param snapshotAnim The animation to run for the snapshot. {@code null} if there is no
+ * snapshot.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback,
- @Nullable Runnable animationCancelledCallback) {
+ @Nullable Runnable animationCancelledCallback,
+ @Nullable AnimationAdapter snapshotAnim) {
if (DEBUG_ANIM) {
Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim);
}
@@ -2573,14 +2581,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
// TODO: This should use isVisible() but because isVisible has a really weird meaning at
// the moment this doesn't work for all animatable window containers.
mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
- animationCancelledCallback, mSurfaceFreezer);
+ animationCancelledCallback, snapshotAnim, mSurfaceFreezer);
}
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback) {
startAnimation(t, anim, hidden, type, animationFinishedCallback,
- null /* adapterAnimationCancelledCallback */);
+ null /* adapterAnimationCancelledCallback */, null /* snapshotAnim */);
}
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@@ -2828,21 +2836,26 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
taskDisplayArea.setBackgroundColor(backgroundColor);
}
+ // Atomic counter to make sure the clearColor callback is only called one.
+ // It will be called twice in the case we cancel the animation without restart
+ // (in that case it will run as the cancel and finished callbacks).
+ final AtomicInteger callbackCounter = new AtomicInteger(0);
+ final Runnable clearBackgroundColorHandler = () -> {
+ if (callbackCounter.getAndIncrement() == 0) {
+ taskDisplayArea.clearBackgroundColor();
+ }
+ };
+
final Runnable cleanUpCallback = isSettingBackgroundColor
- ? taskDisplayArea::clearBackgroundColor : () -> {};
+ ? clearBackgroundColorHandler : () -> {};
startAnimation(getPendingTransaction(), adapter, !isVisible(),
- ANIMATION_TYPE_APP_TRANSITION,
- (type, anim) -> cleanUpCallback.run(),
- cleanUpCallback);
+ ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> cleanUpCallback.run(),
+ cleanUpCallback, thumbnailAdapter);
if (adapter.getShowWallpaper()) {
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
- if (thumbnailAdapter != null) {
- mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(),
- thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> { });
- }
}
}
@@ -2972,6 +2985,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
@Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
mLastLayer = -1;
+ mAnimationLeash = leash;
reassignLayer(t);
// Leash is now responsible for position, so set our position to 0.
@@ -2981,11 +2995,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
@Override
public void onAnimationLeashLost(Transaction t) {
mLastLayer = -1;
- mSurfaceFreezer.unfreeze(t);
+ mAnimationLeash = null;
reassignLayer(t);
updateSurfacePosition(t);
}
+ @Override
+ public SurfaceControl getAnimationLeash() {
+ return mAnimationLeash;
+ }
+
private void doAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
for (int i = 0; i < mSurfaceAnimationSources.size(); ++i) {
mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim);
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 08404411c02b..c95470071e2d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -43,7 +43,6 @@ public class WindowManagerDebugConfig {
static final boolean DEBUG_CONFIGURATION = false;
static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false;
static final boolean DEBUG_WALLPAPER = false;
- static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
static final boolean DEBUG_DRAG = true;
static final boolean DEBUG_SCREENSHOT = false;
static final boolean DEBUG_LAYOUT_REPEATS = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4cf8c97eb132..776a65db365f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4981,23 +4981,49 @@ public class WindowManagerService extends IWindowManager.Stub
return Surface.ROTATION_0;
}
+ // Returns an input target which is mapped to the given input token. This can be a WindowState
+ // or an embedded window.
+ @Nullable InputTarget getInputTargetFromToken(IBinder inputToken) {
+ WindowState windowState = mInputToWindowMap.get(inputToken);
+ if (windowState != null) {
+ return windowState;
+ }
+
+ EmbeddedWindowController.EmbeddedWindow embeddedWindow =
+ mEmbeddedWindowController.get(inputToken);
+ if (embeddedWindow != null) {
+ return embeddedWindow;
+ }
+
+ return null;
+ }
+
void reportFocusChanged(IBinder oldToken, IBinder newToken) {
- WindowState lastFocus;
- WindowState newFocus;
+ InputTarget lastTarget;
+ InputTarget newTarget;
synchronized (mGlobalLock) {
- lastFocus = mInputToWindowMap.get(oldToken);
- newFocus = mInputToWindowMap.get(newToken);
- ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus changing: %s -> %s", lastFocus, newFocus);
+ lastTarget = getInputTargetFromToken(oldToken);
+ newTarget = getInputTargetFromToken(newToken);
+ if (newTarget == null && lastTarget == null) {
+ Slog.v(TAG_WM, "Unknown focus tokens, dropping reportFocusChanged");
+ return;
+ }
+
+ mAccessibilityController.onFocusChanged(lastTarget, newTarget);
+ ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus changing: %s -> %s", lastTarget, newTarget);
}
- if (newFocus != null) {
- mAnrController.onFocusChanged(newFocus);
- newFocus.reportFocusChangedSerialized(true);
+ // Call WindowState focus change observers
+ WindowState newFocusedWindow = newTarget != null ? newTarget.getWindowState() : null;
+ if (newFocusedWindow != null && newFocusedWindow.mInputChannelToken == newToken) {
+ mAnrController.onFocusChanged(newFocusedWindow);
+ newFocusedWindow.reportFocusChangedSerialized(true);
notifyFocusChanged();
}
- if (lastFocus != null) {
- lastFocus.reportFocusChangedSerialized(false);
+ WindowState lastFocusedWindow = lastTarget != null ? lastTarget.getWindowState() : null;
+ if (lastFocusedWindow != null && lastFocusedWindow.mInputChannelToken == oldToken) {
+ lastFocusedWindow.reportFocusChangedSerialized(false);
}
}
@@ -7522,11 +7548,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public IBinder getFocusedWindowToken() {
synchronized (mGlobalLock) {
- WindowState windowState = getFocusedWindowLocked();
- if (windowState != null) {
- return windowState.mClient.asBinder();
- }
- return null;
+ return mAccessibilityController.getFocusedWindowToken();
}
}
@@ -8267,7 +8289,7 @@ public class WindowManagerService extends IWindowManager.Stub
clientChannel = win.openInputChannel();
mEmbeddedWindowController.add(clientChannel.getToken(), win);
applicationHandle = win.getApplicationHandle();
- name = win.getName();
+ name = win.toString();
}
updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
@@ -8333,7 +8355,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.e(TAG, "Couldn't find window for provided channelToken.");
return;
}
- name = win.getName();
+ name = win.toString();
applicationHandle = win.getApplicationHandle();
}
@@ -8542,10 +8564,9 @@ public class WindowManagerService extends IWindowManager.Stub
SurfaceControl.Transaction t = mTransactionFactory.get();
final int displayId = embeddedWindow.mDisplayId;
if (grantFocus) {
- t.setFocusedWindow(inputToken, embeddedWindow.getName(), displayId).apply();
+ t.setFocusedWindow(inputToken, embeddedWindow.toString(), displayId).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
- "Focus request " + embeddedWindow.getName(),
- "reason=grantEmbeddedWindowFocus(true)");
+ "Focus request " + embeddedWindow, "reason=grantEmbeddedWindowFocus(true)");
} else {
// Search for a new focus target
DisplayContent displayContent = mRoot.getDisplayContent(displayId);
@@ -8554,18 +8575,18 @@ public class WindowManagerService extends IWindowManager.Stub
if (newFocusTarget == null) {
ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus remove request for "
+ "win=%s dropped since no candidate was found",
- embeddedWindow.getName());
+ embeddedWindow);
return;
}
t.requestFocusTransfer(newFocusTarget.mInputChannelToken, newFocusTarget.getName(),
- inputToken, embeddedWindow.getName(),
+ inputToken, embeddedWindow.toString(),
displayId).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + newFocusTarget,
"reason=grantEmbeddedWindowFocus(false)");
}
ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus win=%s grantFocus=%s",
- embeddedWindow.getName(), grantFocus);
+ embeddedWindow, grantFocus);
}
}
@@ -8594,24 +8615,24 @@ public class WindowManagerService extends IWindowManager.Stub
}
SurfaceControl.Transaction t = mTransactionFactory.get();
if (grantFocus) {
- t.requestFocusTransfer(targetInputToken, embeddedWindow.getName(),
+ t.requestFocusTransfer(targetInputToken, embeddedWindow.toString(),
hostWindow.mInputChannel.getToken(),
hostWindow.getName(),
hostWindow.getDisplayId()).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
- "Transfer focus request " + embeddedWindow.getName(),
+ "Transfer focus request " + embeddedWindow,
"reason=grantEmbeddedWindowFocus(true)");
} else {
t.requestFocusTransfer(hostWindow.mInputChannel.getToken(), hostWindow.getName(),
targetInputToken,
- embeddedWindow.getName(),
+ embeddedWindow.toString(),
hostWindow.getDisplayId()).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + hostWindow,
"reason=grantEmbeddedWindowFocus(false)");
}
ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus win=%s grantFocus=%s",
- embeddedWindow.getName(), grantFocus);
+ embeddedWindow, grantFocus);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 781b53df998e..54ce5fc6bbec 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -117,7 +117,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final DisplayAreaOrganizerController mDisplayAreaOrganizerController;
final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
- final TransitionController mTransitionController;
+ TransitionController mTransitionController;
/**
* A Map which manages the relationship between
* {@link TaskFragmentCreationParams#getFragmentToken()} and {@link TaskFragment}
@@ -131,7 +131,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mTaskOrganizerController = new TaskOrganizerController(mService);
mDisplayAreaOrganizerController = new DisplayAreaOrganizerController(mService);
mTaskFragmentOrganizerController = new TaskFragmentOrganizerController(atm);
- mTransitionController = new TransitionController(atm);
+ }
+
+ void setWindowManager(WindowManagerService wms) {
+ mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController);
}
TransitionController getTransitionController() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ad4734f0526c..d29b2aecf793 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -273,7 +273,7 @@ import java.util.function.Predicate;
/** A window in the window manager. */
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,
- InsetsControlTarget {
+ InsetsControlTarget, InputTarget {
static final String TAG = TAG_WITH_CLASS_NAME ? "WindowState" : TAG_WM;
// The minimal size of a window within the usable area of the freeform root task.
@@ -1727,7 +1727,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return state;
}
- int getDisplayId() {
+ @Override
+ public int getDisplayId() {
final DisplayContent displayContent = getDisplayContent();
if (displayContent == null) {
return Display.INVALID_DISPLAY;
@@ -1735,6 +1736,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return displayContent.getDisplayId();
}
+ @Override
+ public WindowState getWindowState() {
+ return this;
+ }
+
+ @Override
+ public IWindow getIWindow() {
+ return mClient;
+ }
+
+ @Override
+ public int getPid() {
+ return mSession.mPid;
+ }
+
Task getTask() {
return mActivityRecord != null ? mActivityRecord.getTask() : null;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 82140f4d965c..5d0e34a80f3f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -43,6 +43,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -893,6 +894,33 @@ public class AppTransitionControllerTest extends WindowTestsBase {
}
@Test
+ public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() {
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ setupTaskFragmentRemoteAnimation(organizer, adapter);
+
+ // Create a TaskFragment with embedded activity.
+ final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
+ createTask(mDisplayContent), organizer);
+ final ActivityRecord activity = taskFragment.getTopMostActivity();
+ activity.allDrawn = true;
+ // Set wallpaper as visible.
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
+ spyOn(mDisplayContent.mWallpaperController);
+ doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare a transition.
+ prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+
+ // Should not be overridden when there is wallpaper in the transition.
+ verify(mDisplayContent.mAppTransition, never())
+ .overridePendingAppTransitionRemote(adapter, false /* sync */);
+ }
+
+ @Test
public void testTransitionGoodToGoForTaskFragments() {
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final Task task = createTask(mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 6d60bcf1fce6..a1c24c26af35 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -34,8 +34,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
@@ -448,7 +451,8 @@ public class TransitionTests extends WindowTestsBase {
@Test
public void testIntermediateVisibility() {
- final TransitionController controller = new TransitionController(mAtm);
+ final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
+ final TransitionController controller = new TransitionController(mAtm, snapshotController);
final ITransitionPlayer player = new ITransitionPlayer.Default();
controller.registerTransitionPlayer(player);
ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
@@ -511,6 +515,71 @@ public class TransitionTests extends WindowTestsBase {
assertTrue(activity2.isVisible());
}
+ @Test
+ public void testTransientLaunch() {
+ final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
+ final TransitionController controller = new TransitionController(mAtm, snapshotController);
+ final ITransitionPlayer player = new ITransitionPlayer.Default();
+ controller.registerTransitionPlayer(player);
+ ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
+ final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
+
+ // Start out with task2 visible and set up a transition that closes task2 and opens task1
+ final Task task1 = createTask(mDisplayContent);
+ task1.mTaskOrganizer = mockOrg;
+ final ActivityRecord activity1 = createActivityRecord(task1);
+ activity1.mVisibleRequested = false;
+ activity1.setVisible(false);
+ final Task task2 = createTask(mDisplayContent);
+ task2.mTaskOrganizer = mockOrg;
+ final ActivityRecord activity2 = createActivityRecord(task2);
+ activity2.mVisibleRequested = true;
+ activity2.setVisible(true);
+
+ openTransition.collectExistenceChange(task1);
+ openTransition.collectExistenceChange(activity1);
+ openTransition.collectExistenceChange(task2);
+ openTransition.collectExistenceChange(activity2);
+
+ activity1.mVisibleRequested = true;
+ activity1.setVisible(true);
+ activity2.mVisibleRequested = false;
+
+ // Using abort to force-finish the sync (since we can't wait for drawing in unit test).
+ // We didn't call abort on the transition itself, so it will still run onTransactionReady
+ // normally.
+ mWm.mSyncEngine.abort(openTransition.getSyncId());
+
+ verify(snapshotController, times(1)).recordTaskSnapshot(eq(task2), eq(false));
+
+ openTransition.finishTransition();
+
+ // We are now going to simulate closing task1 to return back to (open) task2.
+ final Transition closeTransition = controller.createTransition(TRANSIT_CLOSE);
+
+ closeTransition.collectExistenceChange(task1);
+ closeTransition.collectExistenceChange(activity1);
+ closeTransition.collectExistenceChange(task2);
+ closeTransition.collectExistenceChange(activity2);
+ closeTransition.setTransientLaunch(activity2);
+
+ activity1.mVisibleRequested = false;
+ activity2.mVisibleRequested = true;
+
+ // Using abort to force-finish the sync (since we obviously can't wait for drawing).
+ // We didn't call abort on the actual transition, so it will still run onTransactionReady
+ // normally.
+ mWm.mSyncEngine.abort(closeTransition.getSyncId());
+
+ // Make sure we haven't called recordSnapshot (since we are transient, it shouldn't be
+ // called until finish).
+ verify(snapshotController, times(0)).recordTaskSnapshot(eq(task1), eq(false));
+
+ closeTransition.finishTransition();
+
+ verify(snapshotController, times(1)).recordTaskSnapshot(eq(task1), eq(false));
+ }
+
/** Fill the change map with all the parents of top. Change maps are usually fully populated */
private static void fillChangeMap(ArrayMap<WindowContainer, Transition.ChangeInfo> changes,
WindowContainer top) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 68053eb324b2..bbeb980353ed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -25,6 +25,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
@@ -52,6 +53,7 @@ import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -1106,6 +1108,71 @@ public class WindowContainerTests extends WindowTestsBase {
verify(surfaceAnimator, never()).setRelativeLayer(any(), any(), anyInt());
}
+ @Test
+ public void testStartChangeTransitionWhenPreviousIsNotFinished() {
+ final WindowContainer container = createTaskFragmentWithParentTask(
+ createTask(mDisplayContent), false);
+ container.mSurfaceControl = mock(SurfaceControl.class);
+ final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator;
+ final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer;
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ spyOn(container);
+ spyOn(surfaceAnimator);
+ spyOn(surfaceFreezer);
+ doReturn(t).when(container).getPendingTransaction();
+ doReturn(t).when(container).getSyncTransaction();
+
+ // Leash and snapshot created for change transition.
+ container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
+ // Can't really take a snapshot, manually set one.
+ surfaceFreezer.mSnapshot = mock(SurfaceFreezer.Snapshot.class);
+
+ assertNotNull(surfaceFreezer.mLeash);
+ assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash());
+
+ // Start animation: surfaceAnimator take over the leash and snapshot from surfaceFreezer.
+ container.applyAnimationUnchecked(null /* lp */, true /* enter */,
+ TRANSIT_OLD_TASK_FRAGMENT_CHANGE, false /* isVoiceInteraction */,
+ null /* sources */);
+
+ assertNull(surfaceFreezer.mLeash);
+ assertNull(surfaceFreezer.mSnapshot);
+ assertNotNull(surfaceAnimator.mLeash);
+ assertNotNull(surfaceAnimator.mSnapshot);
+ final SurfaceControl prevLeash = surfaceAnimator.mLeash;
+ final SurfaceFreezer.Snapshot prevSnapshot = surfaceAnimator.mSnapshot;
+
+ // Prepare another change transition.
+ container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
+ surfaceFreezer.mSnapshot = mock(SurfaceFreezer.Snapshot.class);
+
+ assertNotNull(surfaceFreezer.mLeash);
+ assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash());
+ assertNotEquals(prevLeash, container.getAnimationLeash());
+
+ // Start another animation before the previous one is finished, it should reset the previous
+ // one, but not change the current one.
+ container.applyAnimationUnchecked(null /* lp */, true /* enter */,
+ TRANSIT_OLD_TASK_FRAGMENT_CHANGE, false /* isVoiceInteraction */,
+ null /* sources */);
+
+ verify(container, never()).onAnimationLeashLost(any());
+ verify(surfaceFreezer, never()).unfreeze(any());
+ assertNotNull(surfaceAnimator.mLeash);
+ assertNotNull(surfaceAnimator.mSnapshot);
+ assertEquals(surfaceAnimator.mLeash, container.getAnimationLeash());
+ assertNotEquals(prevLeash, surfaceAnimator.mLeash);
+ assertNotEquals(prevSnapshot, surfaceAnimator.mSnapshot);
+
+ // Clean up after animation finished.
+ surfaceAnimator.mInnerAnimationFinishedCallback.onAnimationFinished(
+ ANIMATION_TYPE_APP_TRANSITION, surfaceAnimator.getAnimation());
+
+ verify(container).onAnimationLeashLost(any());
+ assertNull(surfaceAnimator.mLeash);
+ assertNull(surfaceAnimator.mSnapshot);
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 562a0bd6a05d..64cb790d324b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -102,35 +102,33 @@ fun FlickerTestParameter.statusBarLayerIsVisible() {
}
}
-@JvmOverloads
-fun FlickerTestParameter.navBarLayerRotatesAndScales(
- beginRotation: Int,
- endRotation: Int = beginRotation
-) {
- val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
- val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
-
+fun FlickerTestParameter.navBarLayerRotatesAndScales() {
assertLayersStart {
- this.visibleRegion(FlickerComponentName.NAV_BAR).coversExactly(startingPos)
+ val display = this.entry.displays.minByOrNull { it.id }
+ ?: throw RuntimeException("There is no display!")
+ this.visibleRegion(FlickerComponentName.NAV_BAR)
+ .coversExactly(WindowUtils.getNavigationBarPosition(display))
}
assertLayersEnd {
- this.visibleRegion(FlickerComponentName.NAV_BAR).coversExactly(endingPos)
+ val display = this.entry.displays.minByOrNull { it.id }
+ ?: throw RuntimeException("There is no display!")
+ this.visibleRegion(FlickerComponentName.NAV_BAR)
+ .coversExactly(WindowUtils.getNavigationBarPosition(display))
}
}
-@JvmOverloads
-fun FlickerTestParameter.statusBarLayerRotatesScales(
- beginRotation: Int,
- endRotation: Int = beginRotation
-) {
- val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
- val endingPos = WindowUtils.getStatusBarPosition(endRotation)
-
+fun FlickerTestParameter.statusBarLayerRotatesScales() {
assertLayersStart {
- this.visibleRegion(FlickerComponentName.STATUS_BAR).coversExactly(startingPos)
+ val display = this.entry.displays.minByOrNull { it.id }
+ ?: throw RuntimeException("There is no display!")
+ this.visibleRegion(FlickerComponentName.STATUS_BAR)
+ .coversExactly(WindowUtils.getStatusBarPosition(display))
}
assertLayersEnd {
- this.visibleRegion(FlickerComponentName.STATUS_BAR).coversExactly(endingPos)
+ val display = this.entry.displays.minByOrNull { it.id }
+ ?: throw RuntimeException("There is no display!")
+ this.visibleRegion(FlickerComponentName.STATUS_BAR)
+ .coversExactly(WindowUtils.getStatusBarPosition(display))
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 9b34853092a2..9f26c31a6d63 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.close
-import android.platform.test.annotations.Postsubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -80,11 +79,6 @@ class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index e38079490618..795766fccfbd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.close
-import android.platform.test.annotations.Postsubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -79,11 +78,6 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index 04826191d8ad..511fc26fdb38 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -18,7 +18,6 @@ package com.android.server.wm.flicker.close
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
-import android.view.Surface
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
@@ -114,18 +113,14 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
*/
@Presubmit
@Test
- open fun navBarLayerRotatesAndScales() {
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
+ open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks the position of the status bar at the start and end of the transition
*/
@Presubmit
@Test
- open fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
+ open fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
/**
* Checks that all windows that are visible on the trace, are visible for at least 2
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
new file mode 100644
index 000000000000..be68704fc32d
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 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.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class NewTasksAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_LAUNCHER_NAME,
+ component: FlickerComponentName =
+ ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+ fun openNewTask(device: UiDevice, wmHelper: WindowManagerStateHelper) {
+ val button = device.wait(
+ Until.findObject(By.res(getPackage(), "launch_new_task")),
+ FIND_TIMEOUT)
+
+ require(button != null) {
+ "Button not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)"
+ }
+ button.click()
+ wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitForFullScreenApp(component)
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 35505367ce21..5e21aff94769 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -151,15 +151,11 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() {
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
- }
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
- }
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index f7f325ec7e22..0582685f2c54 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -150,15 +150,11 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() {
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 11660dfe43fc..91b3d3dae3cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -32,7 +32,6 @@ import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
@@ -121,21 +120,19 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
@Test
fun navBarLayerRotatesAndScales() {
Assume.assumeFalse(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ testSpec.navBarLayerRotatesAndScales()
}
@FlakyTest
@Test
fun navBarLayerRotatesAndScales_Flaky() {
Assume.assumeTrue(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ testSpec.navBarLayerRotatesAndScales()
}
@Presubmit
@Test
- fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
- }
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index bb2ffbc372d0..b589969dee14 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -34,7 +34,6 @@ import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
@@ -143,14 +142,11 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
new file mode 100644
index 000000000000..a9568b325af2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 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.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Launch an app that automatically displays the IME
+ *
+ * To run this test: `atest FlickerTests:LaunchAppShowImeOnStartTest`
+ *
+ * Actions:
+ * Make sure no apps are running on the device
+ * Launch an app [testApp] that automatically displays IME and wait animation to complete
+ *
+ * To run only the presubmit assertions add: `--
+ * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
+ * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit`
+ *
+ * To run only the postsubmit assertions add: `--
+ * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
+ * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit`
+ *
+ * To run only the flaky assertions add: `--
+ * --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest`
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [CloseAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class LaunchAppShowImeOnStartTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitImeShown()
+ }
+ }
+ }
+
+ /**
+ * Checks that [FlickerComponentName.IME] window becomes visible during the transition
+ */
+ @Presubmit
+ @Test
+ fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
+
+ /**
+ * Checks that [FlickerComponentName.IME] layer becomes visible during the transition
+ */
+ @Presubmit
+ @Test
+ fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+
+ /**
+ * Checks that [FlickerComponentName.IME] layer is invisible at the start of the transition
+ */
+ @Presubmit
+ @Test
+ fun imeLayerNotExistsStart() {
+ testSpec.assertLayersStart {
+ this.isInvisible(FlickerComponentName.IME)
+ }
+ }
+
+ /**
+ * Checks that [FlickerComponentName.IME] layer is visible at the end of the transition
+ */
+ @Presubmit
+ @Test
+ fun imeLayerExistsEnd() {
+ testSpec.assertLayersEnd {
+ this.isVisible(FlickerComponentName.IME)
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 5,
+ supportedRotations = listOf(Surface.ROTATION_0),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 44a27b1278c8..7bf0186cd857 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -34,7 +34,6 @@ import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
@@ -125,15 +124,11 @@ class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() {
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
- }
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
- }
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 7a017039534a..f6febe9e2234 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -38,7 +38,6 @@ import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
@@ -207,15 +206,11 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() {
- testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
- }
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
@Presubmit
@Test
- fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
- }
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 3678f33aa46e..663af703f76d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -27,6 +27,7 @@ import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -78,6 +79,11 @@ class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransitio
}
transitions {
device.reopenAppFromOverview(wmHelper)
+ wmHelper.waitFor(
+ WindowManagerConditionsFactory.hasLayersAnimating().negate(),
+ WindowManagerConditionsFactory.isWMStateComplete(),
+ WindowManagerConditionsFactory.isHomeActivityVisible().negate()
+ )
wmHelper.waitForFullScreenApp(testApp.component)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 1bdc23547bef..cf10c5366ce9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -28,6 +28,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
import com.google.common.truth.Truth
import org.junit.FixMethodOrder
@@ -107,7 +108,7 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
* Checks that the app layer doesn't exist at the start of the transition, that it is
* created (invisible) and becomes visible during the transition
*/
- @Presubmit
+ @FlakyTest
@Test
fun appLayerBecomesVisible() {
testSpec.assertLayers {
@@ -168,6 +169,11 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
/** {@inheritDoc} */
@FlakyTest
@Test
+ override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
+
+ /** {@inheritDoc} */
+ @FlakyTest
+ @Test
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 419d3e88983b..7af7b3ab6f24 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -18,13 +18,11 @@ package com.android.server.wm.flicker.launch
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
-import android.view.Surface
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.StandardAppHelper
@@ -98,9 +96,7 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
*/
@Presubmit
@Test
- open fun navBarLayerRotatesAndScales() {
- testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
- }
+ open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks that the status bar window is visible during the whole transition
@@ -125,9 +121,7 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
*/
@Presubmit
@Test
- open fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
- }
+ open fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
/**
* Checks that all windows that are visible on the trace, are visible for at least 2
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
new file mode 100644
index 000000000000..495e2d62a11d
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2021 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.server.wm.flicker.launch
+
+import android.app.Instrumentation
+import android.app.WallpaperManager
+import android.platform.test.annotations.Postsubmit
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.helpers.NewTasksAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.navBarLayerIsVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.flicker.testapp.ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME
+import com.android.server.wm.flicker.testapp.ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.FlickerComponentName.Companion.SPLASH_SCREEN
+import com.android.server.wm.traces.common.FlickerComponentName.Companion.WALLPAPER_BBQ_WRAPPER
+import com.android.server.wm.traces.parser.toFlickerComponent
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test the back and forward transition between 2 activities.
+ *
+ * To run this test: `atest FlickerTests:ActivitiesTransitionTest`
+ *
+ * Actions:
+ * Launch the NewTaskLauncherApp [mTestApp]
+ * Open a new task (SimpleActivity) from the NewTaskLauncherApp [mTestApp]
+ * Go back to the NewTaskLauncherApp [mTestApp]
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group4
+class TaskTransitionTest(val testSpec: FlickerTestParameter) {
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val mTestApp: NewTasksAppHelper = NewTasksAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ eachRun {
+ mTestApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(mTestApp.component)
+ }
+ }
+ teardown {
+ test {
+ mTestApp.exit()
+ }
+ }
+ transitions {
+ mTestApp.openNewTask(device, wmHelper)
+ device.pressBack()
+ wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitForFullScreenApp(mTestApp.component)
+ }
+ }
+ }
+
+ /**
+ * Checks that the wallpaper window is never visible when performing task transitions.
+ * A solid color background should be shown instead.
+ */
+ @Postsubmit
+ @Test
+ fun wallpaperWindowIsNeverVisible() {
+ testSpec.assertWm {
+ this.isNonAppWindowInvisible(WALLPAPER)
+ }
+ }
+
+ /**
+ * Checks that the wallpaper layer is never visible when performing task transitions.
+ * A solid color background should be shown instead.
+ */
+ @Postsubmit
+ @Test
+ fun wallpaperLayerIsNeverVisible() {
+ testSpec.assertLayers {
+ this.isInvisible(WALLPAPER)
+ this.isInvisible(WALLPAPER_BBQ_WRAPPER)
+ }
+ }
+
+ /**
+ * Check that the launcher window is never visible when performing task transitions.
+ * A solid color background should be shown above it.
+ */
+ @Postsubmit
+ @Test
+ fun launcherWindowIsNeverVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(LAUNCHER_COMPONENT)
+ }
+ }
+
+ /**
+ * Checks that the launcher layer is never visible when performing task transitions.
+ * A solid color background should be shown above it.
+ */
+ @Postsubmit
+ @Test
+ fun launcherLayerIsNeverVisible() {
+ testSpec.assertLayers {
+ this.isInvisible(LAUNCHER_COMPONENT)
+ }
+ }
+
+ /**
+ * Checks that a color background is visible while the task transition is occurring.
+ */
+ @Postsubmit
+ @Test
+ fun colorLayerIsVisibleDuringTransition() {
+ val bgColorLayer = FlickerComponentName("", "colorBackgroundLayer")
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+
+ testSpec.assertLayers {
+ this.coversExactly(displayBounds, LAUNCH_NEW_TASK_ACTIVITY)
+ .isInvisible(bgColorLayer)
+ .then()
+ // Transitioning
+ .isVisible(bgColorLayer)
+ .then()
+ // Fully transitioned to simple SIMPLE_ACTIVITY
+ .coversExactly(displayBounds, SIMPLE_ACTIVITY)
+ .isInvisible(bgColorLayer)
+ .then()
+ // Transitioning back
+ .isVisible(bgColorLayer)
+ .then()
+ // Fully transitioned back to LAUNCH_NEW_TASK_ACTIVITY
+ .isInvisible(bgColorLayer)
+ .coversExactly(displayBounds, LAUNCH_NEW_TASK_ACTIVITY)
+ }
+ }
+
+ /**
+ * Checks that we start with the LaunchNewTask activity on top and then open up
+ * the SimpleActivity and then go back to the LaunchNewTask activity.
+ */
+ @Postsubmit
+ @Test
+ fun newTaskOpensOnTopAndThenCloses() {
+ testSpec.assertWm {
+ this.isAppWindowOnTop(LAUNCH_NEW_TASK_ACTIVITY)
+ .then()
+ .isAppWindowOnTop(SPLASH_SCREEN, isOptional = true)
+ .then()
+ .isAppWindowOnTop(SIMPLE_ACTIVITY)
+ .then()
+ .isAppWindowOnTop(SPLASH_SCREEN, isOptional = true)
+ .then()
+ .isAppWindowOnTop(LAUNCH_NEW_TASK_ACTIVITY)
+ }
+ }
+
+ /**
+ * Checks that all parts of the screen are covered at the start and end of the transition
+ */
+ @Postsubmit
+ @Test
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
+
+ /**
+ * Checks that the navbar window is visible throughout the transition
+ */
+ @Postsubmit
+ @Test
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
+
+ /**
+ * Checks that the navbar layer is visible throughout the transition
+ */
+ @Postsubmit
+ @Test
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
+
+ /**
+ * Checks that the status bar window is visible throughout the transition
+ */
+ @Postsubmit
+ @Test
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
+
+ /**
+ * Checks that the status bar layer is visible throughout the transition
+ */
+ @Postsubmit
+ @Test
+ fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
+
+ companion object {
+ private val WALLPAPER = getWallpaperPackage(InstrumentationRegistry.getInstrumentation())
+ private val LAUNCH_NEW_TASK_ACTIVITY =
+ LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
+ private val SIMPLE_ACTIVITY = SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent()
+
+ private fun getWallpaperPackage(instrumentation: Instrumentation): FlickerComponentName {
+ val wallpaperManager = WallpaperManager.getInstance(instrumentation.targetContext)
+
+ return wallpaperManager.wallpaperInfo.component.toFlickerComponent()
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index cdab6818e209..52904cce8772 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -297,8 +297,7 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet
*/
@Postsubmit
@Test
- fun navbarIsAlwaysInRightPosition() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ fun navbarIsAlwaysInRightPosition() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks that the status bar window is visible throughout the entire transition.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index d1a3fe43b6da..842aa2b548db 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -314,8 +314,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
*/
@Postsubmit
@Test
- fun navbarIsAlwaysInRightPosition() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ fun navbarIsAlwaysInRightPosition() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks that the status bar window is visible throughout the entire transition.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index 0389f7ce8d8d..10ca0d9b323b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -305,8 +305,7 @@ class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) {
*/
@Presubmit
@Test
- fun navbarIsAlwaysInRightPosition() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ fun navbarIsAlwaysInRightPosition() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks that the status bar window is visible throughout the entire transition.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 878821a80d0e..fd8abc621b33 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.rotation
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -24,14 +25,14 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.rules.WMFlickerServiceRuleForTestSpec
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
import org.junit.FixMethodOrder
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -80,6 +81,9 @@ import org.junit.runners.Parameterized
class ChangeAppRotationTest(
testSpec: FlickerTestParameter
) : RotationTransition(testSpec) {
+ @get:Rule
+ val flickerRule = WMFlickerServiceRuleForTestSpec(testSpec)
+
override val testApp = SimpleAppHelper(instrumentation)
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
@@ -91,6 +95,24 @@ class ChangeAppRotationTest(
}
}
+ @Postsubmit
+ @Test
+ fun runPresubmitAssertion() {
+ flickerRule.checkPresubmitAssertions()
+ }
+
+ @Postsubmit
+ @Test
+ fun runPostsubmitAssertion() {
+ flickerRule.checkPostsubmitAssertions()
+ }
+
+ @FlakyTest
+ @Test
+ fun runFlakyAssertion() {
+ flickerRule.checkFlakyAssertions()
+ }
+
/** {@inheritDoc} */
@FlakyTest(bugId = 190185577)
@Test
@@ -111,6 +133,7 @@ class ChangeAppRotationTest(
.isVisible(FlickerComponentName.ROTATION)
.then()
.isVisible(testApp.component)
+ .isInvisible(FlickerComponentName.ROTATION)
}
}
@@ -138,10 +161,7 @@ class ChangeAppRotationTest(
*/
@Presubmit
@Test
- fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(
- testSpec.config.startRotation, testSpec.config.endRotation)
- }
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
/** {@inheritDoc} */
@FlakyTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 2b03396c6296..e850632ed8af 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -92,10 +92,7 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
*/
@Presubmit
@Test
- open fun navBarLayerRotatesAndScales() {
- testSpec.navBarLayerRotatesAndScales(
- testSpec.config.startRotation, testSpec.config.endRotation)
- }
+ open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks that all layers that are visible on the trace, are visible for at least 2
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 3b9f33aaded1..cb37fc7b47e9 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -80,5 +80,15 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name=".LaunchNewTaskActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewTaskActivity"
+ android:configChanges="orientation|screenSize"
+ android:label="LaunchNewTaskActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
new file mode 100644
index 000000000000..8f75d175d00a
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/holo_orange_light">
+ <Button
+ android:id="@+id/launch_new_task"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="New task" />
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 224d2ac38a11..baf36ab0e132 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -51,4 +51,9 @@ public class ActivityOptions {
public static final ComponentName BUTTON_ACTIVITY_COMPONENT_NAME =
new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ButtonActivity");
+
+ public static final String LAUNCH_NEW_TASK_ACTIVITY_LAUNCHER_NAME = "LaunchNewTaskApp";
+ public static final ComponentName LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".LaunchNewTaskActivity");
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
new file mode 100644
index 000000000000..1809781b33e6
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 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.server.wm.flicker.testapp;
+
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class LaunchNewTaskActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ WindowManager.LayoutParams p = getWindow().getAttributes();
+ p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+ .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ getWindow().setAttributes(p);
+ setContentView(R.layout.task_button);
+
+ Button button = findViewById(R.id.launch_new_task);
+ button.setOnClickListener(v -> {
+ Intent intent = new Intent(LaunchNewTaskActivity.this, SimpleActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
+ startActivity(intent);
+ });
+ }
+}