summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/aconfig/job.aconfig7
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java14
-rw-r--r--core/api/current.txt1
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/java/android/app/AppCompatTaskInfo.java23
-rw-r--r--core/java/android/app/WallpaperManager.java17
-rw-r--r--core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.aidl23
-rw-r--r--core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java113
-rw-r--r--core/java/android/hardware/input/InputSettings.java33
-rw-r--r--core/java/android/os/vibrator/flags.aconfig11
-rw-r--r--core/java/android/permission/flags.aconfig7
-rw-r--r--core/java/android/provider/Settings.java1
-rw-r--r--core/java/android/service/dreams/DreamService.java3
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java7
-rw-r--r--core/java/android/view/HandwritingInitiator.java5
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewOverlay.java15
-rw-r--r--core/java/android/view/ViewRootImpl.java63
-rw-r--r--core/java/android/widget/Editor.java44
-rw-r--r--core/java/android/widget/TextView.java12
-rw-r--r--core/java/android/window/flags/wallpaper_manager.aconfig10
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java1
-rw-r--r--core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java7
-rw-r--r--core/jni/android_os_SELinux.cpp14
-rw-r--r--core/res/Android.bp1
-rw-r--r--core/res/AndroidManifest.xml35
-rw-r--r--core/res/res/drawable/ic_zen_mode_icon_lotus_flower.xml25
-rw-r--r--core/res/res/drawable/ic_zen_mode_icon_rabbit.xml25
-rw-r--r--core/res/res/drawable/ic_zen_mode_type_unknown.xml2
-rw-r--r--core/tests/coretests/src/android/view/ViewFrameRateTest.java29
-rw-r--r--core/tests/coretests/src/android/widget/TextViewContextMenuTest.java17
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarImpl.java (renamed from libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java)103
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java2
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java96
-rw-r--r--libs/WindowManager/Shell/Android.bp8
-rw-r--r--libs/WindowManager/Shell/res/layout/compat_ui_restart_button_layout.xml41
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml2
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/ShellSharedConstants.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java)4
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransactionPool.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/common/TransactionPool.java)4
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TriangleShape.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java)4
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java)4
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/draganddrop/DragAndDropConstants.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropConstants.java)4
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/magnetictarget/MagnetizedObject.kt (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt)5
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java)6
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/startingsurface/SplashScreenExitAnimationUtils.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java)10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java41
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponent.kt212
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponentFactory.kt30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponentState.kt5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUISpec.kt31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/components/RestartButtonSpec.kt58
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/DefaultCompatUIComponentFactory.kt51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandler.kt46
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeDragAndDropTransitionHandler.kt111
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java82
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt119
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ReturnToDragStartAnimator.kt14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuView.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIComponentTest.kt122
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIHandlerRule.kt67
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIStateUtil.kt1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandlerTest.kt132
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIRepositoryTest.kt18
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUIComponentFactory.kt69
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUILayout.kt111
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUILifecyclePredicates.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUISpec.kt7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt68
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt76
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java32
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/SplitBoundsTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/magnetictarget/MagnetizedObjectTest.kt (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/magnetictarget/MagnetizedObjectTest.kt)4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/split/SplitScreenConstantsTest.kt (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitScreenConstantsTest.kt)1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java9
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/MockTransactionPool.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldAnimationControllerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt6
-rw-r--r--libs/androidfw/AssetManager2.cpp12
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h12
-rw-r--r--libs/androidfw/tests/AssetManager2_test.cpp20
-rw-r--r--libs/androidfw/tests/BenchmarkHelpers.cpp2
-rw-r--r--libs/androidfw/tests/Theme_test.cpp2
-rw-r--r--media/java/android/media/MediaCas.java14
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java38
-rw-r--r--media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java40
-rw-r--r--media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl26
-rw-r--r--media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl2
-rw-r--r--media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl2
-rw-r--r--media/jni/android_media_tv_Tuner.cpp40
-rw-r--r--media/jni/android_media_tv_Tuner.h8
-rw-r--r--media/jni/tuner/TunerClient.cpp10
-rw-r--r--media/jni/tuner/TunerClient.h10
-rw-r--r--nfc/java/android/nfc/cardemulation/CardEmulation.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java29
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModesBackend.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java33
-rw-r--r--packages/SettingsProvider/Android.bp1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java122
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig11
-rw-r--r--packages/SystemUI/Android.bp8
-rw-r--r--packages/SystemUI/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorTest.kt45
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/EditWidgetsActivityControllerTest.kt107
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt17
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt13
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt73
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropStateTest.kt123
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt226
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt133
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt12
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt96
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt91
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/data/model/GestureEduModel.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/data/repository/UserContextualEducationRepository.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/shared/model/EducationInfo.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt84
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/view/KeyboardTouchpadTutorialActivity.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialModule.kt (renamed from packages/SystemUI/src/com/android/systemui/inputdevice/oobe/KeyboardTouchpadTutorialModule.kt)0
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/TouchpadTutorialScreensProvider.kt (renamed from packages/SystemUI/src/com/android/systemui/inputdevice/oobe/TouchpadTutorialScreensProvider.kt)0
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/KeyboardTouchpadConnectionInteractor.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt (renamed from packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionKeyTutorialScreen.kt)0
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt (renamed from packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionTutorialContent.kt)0
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialComponents.kt (renamed from packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialComponents.kt)0
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt (renamed from packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialScreenConfig.kt)0
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt106
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt205
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/lifecycle/Activatable.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/lifecycle/SafeActivatable.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt146
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt207
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java184
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/FlowDumper.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt393
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt316
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java409
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt66
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/FakeContextualEducationRepository.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeActivatable.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeSysUiViewModel.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt11
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialKosmos.kt28
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt40
-rw-r--r--ravenwood/tools/ravenizer-fake/Android.bp14
-rwxr-xr-xravenwood/tools/ravenizer-fake/ravenizer31
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java39
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java41
-rw-r--r--services/core/java/com/android/server/am/BroadcastSentEventRecord.java134
-rw-r--r--services/core/java/com/android/server/am/flags.aconfig11
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java58
-rw-r--r--services/core/java/com/android/server/display/WakelockController.java73
-rw-r--r--services/core/java/com/android/server/input/InputSettingsObserver.java6
-rw-r--r--services/core/java/com/android/server/input/NativeInputManagerService.java5
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java186
-rw-r--r--services/core/java/com/android/server/notification/GroupHelper.java32
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java28
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java2
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java12
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/LnbResource.java3
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceBasic.java8
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java169
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java41
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java66
-rw-r--r--services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java4
-rw-r--r--services/core/java/com/android/server/wm/AppCompatUtils.java2
-rw-r--r--services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java180
-rw-r--r--services/core/java/com/android/server/wm/DimmerAnimationHelper.java54
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java8
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp30
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java26
-rw-r--r--services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp2
-rw-r--r--services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig2
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java11
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java24
-rw-r--r--services/tests/dreamservicetests/src/com/android/server/dreams/DreamServiceTest.java36
-rw-r--r--services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java60
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java159
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java110
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java648
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java13
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteSubscriberInfo.java2
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteSubscriberProvisionStatus.java2
-rw-r--r--tests/Input/src/com/android/server/input/InputManagerServiceTests.kt1
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt17
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt12
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt19
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt2
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt41
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt33
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt47
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt59
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt (renamed from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapper.kt)31
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt114
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt296
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt301
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt332
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt301
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt452
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt22
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java36
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java58
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java26
382 files changed, 8986 insertions, 2935 deletions
diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig
index e8568651eeaa..613b7842ae3a 100644
--- a/apex/jobscheduler/service/aconfig/job.aconfig
+++ b/apex/jobscheduler/service/aconfig/job.aconfig
@@ -58,3 +58,10 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "remove_user_during_user_switch"
+ namespace: "backstage_power"
+ description: "Remove started user if user will be stopped due to user switch"
+ bug: "321598070"
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 5f2b01a7304a..3d25ed5aa2b7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1669,6 +1669,20 @@ public class JobSchedulerService extends com.android.server.SystemService
}
@Override
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ if (!Flags.removeUserDuringUserSwitch()
+ || from == null
+ || !mActivityManagerInternal.isEarlyPackageKillEnabledForUserSwitch(
+ from.getUserIdentifier(),
+ to.getUserIdentifier())) {
+ return;
+ }
+ synchronized (mLock) {
+ mStartedUsers = ArrayUtils.removeInt(mStartedUsers, from.getUserIdentifier());
+ }
+ }
+
+ @Override
public void onUserStopping(@NonNull TargetUser user) {
synchronized (mLock) {
mStartedUsers = ArrayUtils.removeInt(mStartedUsers, user.getUserIdentifier());
diff --git a/core/api/current.txt b/core/api/current.txt
index c42d1ffcba6d..c1366a155aed 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -26,6 +26,7 @@ package android {
field public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+ field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String BIND_APP_FUNCTION_SERVICE = "android.permission.BIND_APP_FUNCTION_SERVICE";
field public static final String BIND_AUTOFILL_SERVICE = "android.permission.BIND_AUTOFILL_SERVICE";
field public static final String BIND_CALL_REDIRECTION_SERVICE = "android.permission.BIND_CALL_REDIRECTION_SERVICE";
field public static final String BIND_CARRIER_MESSAGING_CLIENT_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 445a57220757..fe792bc3a10b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -139,6 +139,8 @@ package android {
field @FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission") public static final String EMBED_ANY_APP_IN_UNTRUSTED_MODE = "android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE";
field @FlaggedApi("android.content.pm.emergency_install_permission") public static final String EMERGENCY_INSTALL_PACKAGES = "android.permission.EMERGENCY_INSTALL_PACKAGES";
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
+ field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String EXECUTE_APP_FUNCTIONS = "android.permission.EXECUTE_APP_FUNCTIONS";
+ field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String EXECUTE_APP_FUNCTIONS_TRUSTED = "android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED";
field public static final String EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS = "android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS";
field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
diff --git a/core/java/android/app/AppCompatTaskInfo.java b/core/java/android/app/AppCompatTaskInfo.java
index 81e9df66e18a..8370c2e522f3 100644
--- a/core/java/android/app/AppCompatTaskInfo.java
+++ b/core/java/android/app/AppCompatTaskInfo.java
@@ -95,6 +95,8 @@ public class AppCompatTaskInfo implements Parcelable {
private static final int FLAG_FULLSCREEN_OVERRIDE_SYSTEM = FLAG_BASE << 7;
/** Top activity flag for whether has activity has been overridden to fullscreen by user. */
private static final int FLAG_FULLSCREEN_OVERRIDE_USER = FLAG_BASE << 8;
+ /** Top activity flag for whether min aspect ratio of the activity has been overridden.*/
+ public static final int FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE = FLAG_BASE << 9;
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {
@@ -108,7 +110,8 @@ public class AppCompatTaskInfo implements Parcelable {
FLAG_IS_FROM_LETTERBOX_DOUBLE_TAP,
FLAG_ELIGIBLE_FOR_USER_ASPECT_RATIO_BUTTON,
FLAG_FULLSCREEN_OVERRIDE_SYSTEM,
- FLAG_FULLSCREEN_OVERRIDE_USER
+ FLAG_FULLSCREEN_OVERRIDE_USER,
+ FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE
})
public @interface TopActivityFlag {}
@@ -118,7 +121,7 @@ public class AppCompatTaskInfo implements Parcelable {
@TopActivityFlag
private static final int FLAGS_ORGANIZER_INTERESTED = FLAG_IS_FROM_LETTERBOX_DOUBLE_TAP
| FLAG_ELIGIBLE_FOR_USER_ASPECT_RATIO_BUTTON | FLAG_FULLSCREEN_OVERRIDE_SYSTEM
- | FLAG_FULLSCREEN_OVERRIDE_USER;
+ | FLAG_FULLSCREEN_OVERRIDE_USER | FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE;
@TopActivityFlag
private static final int FLAGS_COMPAT_UI_INTERESTED = FLAGS_ORGANIZER_INTERESTED
@@ -301,6 +304,21 @@ public class AppCompatTaskInfo implements Parcelable {
setTopActivityFlag(FLAG_LETTERBOXED, enable);
}
+ /**
+ * @return {@code true} if the top activity's min aspect ratio has been overridden.
+ */
+ public boolean hasMinAspectRatioOverride() {
+ return isTopActivityFlagEnabled(FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE);
+ }
+
+ /**
+ * Sets the top activity flag for whether the min aspect ratio of the activity has been
+ * overridden.
+ */
+ public void setHasMinAspectRatioOverride(boolean enable) {
+ setTopActivityFlag(FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE, enable);
+ }
+
/** Clear all top activity flags and set to false. */
public void clearTopActivityFlags() {
mTopActivityFlags = FLAG_UNDEFINED;
@@ -392,6 +410,7 @@ public class AppCompatTaskInfo implements Parcelable {
+ " topActivityLetterboxAppHeight=" + topActivityLetterboxAppHeight
+ " isUserFullscreenOverrideEnabled=" + isUserFullscreenOverrideEnabled()
+ " isSystemFullscreenOverrideEnabled=" + isSystemFullscreenOverrideEnabled()
+ + " hasMinAspectRatioOverride=" + hasMinAspectRatioOverride()
+ " cameraCompatTaskInfo=" + cameraCompatTaskInfo.toString()
+ "}";
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 5903a7ff619c..38f59adfcc1e 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1571,12 +1571,29 @@ public class WallpaperManager {
*/
@Nullable
public Rect peekBitmapDimensions(@SetWallpaperFlags int which, boolean returnDefault) {
+ if (multiCrop()) {
+ return peekBitmapDimensionsAsUser(which, returnDefault, mContext.getUserId());
+ }
checkExactlyOneWallpaperFlagSet(which);
return sGlobals.peekWallpaperDimensions(mContext, returnDefault, which,
mContext.getUserId());
}
/**
+ * Overload of {@link #peekBitmapDimensions(int, boolean)} with a userId argument.
+ * TODO(b/360120606): remove the SuppressWarnings
+ * @hide
+ */
+ @SuppressWarnings("AndroidFrameworkContextUserId")
+ @FlaggedApi(FLAG_MULTI_CROP)
+ @Nullable
+ public Rect peekBitmapDimensionsAsUser(@SetWallpaperFlags int which, boolean returnDefault,
+ int userId) {
+ checkExactlyOneWallpaperFlagSet(which);
+ return sGlobals.peekWallpaperDimensions(mContext, returnDefault, which, userId);
+ }
+
+ /**
* For the current user, given a list of display sizes, return a list of rectangles representing
* the area of the current wallpaper that would be shown for each of these sizes.
*
diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.aidl b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.aidl
new file mode 100644
index 000000000000..42ec45df8f25
--- /dev/null
+++ b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.aidl
@@ -0,0 +1,23 @@
+
+/*
+ * Copyright (C) 2024 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 android.app.appfunctions;
+
+import android.app.appfunctions.ExecuteAppFunctionAidlRequest;
+
+/** {@hide} */
+parcelable ExecuteAppFunctionAidlRequest; \ No newline at end of file
diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java
new file mode 100644
index 000000000000..2f3c555d9465
--- /dev/null
+++ b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2024 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 android.app.appfunctions;
+
+import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+
+import java.util.Objects;
+
+/**
+ * An internal request to execute an app function.
+ *
+ * @hide
+ */
+@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
+public final class ExecuteAppFunctionAidlRequest implements Parcelable {
+
+ public static final Creator<ExecuteAppFunctionAidlRequest> CREATOR =
+ new Creator<ExecuteAppFunctionAidlRequest>() {
+ @Override
+ public ExecuteAppFunctionAidlRequest createFromParcel(Parcel in) {
+ ExecuteAppFunctionRequest clientRequest =
+ ExecuteAppFunctionRequest.CREATOR.createFromParcel(in);
+ UserHandle userHandle =
+ UserHandle.CREATOR.createFromParcel(in);
+ String callingPackage = in.readString8();
+ return new ExecuteAppFunctionAidlRequest(
+ clientRequest, userHandle, callingPackage);
+ }
+
+ @Override
+ public ExecuteAppFunctionAidlRequest[] newArray(int size) {
+ return new ExecuteAppFunctionAidlRequest[size];
+ }
+ };
+
+ /**
+ * The client request to execute an app function.
+ */
+ private final ExecuteAppFunctionRequest mClientRequest;
+
+ /**
+ * The user handle of the user to execute the app function.
+ */
+ private final UserHandle mUserHandle;
+
+ /**
+ * The package name of the app that is requesting to execute the app function.
+ */
+ private final String mCallingPackage;
+
+ public ExecuteAppFunctionAidlRequest(
+ ExecuteAppFunctionRequest clientRequest, UserHandle userHandle, String callingPackage) {
+ this.mClientRequest = Objects.requireNonNull(clientRequest);
+ this.mUserHandle = Objects.requireNonNull(userHandle);
+ this.mCallingPackage = Objects.requireNonNull(callingPackage);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ mClientRequest.writeToParcel(dest, flags);
+ mUserHandle.writeToParcel(dest, flags);
+ dest.writeString8(mCallingPackage);
+ }
+
+ /**
+ * Returns the client request to execute an app function.
+ */
+ @NonNull
+ public ExecuteAppFunctionRequest getClientRequest() {
+ return mClientRequest;
+ }
+
+ /**
+ * Returns the user handle of the user to execute the app function.
+ */
+ @NonNull
+ public UserHandle getUserHandle() {
+ return mUserHandle;
+ }
+
+ /**
+ * Returns the package name of the app that is requesting to execute the app function.
+ */
+ @NonNull
+ public String getCallingPackage() {
+ return mCallingPackage;
+ }
+}
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index d85e41d19c68..c5d0caf228d2 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -336,6 +336,39 @@ public class InputSettings {
}
/**
+ * Returns true if the touchpad visualizer is allowed to appear.
+ *
+ * @param context The application context.
+ * @return Whether it is allowed to show touchpad visualizer or not.
+ *
+ * @hide
+ */
+ public static boolean useTouchpadVisualizer(@NonNull Context context) {
+ if (!isTouchpadVisualizerFeatureFlagEnabled()) {
+ return false;
+ }
+ return Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_VISUALIZER, 0, UserHandle.USER_CURRENT) == 1;
+ }
+
+ /**
+ * Sets the touchpad visualizer behaviour.
+ *
+ * @param context The application context.
+ * @param enabled Will enable touchpad visualizer if true, disable it if false
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+ public static void setTouchpadVisualizer(@NonNull Context context, boolean enabled) {
+ if (!isTouchpadVisualizerFeatureFlagEnabled()) {
+ return;
+ }
+ Settings.System.putIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_VISUALIZER, enabled ? 1 : 0, UserHandle.USER_CURRENT);
+ }
+
+ /**
* Returns true if the touchpad should allow tap dragging.
*
* The returned value only applies to gesture-compatible touchpads.
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index 53a1a67dfc58..e3b1221b3004 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -113,3 +113,14 @@ flag {
purpose: PURPOSE_FEATURE
}
}
+
+flag {
+ namespace: "haptics"
+ name: "normalized_pwle_effects"
+ is_exported: true
+ description: "Enables functionality to create PWLE effects using advanced and simple APIs"
+ bug: "341052318"
+ metadata {
+ purpose: PURPOSE_FEATURE
+ }
+} \ No newline at end of file
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 4c4aa6cc4e68..5174005a8175 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -217,6 +217,13 @@ flag {
}
flag {
+ name: "check_op_validate_package"
+ namespace: "permissions"
+ description: "Validate package/uid match in checkOp similar to noteOp"
+ bug: "294609684"
+}
+
+flag {
name: "location_bypass_privacy_dashboard_enabled"
is_exported: true
namespace: "permissions"
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7ca40ea23d57..184bac4269bb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14953,6 +14953,7 @@ public final class Settings {
*
* @hide
*/
+ @Readable
public static final String MUTE_ALARM_STREAM_WITH_RINGER_MODE =
"mute_alarm_stream_with_ringer_mode";
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 9c281f3d6f90..0242de0b972c 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1363,6 +1363,9 @@ public class DreamService extends Service implements Window.Callback {
* Tells the dream to come to the front (which in turn tells the overlay to come to the front).
*/
private void comeToFront() {
+ if (mOverlayConnection == null) {
+ return;
+ }
mOverlayConnection.addConsumer(overlay -> {
try {
overlay.comeToFront();
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 66d08f99516e..08e51a131198 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -27,6 +27,7 @@ import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.window.flags.Flags.FLAG_OFFLOAD_COLOR_EXTRACTION;
+import static com.android.window.flags.Flags.noDuplicateSurfaceDestroyedEvents;
import static com.android.window.flags.Flags.noConsecutiveVisibilityEvents;
import static com.android.window.flags.Flags.noVisibilityEventOnDisplayStateChange;
import static com.android.window.flags.Flags.offloadColorExtraction;
@@ -255,6 +256,7 @@ public abstract class WallpaperService extends Service {
*/
private boolean mIsScreenTurningOn;
boolean mReportedVisible;
+ boolean mReportedSurfaceCreated;
boolean mDestroyed;
// Set to true after receiving WallpaperManager#COMMAND_FREEZE. It's reset back to false
// after receiving WallpaperManager#COMMAND_UNFREEZE. COMMAND_FREEZE is fully applied once
@@ -1381,6 +1383,7 @@ public abstract class WallpaperService extends Service {
if (surfaceCreating) {
mIsCreating = true;
didSurface = true;
+ mReportedSurfaceCreated = true;
if (DEBUG) Log.v(TAG, "onSurfaceCreated("
+ mSurfaceHolder + "): " + this);
Trace.beginSection("WPMS.Engine.onSurfaceCreated");
@@ -2264,8 +2267,10 @@ public abstract class WallpaperService extends Service {
}
void reportSurfaceDestroyed() {
- if (mSurfaceCreated) {
+ if ((!noDuplicateSurfaceDestroyedEvents() && mSurfaceCreated)
+ || (noDuplicateSurfaceDestroyedEvents() && mReportedSurfaceCreated)) {
mSurfaceCreated = false;
+ mReportedSurfaceCreated = false;
mSurfaceHolder.ungetCallbacks();
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
if (callbacks != null) {
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index ccec89bb6262..8912035c0be3 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -350,12 +350,13 @@ public class HandwritingInitiator {
return;
}
+ final View focusedView = getFocusedView();
+
if (!view.isAutoHandwritingEnabled()) {
- clearFocusedView(view);
+ clearFocusedView(focusedView);
return;
}
- final View focusedView = getFocusedView();
if (focusedView == view) {
return;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3088fd3094b0..e81f32e1e64b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -33989,7 +33989,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|| mLastFrameTop != mTop)
&& viewRootImpl.shouldCheckFrameRateCategory()
&& parent instanceof View
- && ((View) parent).mFrameContentVelocity <= 0
+ && ((View) parent).getFrameContentVelocity() <= 0
&& !isInputMethodWindowType) {
return FRAME_RATE_CATEGORY_HIGH_HINT | FRAME_RATE_CATEGORY_REASON_BOOST;
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 02f7e95ba742..2786c84521c5 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -15,7 +15,10 @@
*/
package android.view;
+import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
+
import android.animation.LayoutTransition;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -365,6 +368,18 @@ public class ViewOverlay {
}
return null;
}
+
+ /**
+ * @hide
+ */
+ @Override
+ @FlaggedApi(FLAG_VIEW_VELOCITY_API)
+ public float getFrameContentVelocity() {
+ if (mHostView != null) {
+ return mHostView.getFrameContentVelocity();
+ }
+ return super.getFrameContentVelocity();
+ }
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e97f603f5db3..0e0262715d2f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -304,6 +304,7 @@ import java.util.OptionalInt;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -1201,8 +1202,7 @@ public final class ViewRootImpl implements ViewParent,
private String mLargestViewTraceName;
private final boolean mAppStartInfoTimestampsFlagValue;
- @GuardedBy("this")
- private boolean mAppStartTimestampsSent = false;
+ private AtomicBoolean mAppStartTimestampsSent = new AtomicBoolean(false);
private boolean mAppStartTrackingStarted = false;
private long mRenderThreadDrawStartTimeNs = -1;
private long mFirstFramePresentedTimeNs = -1;
@@ -2647,7 +2647,7 @@ public final class ViewRootImpl implements ViewParent,
destroySurface();
// Reset so they can be sent again for warm starts.
- mAppStartTimestampsSent = false;
+ mAppStartTimestampsSent.set(false);
mAppStartTrackingStarted = false;
mRenderThreadDrawStartTimeNs = -1;
mFirstFramePresentedTimeNs = -1;
@@ -4503,42 +4503,29 @@ public final class ViewRootImpl implements ViewParent,
}
private void maybeSendAppStartTimes() {
- synchronized (this) {
- if (mAppStartTimestampsSent) {
- // Don't send timestamps more than once.
- return;
- }
-
- // If we already have {@link mRenderThreadDrawStartTimeNs} then pass it through, if not
- // post to main thread and check if we have it there.
- if (mRenderThreadDrawStartTimeNs != -1) {
- sendAppStartTimesLocked();
- } else {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- synchronized (ViewRootImpl.this) {
- if (mRenderThreadDrawStartTimeNs == -1) {
- return;
- }
- sendAppStartTimesLocked();
- }
- }
- });
- }
+ if (mAppStartTimestampsSent.get()) {
+ // Don't send timestamps more than once.
+ return;
}
- }
- @GuardedBy("this")
- private void sendAppStartTimesLocked() {
- try {
- ActivityManager.getService().reportStartInfoViewTimestamps(
- mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs);
- mAppStartTimestampsSent = true;
- } catch (RemoteException e) {
- // Ignore, timestamps may be lost.
- if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e);
- }
+ // Post to main thread
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mRenderThreadDrawStartTimeNs == -1) {
+ return;
+ }
+
+ try {
+ ActivityManager.getService().reportStartInfoViewTimestamps(
+ mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs);
+ mAppStartTimestampsSent.set(true);
+ } catch (RemoteException e) {
+ // Ignore, timestamps may be lost.
+ if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e);
+ }
+ }
+ });
}
/**
@@ -13025,7 +13012,7 @@ public final class ViewRootImpl implements ViewParent,
private boolean shouldSetFrameRateCategory() {
// use toolkitSetFrameRate flag to gate the change
- return shouldEnableDvrr() && mSurface.isValid() && shouldEnableDvrr();
+ return shouldEnableDvrr() && mSurface.isValid();
}
private boolean shouldSetFrameRate() {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index d28c953fe0bd..03a26722da8f 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -474,7 +474,11 @@ public class Editor {
private final AccessibilitySmartActions mA11ySmartActions;
private InsertModeController mInsertModeController;
- Editor(TextView textView) {
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public Editor(TextView textView) {
mTextView = textView;
// Synchronize the filter list, which places the undo input filter at the end.
mTextView.setFilters(mTextView.getFilters());
@@ -3206,16 +3210,6 @@ public class Editor {
}
}
- final int menuItemOrderUndo = 2;
- final int menuItemOrderRedo = 3;
- final int menuItemOrderCut = 4;
- final int menuItemOrderCopy = 5;
- final int menuItemOrderPaste = 6;
- final int menuItemOrderPasteAsPlainText = 7;
- final int menuItemOrderSelectAll = 8;
- final int menuItemOrderShare = 9;
- final int menuItemOrderAutofill = 10;
-
menu.setOptionalIconsVisible(true);
menu.setGroupDividerEnabled(true);
@@ -3224,7 +3218,18 @@ public class Editor {
final int keyboard = mTextView.getResources().getConfiguration().keyboard;
menu.setQwertyMode(keyboard == Configuration.KEYBOARD_QWERTY);
- final TypedArray a = mTextView.getContext().obtainStyledAttributes(new int[] {
+ setTextContextMenuItems(menu);
+
+ mPreserveSelection = true;
+
+ // No-op for the old context menu because it doesn't have icons.
+ adjustIconSpacing(menu);
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public void setTextContextMenuItems(ContextMenu menu) {
+ final TypedArray a = mTextView.getContext().obtainStyledAttributes(new int[]{
// TODO: Make Undo/Redo be public attribute.
com.android.internal.R.attr.actionModeUndoDrawable,
com.android.internal.R.attr.actionModeRedoDrawable,
@@ -3235,6 +3240,16 @@ public class Editor {
android.R.attr.actionModeShareDrawable,
});
+ final int menuItemOrderUndo = 2;
+ final int menuItemOrderRedo = 3;
+ final int menuItemOrderCut = 4;
+ final int menuItemOrderCopy = 5;
+ final int menuItemOrderPaste = 6;
+ final int menuItemOrderPasteAsPlainText = 7;
+ final int menuItemOrderSelectAll = 8;
+ final int menuItemOrderShare = 9;
+ final int menuItemOrderAutofill = 10;
+
menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo,
com.android.internal.R.string.undo)
.setAlphabeticShortcut('z')
@@ -3291,12 +3306,7 @@ public class Editor {
.setEnabled(mTextView.canRequestAutofill()
&& (selected == null || selected.isEmpty()))
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
-
- mPreserveSelection = true;
a.recycle();
-
- // No-op for the old context menu because it doesn't have icons.
- adjustIconSpacing(menu);
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 61ecc6264ffa..72b268b440b5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12255,7 +12255,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return selectionMin >= 0 && selectionMax > 0 && selectionMin != selectionMax;
}
- String getSelectedText() {
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public String getSelectedText() {
if (!hasSelection()) {
return null;
}
@@ -14080,7 +14084,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
structure.setInputType(getInputType());
}
- boolean canRequestAutofill() {
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public boolean canRequestAutofill() {
if (!isAutofillable()) {
return false;
}
diff --git a/core/java/android/window/flags/wallpaper_manager.aconfig b/core/java/android/window/flags/wallpaper_manager.aconfig
index 01c78a0bfb1d..8c6721a7e96a 100644
--- a/core/java/android/window/flags/wallpaper_manager.aconfig
+++ b/core/java/android/window/flags/wallpaper_manager.aconfig
@@ -39,3 +39,13 @@ flag {
description: "Prevent the system from sending visibility event on display state change."
bug: "331725519"
}
+
+flag {
+ name: "no_duplicate_surface_destroyed_events"
+ namespace: "systemui"
+ description: "Prevent the system from sending onSurfaceDestroyed() twice."
+ bug: "344461715"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index ec004d07c781..0d0207ff7c0e 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -418,6 +418,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mElevation = preservedWindow.getElevation();
mLoadElevation = false;
mForceDecorInstall = true;
+ mDecorFitsSystemWindows = preservedWindow.decorFitsSystemWindows();
setSystemBarAppearance(preservedWindow.getSystemBarAppearance());
// If we're preserving window, carry over the app token from the preserved
// window, as we'll be skipping the addView in handleResumeActivity(), and
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index cbcbf2db6c51..79a5469956df 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -401,7 +401,9 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto
Log.e(LOG_TAG, "Failed to wait for tracing to finish", e);
}
- dumpViewerConfig();
+ if (!android.tracing.Flags.clientSideProtoLogging()) {
+ dumpViewerConfig();
+ }
Log.d(LOG_TAG, "Finished onTracingFlush");
}
@@ -497,7 +499,8 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto
os.write(GROUP_ID, pis.readInt(GROUP_ID));
break;
case (int) LOCATION:
- os.write(LOCATION, pis.readInt(LOCATION));
+ os.write(LOCATION, pis.readString(LOCATION));
+ break;
default:
throw new RuntimeException(
"Unexpected field id " + pis.getFieldNumber());
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 84ca1ba6ad7c..7a4670f4e49d 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -53,7 +53,7 @@ selabel_handle* GetSELabelHandle() {
}
struct SecurityContext_Delete {
- void operator()(security_context_t p) const {
+ void operator()(char* p) const {
freecon(p);
}
};
@@ -111,7 +111,7 @@ static jstring fileSelabelLookup(JNIEnv* env, jobject, jstring pathStr) {
return NULL;
}
- security_context_t tmp = NULL;
+ char* tmp = NULL;
if (selabel_lookup(selabel_handle, &tmp, path_c_str, S_IFREG) != 0) {
ALOGE("fileSelabelLookup => selabel_lookup for %s failed: %d", path_c_str, errno);
return NULL;
@@ -138,7 +138,7 @@ static jstring getFdConInner(JNIEnv *env, jobject fileDescriptor, bool isSocket)
return NULL;
}
- security_context_t tmp = NULL;
+ char* tmp = NULL;
int ret;
if (isSocket) {
ret = getpeercon(fd, &tmp);
@@ -184,7 +184,7 @@ static jstring getFdCon(JNIEnv *env, jobject, jobject fileDescriptor) {
* Function: setFSCreateCon
* Purpose: set security context used for creating a new file system object
* Parameters:
- * context: security_context_t representing the new context of a file system object,
+ * context: char* representing the new context of a file system object,
* set to NULL to return to the default policy behavior
* Returns: true on success, false on error
* Exception: none
@@ -267,7 +267,7 @@ static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
return NULL;
}
- security_context_t tmp = NULL;
+ char* tmp = NULL;
int ret = getfilecon(path.c_str(), &tmp);
Unique_SecurityContext context(tmp);
@@ -293,7 +293,7 @@ static jstring getCon(JNIEnv *env, jobject) {
return NULL;
}
- security_context_t tmp = NULL;
+ char* tmp = NULL;
int ret = getcon(&tmp);
Unique_SecurityContext context(tmp);
@@ -320,7 +320,7 @@ static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
return NULL;
}
- security_context_t tmp = NULL;
+ char* tmp = NULL;
int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
Unique_SecurityContext context(tmp);
diff --git a/core/res/Android.bp b/core/res/Android.bp
index e900eb2f01ab..c1edb1542ea1 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -156,6 +156,7 @@ android_app {
generate_product_characteristics_rro: true,
flags_packages: [
+ "android.app.appfunctions.flags-aconfig",
"android.app.contextualsearch.flags-aconfig",
"android.content.pm.flags-aconfig",
"android.provider.flags-aconfig",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 117041ab353e..55c66e2329e4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -8010,6 +8010,41 @@
<permission android:name="android.permission.EXECUTE_APP_ACTION"
android:protectionLevel="internal|role" />
+ <!-- Must be required by an {@link android.app.appfunctions.AppFunctionService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") -->
+ <permission android:name="android.permission.BIND_APP_FUNCTION_SERVICE"
+ android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows a trusted application to perform actions on behalf of users inside of
+ applications with privacy guarantees from the system.
+ <p>This permission is currently only granted to system packages in the
+ {@link android.app.role.SYSTEM_UI_INTELLIGENCE} role which complies with privacy
+ requirements outlined in the Android CDD section "9.8.6 Content Capture".
+ <p>Apps are not able to opt-out from caller having this permission.
+ <p>Protection level: internal|role
+ @hide
+ @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") -->
+ <permission android:name="android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED"
+ android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager"
+ android:protectionLevel="internal|role" />
+
+ <!-- @SystemApi Allows an application to perform actions on behalf of users inside of
+ applications.
+ <p>This permission is currently only granted to preinstalled / system apps having the
+ {@link android.app.role.ASSISTANT} role.
+ <p>Apps contributing app functions can opt to disallow callers with this permission,
+ limiting to only callers with {@link android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED}
+ instead.
+ <p>Protection level: internal|role
+ @hide
+ @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") -->
+ <permission android:name="android.permission.EXECUTE_APP_FUNCTIONS"
+ android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager"
+ android:protectionLevel="internal|role" />
+
<!-- Allows an application to display its suggestions using the autofill framework.
<p>For now, this permission is only granted to the Browser application.
<p>Protection level: internal|role
diff --git a/core/res/res/drawable/ic_zen_mode_icon_lotus_flower.xml b/core/res/res/drawable/ic_zen_mode_icon_lotus_flower.xml
new file mode 100644
index 000000000000..c1afd44ecfc4
--- /dev/null
+++ b/core/res/res/drawable/ic_zen_mode_icon_lotus_flower.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2024 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:tint="?android:attr/colorControlNormal"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M480,880Q407,871 335,840.5Q263,810 206.5,753Q150,696 115,609Q80,522 80,400L80,360L120,360Q171,360 225,373Q279,386 326,412Q338,326 380.5,235.5Q423,145 480,80Q537,145 579.5,235.5Q622,326 634,412Q681,386 735,373Q789,360 840,360L880,360L880,400Q880,522 845,609Q810,696 753.5,753Q697,810 625.5,840.5Q554,871 480,880ZM478,798Q467,632 379.5,547Q292,462 162,442Q173,613 263.5,697Q354,781 478,798ZM480,544Q495,522 516.5,498.5Q538,475 558,458Q556,401 535.5,339Q515,277 480,218Q445,277 424.5,339Q404,401 402,458Q422,475 444,498.5Q466,522 480,544ZM558,780Q595,768 635,745Q675,722 709.5,682.5Q744,643 768.5,584Q793,525 798,442Q704,456 633,504.5Q562,553 524,628Q536,660 544.5,698Q553,736 558,780ZM480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544ZM558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780ZM478,798Q478,798 478,798Q478,798 478,798Q478,798 478,798Q478,798 478,798ZM524,628L524,628Q524,628 524,628Q524,628 524,628L524,628L524,628L524,628Q524,628 524,628Q524,628 524,628L524,628Q524,628 524,628Q524,628 524,628ZM480,880L480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880L480,880Q480,880 480,880Q480,880 480,880L480,880Q480,880 480,880Q480,880 480,880L480,880Z" />
+</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_zen_mode_icon_rabbit.xml b/core/res/res/drawable/ic_zen_mode_icon_rabbit.xml
deleted file mode 100644
index 190d0cb319ec..000000000000
--- a/core/res/res/drawable/ic_zen_mode_icon_rabbit.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2024 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:tint="?android:attr/colorControlNormal"
- android:viewportHeight="960"
- android:viewportWidth="960">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M380,880Q305,880 252.5,827.5Q200,775 200,700Q200,665 217,635.5Q234,606 280,560Q286,554 291.5,547.5Q297,541 306,530Q255,452 227.5,366.5Q200,281 200,200Q200,142 221,111Q242,80 280,80Q337,80 382,135Q427,190 450,236Q459,256 466.5,276.5Q474,297 480,319Q486,297 493.5,276.5Q501,256 511,236Q533,190 578,135Q623,80 680,80Q718,80 739,111Q760,142 760,200Q760,281 732.5,366.5Q705,452 654,530Q663,541 668.5,547.5Q674,554 680,560Q726,606 743,635.5Q760,665 760,700Q760,775 707.5,827.5Q655,880 580,880Q535,880 507.5,870Q480,860 480,860Q480,860 452.5,870Q425,880 380,880ZM380,800Q403,800 426,794.5Q449,789 469,778Q458,773 449,761Q440,749 440,740Q440,732 451.5,726Q463,720 480,720Q497,720 508.5,726Q520,732 520,740Q520,749 511,761Q502,773 491,778Q511,789 534,794.5Q557,800 580,800Q622,800 651,771Q680,742 680,700Q680,682 670,665Q660,648 640,631Q626,619 617,610Q608,601 588,576Q559,541 540,530.5Q521,520 480,520Q439,520 419.5,530.5Q400,541 372,576Q352,601 343,610Q334,619 320,631Q300,648 290,665Q280,682 280,700Q280,742 309,771Q338,800 380,800ZM420,670Q412,670 406,661Q400,652 400,640Q400,628 406,619Q412,610 420,610Q428,610 434,619Q440,628 440,640Q440,652 434,661Q428,670 420,670ZM540,670Q532,670 526,661Q520,652 520,640Q520,628 526,619Q532,610 540,610Q548,610 554,619Q560,628 560,640Q560,652 554,661Q548,670 540,670ZM363,471Q374,463 388,457Q402,451 419,446Q417,398 404.5,350.5Q392,303 373,264Q354,224 331,196.5Q308,169 285,161Q283,167 281.5,176.5Q280,186 280,200Q280,268 301.5,338Q323,408 363,471ZM597,471Q637,408 658.5,338Q680,268 680,200Q680,186 678.5,176.5Q677,167 675,161Q652,169 629,196.5Q606,224 587,264Q569,303 556.5,350.5Q544,398 541,446Q556,450 570,456.5Q584,463 597,471Z" />
-</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_zen_mode_type_unknown.xml b/core/res/res/drawable/ic_zen_mode_type_unknown.xml
index c1afd44ecfc4..04df5f91fd68 100644
--- a/core/res/res/drawable/ic_zen_mode_type_unknown.xml
+++ b/core/res/res/drawable/ic_zen_mode_type_unknown.xml
@@ -21,5 +21,5 @@ Copyright (C) 2024 The Android Open Source Project
android:viewportWidth="960">
<path
android:fillColor="@android:color/white"
- android:pathData="M480,880Q407,871 335,840.5Q263,810 206.5,753Q150,696 115,609Q80,522 80,400L80,360L120,360Q171,360 225,373Q279,386 326,412Q338,326 380.5,235.5Q423,145 480,80Q537,145 579.5,235.5Q622,326 634,412Q681,386 735,373Q789,360 840,360L880,360L880,400Q880,522 845,609Q810,696 753.5,753Q697,810 625.5,840.5Q554,871 480,880ZM478,798Q467,632 379.5,547Q292,462 162,442Q173,613 263.5,697Q354,781 478,798ZM480,544Q495,522 516.5,498.5Q538,475 558,458Q556,401 535.5,339Q515,277 480,218Q445,277 424.5,339Q404,401 402,458Q422,475 444,498.5Q466,522 480,544ZM558,780Q595,768 635,745Q675,722 709.5,682.5Q744,643 768.5,584Q793,525 798,442Q704,456 633,504.5Q562,553 524,628Q536,660 544.5,698Q553,736 558,780ZM480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544Q480,544 480,544ZM558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780Q558,780 558,780ZM478,798Q478,798 478,798Q478,798 478,798Q478,798 478,798Q478,798 478,798ZM524,628L524,628Q524,628 524,628Q524,628 524,628L524,628L524,628L524,628Q524,628 524,628Q524,628 524,628L524,628Q524,628 524,628Q524,628 524,628ZM480,880L480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880Q480,880 480,880L480,880Q480,880 480,880Q480,880 480,880L480,880Q480,880 480,880Q480,880 480,880L480,880Z" />
+ android:pathData="M368,640L480,556L590,640L548,504L660,416L524,416L480,280L436,416L300,416L410,504L368,640ZM160,800Q127,800 103.5,776.5Q80,753 80,720L80,585Q80,574 87,566Q94,558 105,556Q129,548 144.5,527Q160,506 160,480Q160,454 144.5,433Q129,412 105,404Q94,402 87,394Q80,386 80,375L80,240Q80,207 103.5,183.5Q127,160 160,160L800,160Q833,160 856.5,183.5Q880,207 880,240L880,375Q880,386 873,394Q866,402 855,404Q831,412 815.5,433Q800,454 800,480Q800,506 815.5,527Q831,548 855,556Q866,558 873,566Q880,574 880,585L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM160,720L800,720Q800,720 800,720Q800,720 800,720L800,618Q763,596 741.5,559.5Q720,523 720,480Q720,437 741.5,400.5Q763,364 800,342L800,240Q800,240 800,240Q800,240 800,240L160,240Q160,240 160,240Q160,240 160,240L160,342Q197,364 218.5,400.5Q240,437 240,480Q240,523 218.5,559.5Q197,596 160,618L160,720Q160,720 160,720Q160,720 160,720ZM480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Z" />
</vector> \ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
index b8ff59528b24..c631c6f46e37 100644
--- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java
+++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
@@ -994,6 +994,35 @@ public class ViewFrameRateTest {
mViewRoot.getLastPreferredFrameRateCategory());
}
+ /**
+ * If a View is an instance of ViewGroupOverlay,
+ * we obtain the velocity from its hostView.
+ */
+ @Test
+ @RequiresFlagsEnabled(FLAG_VIEW_VELOCITY_API)
+ public void overlayViewGroupVelocity() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
+
+ FrameLayout host = new FrameLayout(mActivity);
+ View childView = new View(mActivity);
+ float velocity = 1000;
+
+ mActivityRule.runOnUiThread(() -> {
+ ViewGroup.LayoutParams fullSize = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mActivity.setContentView(host, fullSize);
+ host.setFrameContentVelocity(velocity);
+ ViewGroupOverlay overlay = host.getOverlay();
+ overlay.add(childView);
+ assertEquals(velocity, host.getFrameContentVelocity());
+ assertEquals(host.getFrameContentVelocity(),
+ ((View) childView.getParent()).getFrameContentVelocity());
+ });
+ }
+
private void runAfterDraw(@NonNull Runnable runnable) {
Handler handler = new Handler(Looper.getMainLooper());
mAfterDrawLatch = new CountDownLatch(1);
diff --git a/core/tests/coretests/src/android/widget/TextViewContextMenuTest.java b/core/tests/coretests/src/android/widget/TextViewContextMenuTest.java
index f9da832ba7de..b11307e0393d 100644
--- a/core/tests/coretests/src/android/widget/TextViewContextMenuTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewContextMenuTest.java
@@ -23,7 +23,9 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyChar;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
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 static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -251,8 +253,9 @@ public class TextViewContextMenuTest {
when(menu.add(anyInt(), eq(TextView.ID_AUTOFILL), anyInt(), anyInt()))
.thenReturn(mockAutofillMenuItem);
- EditText et = mActivity.findViewById(R.id.editText);
- et.setText("Test");
+ EditText et = spy(mActivity.findViewById(R.id.editText));
+ doReturn(true).when(et).canRequestAutofill();
+ doReturn(null).when(et).getSelectedText();
Editor editor = et.getEditorForTesting();
editor.onCreateContextMenu(menu);
@@ -271,11 +274,11 @@ public class TextViewContextMenuTest {
when(menu.add(anyInt(), eq(TextView.ID_AUTOFILL), anyInt(), anyInt()))
.thenReturn(mockAutofillMenuItem);
- EditText et = mActivity.findViewById(R.id.editText);
- et.setText("Test");
- et.selectAll();
- Editor editor = et.getEditorForTesting();
- editor.onCreateContextMenu(menu);
+ EditText et = spy(mActivity.findViewById(R.id.editText));
+ doReturn(true).when(et).canRequestAutofill();
+ doReturn("test").when(et).getSelectedText();
+ Editor editor = new Editor(et);
+ editor.setTextContextMenuItems(menu);
verify(menu).add(anyInt(), eq(TextView.ID_AUTOFILL), anyInt(), anyInt());
verify(mockAutofillMenuItem).setEnabled(false);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarImpl.java
index 60bc7bedf2ed..a1de2062e906 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -16,6 +16,7 @@
package androidx.window.sidecar;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.Application;
@@ -23,8 +24,9 @@ import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
import android.os.IBinder;
+import android.util.ArraySet;
+import android.util.Log;
-import androidx.annotation.NonNull;
import androidx.window.common.BaseDataProducer;
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
@@ -33,17 +35,27 @@ import androidx.window.common.layout.CommonFoldingFeature;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
/**
- * Reference implementation of androidx.window.sidecar OEM interface for use with
- * WindowManager Jetpack.
+ * Basic implementation of the {@link SidecarInterface}. An OEM can choose to use it as the base
+ * class for their implementation.
*/
-class SampleSidecarImpl extends StubSidecar {
+class SidecarImpl implements SidecarInterface {
+
+ private static final String TAG = "WindowManagerSidecar";
+
+ @Nullable
+ private SidecarCallback mSidecarCallback;
+ private final ArraySet<IBinder> mWindowLayoutChangeListenerTokens = new ArraySet<>();
+ private boolean mDeviceStateChangeListenerRegistered;
+ @NonNull
private List<CommonFoldingFeature> mStoredFeatures = new ArrayList<>();
- SampleSidecarImpl(Context context) {
+ SidecarImpl(Context context) {
((Application) context.getApplicationContext())
- .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
+ .registerActivityLifecycleCallbacks(new SidecarImpl.NotifyOnConfigurationChanged());
RawFoldingFeatureProducer settingsFeatureProducer = new RawFoldingFeatureProducer(context);
BaseDataProducer<List<CommonFoldingFeature>> foldingFeatureProducer =
new DeviceStateManagerFoldingFeatureProducer(context,
@@ -53,11 +65,46 @@ class SampleSidecarImpl extends StubSidecar {
foldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
}
- private void setStoredFeatures(List<CommonFoldingFeature> storedFeatures) {
- mStoredFeatures = storedFeatures;
+ @NonNull
+ @Override
+ public SidecarDeviceState getDeviceState() {
+ return SidecarHelper.calculateDeviceState(mStoredFeatures);
+ }
+
+ @NonNull
+ @Override
+ public SidecarWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
+ return SidecarHelper.calculateWindowLayoutInfo(windowToken, mStoredFeatures);
+ }
+
+ @Override
+ public void setSidecarCallback(@NonNull SidecarCallback sidecarCallback) {
+ mSidecarCallback = sidecarCallback;
+ }
+
+ @Override
+ public void onWindowLayoutChangeListenerAdded(@NonNull IBinder iBinder) {
+ mWindowLayoutChangeListenerTokens.add(iBinder);
+ onListenersChanged();
+ }
+
+ @Override
+ public void onWindowLayoutChangeListenerRemoved(@NonNull IBinder iBinder) {
+ mWindowLayoutChangeListenerTokens.remove(iBinder);
+ onListenersChanged();
+ }
+
+ @Override
+ public void onDeviceStateListenersChanged(boolean isEmpty) {
+ mDeviceStateChangeListenerRegistered = !isEmpty;
+ onListenersChanged();
+ }
+
+ private void setStoredFeatures(@NonNull List<CommonFoldingFeature> storedFeatures) {
+ mStoredFeatures = Objects.requireNonNull(storedFeatures);
}
- private void onDisplayFeaturesChanged(List<CommonFoldingFeature> storedFeatures) {
+ private void onDisplayFeaturesChanged(@NonNull List<CommonFoldingFeature> storedFeatures) {
setStoredFeatures(storedFeatures);
updateDeviceState(getDeviceState());
for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
@@ -66,25 +113,43 @@ class SampleSidecarImpl extends StubSidecar {
}
}
- @NonNull
- @Override
- public SidecarDeviceState getDeviceState() {
- return SidecarHelper.calculateDeviceState(mStoredFeatures);
+ void updateDeviceState(@NonNull SidecarDeviceState newState) {
+ if (mSidecarCallback != null) {
+ try {
+ mSidecarCallback.onDeviceStateChanged(newState);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, "App is using an outdated Window Jetpack library", e);
+ }
+ }
+ }
+
+ void updateWindowLayout(@NonNull IBinder windowToken,
+ @NonNull SidecarWindowLayoutInfo newLayout) {
+ if (mSidecarCallback != null) {
+ try {
+ mSidecarCallback.onWindowLayoutChanged(windowToken, newLayout);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, "App is using an outdated Window Jetpack library", e);
+ }
+ }
}
@NonNull
- @Override
- public SidecarWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
- return SidecarHelper.calculateWindowLayoutInfo(windowToken, mStoredFeatures);
+ private Set<IBinder> getWindowsListeningForLayoutChanges() {
+ return mWindowLayoutChangeListenerTokens;
}
- @Override
- protected void onListenersChanged() {
+ protected boolean hasListeners() {
+ return !mWindowLayoutChangeListenerTokens.isEmpty() || mDeviceStateChangeListenerRegistered;
+ }
+
+ private void onListenersChanged() {
if (hasListeners()) {
onDisplayFeaturesChanged(mStoredFeatures);
}
}
+
private final class NotifyOnConfigurationChanged extends EmptyLifecycleCallbacksAdapter {
@Override
public void onActivityCreated(@NonNull Activity activity,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java
index 686a31b6be04..1e306fcebda0 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java
@@ -36,7 +36,7 @@ public class SidecarProvider {
@Nullable
public static SidecarInterface getSidecarImpl(Context context) {
return isWindowExtensionsEnabled()
- ? new SampleSidecarImpl(context.getApplicationContext())
+ ? new SidecarImpl(context.getApplicationContext())
: null;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java
deleted file mode 100644
index 46c1f3ba4691..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.sidecar;
-
-import android.os.IBinder;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Basic implementation of the {@link SidecarInterface}. An OEM can choose to use it as the base
- * class for their implementation.
- */
-abstract class StubSidecar implements SidecarInterface {
-
- private static final String TAG = "WindowManagerSidecar";
-
- private SidecarCallback mSidecarCallback;
- final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>();
- private boolean mDeviceStateChangeListenerRegistered;
-
- StubSidecar() {
- }
-
- @Override
- public void setSidecarCallback(@NonNull SidecarCallback sidecarCallback) {
- this.mSidecarCallback = sidecarCallback;
- }
-
- @Override
- public void onWindowLayoutChangeListenerAdded(@NonNull IBinder iBinder) {
- this.mWindowLayoutChangeListenerTokens.add(iBinder);
- this.onListenersChanged();
- }
-
- @Override
- public void onWindowLayoutChangeListenerRemoved(@NonNull IBinder iBinder) {
- this.mWindowLayoutChangeListenerTokens.remove(iBinder);
- this.onListenersChanged();
- }
-
- @Override
- public void onDeviceStateListenersChanged(boolean isEmpty) {
- this.mDeviceStateChangeListenerRegistered = !isEmpty;
- this.onListenersChanged();
- }
-
- void updateDeviceState(SidecarDeviceState newState) {
- if (this.mSidecarCallback != null) {
- try {
- mSidecarCallback.onDeviceStateChanged(newState);
- } catch (AbstractMethodError e) {
- Log.e(TAG, "App is using an outdated Window Jetpack library", e);
- }
- }
- }
-
- void updateWindowLayout(@NonNull IBinder windowToken,
- @NonNull SidecarWindowLayoutInfo newLayout) {
- if (this.mSidecarCallback != null) {
- try {
- mSidecarCallback.onWindowLayoutChanged(windowToken, newLayout);
- } catch (AbstractMethodError e) {
- Log.e(TAG, "App is using an outdated Window Jetpack library", e);
- }
- }
- }
-
- @NonNull
- Set<IBinder> getWindowsListeningForLayoutChanges() {
- return mWindowLayoutChangeListenerTokens;
- }
-
- protected boolean hasListeners() {
- return !mWindowLayoutChangeListenerTokens.isEmpty() || mDeviceStateChangeListenerRegistered;
- }
-
- protected abstract void onListenersChanged();
-}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 1c3d9c30c91c..1a3aa8eec5ec 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -44,18 +44,10 @@ filegroup {
filegroup {
name: "wm_shell_util-sources",
srcs: [
- "src/com/android/wm/shell/animation/Interpolators.java",
"src/com/android/wm/shell/common/bubbles/*.kt",
"src/com/android/wm/shell/common/bubbles/*.java",
- "src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt",
- "src/com/android/wm/shell/common/split/SplitScreenConstants.java",
- "src/com/android/wm/shell/common/TransactionPool.java",
- "src/com/android/wm/shell/common/TriangleShape.java",
"src/com/android/wm/shell/common/desktopmode/*.kt",
- "src/com/android/wm/shell/draganddrop/DragAndDropConstants.java",
"src/com/android/wm/shell/pip/PipContentOverlay.java",
- "src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java",
- "src/com/android/wm/shell/sysui/ShellSharedConstants.java",
"src/com/android/wm/shell/util/**/*.java",
],
path: "src",
diff --git a/libs/WindowManager/Shell/res/layout/compat_ui_restart_button_layout.xml b/libs/WindowManager/Shell/res/layout/compat_ui_restart_button_layout.xml
new file mode 100644
index 000000000000..d00c69cb2993
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/compat_ui_restart_button_layout.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 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="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="bottom|end">
+
+ <include android:id="@+id/size_compat_hint"
+ android:visibility="gone"
+ android:layout_width="@dimen/compat_hint_width"
+ android:layout_height="wrap_content"
+ layout="@layout/compat_mode_hint"/>
+
+ <ImageButton
+ android:id="@+id/size_compat_restart_button"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/compat_button_margin"
+ android:layout_marginBottom="@dimen/compat_button_margin"
+ android:src="@drawable/size_compat_restart_button_ripple"
+ android:background="@android:color/transparent"
+ android:contentDescription="@string/restart_button_description"/>
+
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 6a62d7a373c8..36d0a3c63b03 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -302,4 +302,6 @@
<string name="desktop_mode_maximize_menu_maximize_text">Maximize Screen</string>
<!-- Maximize menu snap buttons string. -->
<string name="desktop_mode_maximize_menu_snap_text">Snap Screen</string>
+ <!-- Snap resizing non-resizable string. -->
+ <string name="desktop_mode_non_resizable_snap_text">This app can\'t be resized</string>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/ShellSharedConstants.java
index c886cc999216..8f7a2e5a6789 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/ShellSharedConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.sysui;
+package com.android.wm.shell.shared;
/**
* General shell-related constants that are shared with users of the library.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TransactionPool.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransactionPool.java
index 4c34566b0d98..0c5d88dc44a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TransactionPool.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransactionPool.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.common;
+package com.android.wm.shell.shared;
import android.util.Pools;
import android.view.SurfaceControl;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TriangleShape.java
index 707919033065..0ca53278acbb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TriangleShape.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.common;
+package com.android.wm.shell.shared;
import android.graphics.Outline;
import android.graphics.Path;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java
index ce0bf8b29374..f45dc3a1e892 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.animation;
+package com.android.wm.shell.shared.animation;
import android.graphics.Path;
import android.view.animation.BackGestureInterpolator;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropConstants.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/draganddrop/DragAndDropConstants.java
index 20da54efd286..4127adc1f901 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropConstants.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/draganddrop/DragAndDropConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.draganddrop;
+package com.android.wm.shell.shared.draganddrop;
/** Constants that can be used by both Shell and other users of the library, e.g. Launcher */
public class DragAndDropConstants {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/magnetictarget/MagnetizedObject.kt
index 123d4dc49199..efdc6f8cd9de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/magnetictarget/MagnetizedObject.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.wm.shell.common.magnetictarget
+
+package com.android.wm.shell.shared.magnetictarget
import android.annotation.SuppressLint
import android.content.Context
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
index 8c06de79ba76..498dc8bdd24d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.wm.shell.common.split;
+package com.android.wm.shell.shared.split;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -30,7 +30,7 @@ public class SplitScreenConstants {
/** Duration used for every split fade-in or fade-out. */
public static final int FADE_DURATION = 133;
/** Duration where we keep an app veiled to allow it to redraw itself behind the scenes. */
- public static final int VEIL_DELAY_DURATION = 400;
+ public static final int VEIL_DELAY_DURATION = 300;
/** Key for passing in widget intents when invoking split from launcher workspace. */
public static final String KEY_EXTRA_WIDGET_INTENT = "key_extra_widget_intent";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/startingsurface/SplashScreenExitAnimationUtils.java
index ea8c0eb30061..da9bf7a2cba0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/startingsurface/SplashScreenExitAnimationUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.wm.shell.startingsurface;
+package com.android.wm.shell.shared.startingsurface;
import static android.view.Choreographer.CALLBACK_COMMIT;
@@ -45,8 +45,8 @@ import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.window.SplashScreenView;
-import com.android.wm.shell.animation.Interpolators;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
+import com.android.wm.shell.shared.animation.Interpolators;
/**
* Utilities for creating the splash screen window animations.
@@ -88,7 +88,7 @@ public class SplashScreenExitAnimationUtils {
* Creates and starts the animator to fade out the icon, reveal the app, and shift up main
* window with rounded corner radius.
*/
- static void startAnimations(@ExitAnimationType int animationType,
+ public static void startAnimations(@ExitAnimationType int animationType,
ViewGroup splashScreenView, SurfaceControl firstWindowSurface,
int mainWindowShiftLength, TransactionPool transactionPool, Rect firstWindowFrame,
int animationDuration, int iconFadeOutDuration, float iconStartAlpha,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
index 26edd7d2268b..be1f71e939be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
@@ -23,6 +23,8 @@ import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.wm.shell.shared.animation.Interpolators;
+
import javax.inject.Inject;
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index dc2c15365a4d..d7da0515f228 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -29,7 +29,7 @@ import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BA
import static com.android.window.flags.Flags.migratePredictiveBackTransition;
import static com.android.window.flags.Flags.predictiveBackSystemAnims;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index c7e8df980a8b..4fd8b8a5f1b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -51,8 +51,8 @@ import com.android.internal.policy.SystemBarUtils
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
-import com.android.wm.shell.animation.Interpolators
import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.shared.animation.Interpolators
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index e2b0513c951f..3fccecab4319 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -51,7 +51,7 @@ import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.SystemBarUtils;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.shared.animation.Interpolators;
import javax.inject.Inject;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
index c747e1e98956..66d8a5f2eeb9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
@@ -20,7 +20,7 @@ import android.view.SurfaceControl
import android.window.BackEvent
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
-import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.animation.Interpolators
import javax.inject.Inject
import kotlin.math.max
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index dc511be59764..c1dadada505a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
@@ -37,7 +37,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.shared.animation.Interpolators;
import java.util.EnumSet;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index cfe3cfad123f..dabfeebf5cce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -35,7 +35,7 @@ import static com.android.wm.shell.bubbles.Bubbles.DISMISS_PACKAGE_REMOVED;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_SHORTCUT_REMOVED;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_CHANGED;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
import android.annotation.BinderThread;
import android.annotation.NonNull;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index c9fcd5886787..52955267a501 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -71,7 +71,7 @@ import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.common.AlphaOptimizedButton;
-import com.android.wm.shell.common.TriangleShape;
+import com.android.wm.shell.shared.TriangleShape;
import com.android.wm.shell.taskview.TaskView;
import java.io.PrintWriter;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
index 42de401d9db9..1711dca4a8a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
@@ -19,8 +19,8 @@ package com.android.wm.shell.bubbles;
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
-import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
+import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_IN;
+import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_OUT;
import android.animation.ArgbEvaluator;
import android.content.Context;
@@ -50,7 +50,7 @@ import android.widget.TextView;
import androidx.annotation.Nullable;
import com.android.wm.shell.R;
-import com.android.wm.shell.common.TriangleShape;
+import com.android.wm.shell.shared.TriangleShape;
/**
* Flyout view that appears as a 'chat bubble' alongside the bubble stack. The flyout can visually
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 322b01e3e033..53bbf888df5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -19,8 +19,6 @@ package com.android.wm.shell.bubbles;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
-import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
@@ -28,6 +26,8 @@ import static com.android.wm.shell.bubbles.BubblePositioner.StackPinnedEdge.LEFT
import static com.android.wm.shell.bubbles.BubblePositioner.StackPinnedEdge.RIGHT;
import static com.android.wm.shell.common.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
+import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_IN;
+import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_OUT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -82,7 +82,6 @@ import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
import com.android.wm.shell.bubbles.animation.ExpandedAnimationController;
@@ -94,8 +93,9 @@ import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.bubbles.DismissView;
import com.android.wm.shell.common.bubbles.RelativeTouchListener;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import java.io.PrintWriter;
import java.math.BigDecimal;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
index da71b1c741bb..39a2a7b868a0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
@@ -27,7 +27,7 @@ import android.widget.Button
import android.widget.LinearLayout
import com.android.internal.R.color.system_neutral1_900
import com.android.wm.shell.R
-import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.animation.Interpolators
/**
* User education view to highlight the manage button that allows a user to configure the settings
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
index c4108c4129e9..16606198b240 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
@@ -26,7 +26,7 @@ import android.widget.LinearLayout
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
import com.android.wm.shell.R
-import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.animation.Interpolators
/**
* User education view to highlight the collapsed stack of bubbles. Shown only the first time a user
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index f925eaef2c77..8f0dfb9e2215 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -33,13 +33,13 @@ import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.bubbles.BadgedImageView;
import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleStackView;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import com.google.android.collect.Sets;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
index fbef6b5e4a99..7cb537a24ce2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
@@ -40,9 +40,9 @@ import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.animation.FlingAnimationUtils;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.bubbles.BubbleExpandedView;
import com.android.wm.shell.bubbles.BubblePositioner;
+import com.android.wm.shell.shared.animation.Interpolators;
import java.util.ArrayList;
import java.util.List;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 47d4d07500d5..91585dc425eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -42,8 +42,8 @@ import com.android.wm.shell.bubbles.BadgedImageView;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.common.FloatingContentCoordinator;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import com.google.android.collect.Sets;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 8e58db198b13..565fde0a853c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -24,9 +24,9 @@ import static android.view.View.VISIBLE;
import static android.view.View.X;
import static android.view.View.Y;
-import static com.android.wm.shell.animation.Interpolators.EMPHASIZED;
-import static com.android.wm.shell.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.wm.shell.bubbles.bar.BubbleBarExpandedView.CORNER_RADIUS;
+import static com.android.wm.shell.shared.animation.Interpolators.EMPHASIZED;
+import static com.android.wm.shell.shared.animation.Interpolators.EMPHASIZED_DECELERATE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -42,13 +42,13 @@ import android.widget.FrameLayout;
import androidx.annotation.Nullable;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject.MagneticTarget;
+import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject.MagneticTarget;
/**
* Helper class to animate a {@link BubbleBarExpandedView} on a bubble.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
index d45ed0d28f3b..eeb5c94c8f81 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
@@ -22,7 +22,7 @@ import android.view.View
import com.android.wm.shell.bubbles.BubblePositioner
import com.android.wm.shell.common.bubbles.DismissView
import com.android.wm.shell.common.bubbles.RelativeTouchListener
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject
/** Controller for handling drag interactions with [BubbleBarExpandedView] */
@SuppressLint("ClickableViewAccessibility")
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index 9fa85cf0c57c..ac424532e87b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -16,8 +16,8 @@
package com.android.wm.shell.bubbles.bar;
-import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
-import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
+import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_IN;
+import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_OUT;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_GESTURE;
import android.annotation.Nullable;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 3fa51a909aaa..5b01a0d87b5e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -52,6 +52,7 @@ import android.view.inputmethod.InputMethodManagerGlobal;
import androidx.annotation.VisibleForTesting;
import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
import java.util.ArrayList;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
index f7923924789e..bcd40a9a9765 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
@@ -29,6 +29,7 @@ import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
import com.android.internal.protolog.ProtoLog;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.transition.LegacyTransitions;
import java.util.ArrayList;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
index 999da2443248..bdbd4cfef7f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
@@ -32,7 +32,7 @@ import android.util.Property;
import android.view.View;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.shared.animation.Interpolators;
/**
* View for the handle in the docked stack divider.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
index 2e1789a51dff..8156a9c8d04a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
@@ -19,14 +19,14 @@ package com.android.wm.shell.common.split;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_30_70;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_70_30;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_END_AND_DISMISS;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_MINIMIZE;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_NONE;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_START_AND_DISMISS;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_30_70;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_70_30;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_END_AND_DISMISS;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_MINIMIZE;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_NONE;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_START_AND_DISMISS;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SnapPosition;
import android.content.res.Resources;
import android.graphics.Rect;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 1bc179551825..442036ff5781 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -56,8 +56,8 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.animation.Interpolators;
/**
* Divider for multi window splits.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index e2988bc6f2aa..7175e361f91a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -25,8 +25,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static com.android.wm.shell.common.split.SplitLayout.BEHIND_APP_VEIL_LAYER;
import static com.android.wm.shell.common.split.SplitLayout.FRONT_APP_VEIL_LAYER;
-import static com.android.wm.shell.common.split.SplitScreenConstants.FADE_DURATION;
-import static com.android.wm.shell.common.split.SplitScreenConstants.VEIL_DELAY_DURATION;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.FADE_DURATION;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.VEIL_DELAY_DURATION;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 0e050694c733..2a934cba1b50 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -26,13 +26,15 @@ import static android.view.WindowManager.DOCKED_TOP;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLIT_SCREEN_RESIZE;
-import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
-import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_END_AND_DISMISS;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_START_AND_DISMISS;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.shared.animation.Interpolators.DIM_INTERPOLATOR;
+import static com.android.wm.shell.shared.animation.Interpolators.EMPHASIZED;
+import static com.android.wm.shell.shared.animation.Interpolators.LINEAR;
+import static com.android.wm.shell.shared.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_END_AND_DISMISS;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_START_AND_DISMISS;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import android.animation.Animator;
@@ -65,15 +67,15 @@ import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.pip.PipUtils;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
-import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
+import com.android.wm.shell.shared.animation.Interpolators;
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.StageTaskListener;
@@ -813,7 +815,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
float growPortion = 1 - shrinkPortion;
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
- animator.setInterpolator(Interpolators.EMPHASIZED);
+ // Set the base animation to proceed linearly. Each component of the animation (movement,
+ // shrinking, growing) overrides it with a different interpolator later.
+ animator.setInterpolator(LINEAR);
animator.addUpdateListener(animation -> {
if (leash == null) return;
if (roundCorners) {
@@ -822,10 +826,11 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
final float progress = (float) animation.getAnimatedValue();
- float instantaneousX = tempStart.left + progress * diffX;
- float instantaneousY = tempStart.top + progress * diffY;
- int width = (int) (tempStart.width() + progress * diffWidth);
- int height = (int) (tempStart.height() + progress * diffHeight);
+ final float moveProgress = EMPHASIZED.getInterpolation(progress);
+ float instantaneousX = tempStart.left + moveProgress * diffX;
+ float instantaneousY = tempStart.top + moveProgress * diffY;
+ int width = (int) (tempStart.width() + moveProgress * diffWidth);
+ int height = (int) (tempStart.height() + moveProgress * diffHeight);
if (isGoingBehind) {
float shrinkDiffX; // the position adjustments needed for this frame
@@ -897,8 +902,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
taskInfo, mTempRect, t, isGoingBehind, leash, 0, 0);
}
} else {
- final int diffOffsetX = (int) (progress * offsetX);
- final int diffOffsetY = (int) (progress * offsetY);
+ final int diffOffsetX = (int) (moveProgress * offsetX);
+ final int diffOffsetY = (int) (moveProgress * offsetY);
t.setPosition(leash, instantaneousX + diffOffsetX, instantaneousY + diffOffsetY);
mTempRect.set(0, 0, width, height);
mTempRect.offsetTo(-diffOffsetX, -diffOffsetY);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
index f9259e79472e..bdbcb4635ae8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
@@ -16,34 +16,25 @@
package com.android.wm.shell.common.split;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED;
-
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import android.app.ActivityManager;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
-import android.os.UserHandle;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.util.ArrayUtils;
import com.android.wm.shell.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
-
-import java.util.Arrays;
-import java.util.List;
+import com.android.wm.shell.shared.split.SplitScreenConstants;
/** Helper utility class for split screen components to use. */
public class SplitScreenUtils {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponent.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponent.kt
index 9ee50ac3c221..831b331a11e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponent.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponent.kt
@@ -16,28 +16,222 @@
package com.android.wm.shell.compatui.api
-import android.util.Log
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.PixelFormat
+import android.graphics.Point
+import android.os.Binder
+import android.view.IWindow
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.SurfaceSession
+import android.view.View
+import android.view.WindowManager
+import android.view.WindowlessWindowManager
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.common.SyncTransactionQueue
/**
* The component created after a {@link CompatUISpec} definition
*/
class CompatUIComponent(
private val spec: CompatUISpec,
- private val id: String
+ private val id: String,
+ private var context: Context,
+ private val state: CompatUIState,
+ private var compatUIInfo: CompatUIInfo,
+ private val syncQueue: SyncTransactionQueue,
+ private var displayLayout: DisplayLayout?
+) : WindowlessWindowManager(
+ compatUIInfo.taskInfo.configuration,
+ /* rootSurface */
+ null,
+ /* hostInputToken */
+ null
) {
+ private val tag
+ get() = "CompatUI {id = $id}"
+
+ private var leash: SurfaceControl? = null
+
+ private var layout: View? = null
+
+ /**
+ * Utility class for adding and releasing a View hierarchy for this [ ] to `mLeash`.
+ */
+ protected var viewHost: SurfaceControlViewHost? = null
+
+ override fun setConfiguration(configuration: Configuration?) {
+ super.setConfiguration(configuration)
+ configuration?.let {
+ context = context.createConfigurationContext(it)
+ }
+ }
+
/**
* Invoked every time a new CompatUIInfo comes from core
* @param newInfo The new CompatUIInfo object
- * @param sharedState The state shared between all the component
*/
- fun update(newInfo: CompatUIInfo, state: CompatUIState) {
- // TODO(b/322817374): To be removed when the implementation is provided.
- Log.d("CompatUIComponent", "update() newInfo: $newInfo state:$state")
+ fun update(newInfo: CompatUIInfo) {
+ updateComponentState(newInfo, state.stateForComponent(id))
+ updateUI(state)
}
fun release() {
- // TODO(b/322817374): To be removed when the implementation is provided.
- Log.d("CompatUIComponent", "release()")
+ spec.log("$tag releasing.....")
+ // Implementation empty
+ // Hiding before releasing to avoid flickering when transitioning to the Home screen.
+ layout?.visibility = View.GONE
+ layout = null
+ spec.layout.viewReleaser()
+ spec.log("$tag layout releaser invoked!")
+ viewHost?.release()
+ viewHost = null
+ leash?.run {
+ val localLeash: SurfaceControl = this
+ syncQueue.runInSync { t: SurfaceControl.Transaction ->
+ t.remove(
+ localLeash
+ )
+ }
+ leash = null
+ spec.log("$tag leash removed")
+ }
+ spec.log("$tag released")
+ }
+
+ override fun getParentSurface(
+ window: IWindow,
+ attrs: WindowManager.LayoutParams
+ ): SurfaceControl? {
+ val className = javaClass.simpleName
+ val builder = SurfaceControl.Builder(SurfaceSession())
+ .setContainerLayer()
+ .setName(className + "Leash")
+ .setHidden(false)
+ .setCallsite("$className#attachToParentSurface")
+ attachToParentSurface(builder)
+ leash = builder.build()
+ initSurface(leash)
+ return leash
+ }
+
+ fun attachToParentSurface(builder: SurfaceControl.Builder) {
+ compatUIInfo.listener?.attachChildSurfaceToTask(compatUIInfo.taskInfo.taskId, builder)
+ }
+
+ fun initLayout(newCompatUIInfo: CompatUIInfo) {
+ compatUIInfo = newCompatUIInfo
+ spec.log("$tag updating...")
+ check(viewHost == null) { "A UI has already been created with this window manager." }
+ val componentState: CompatUIComponentState? = state.stateForComponent(id)
+ spec.log("$tag state: $componentState")
+ // We inflate the layout
+ layout = spec.layout.viewBuilder(context, compatUIInfo, componentState)
+ spec.log("$tag layout: $layout")
+ viewHost = createSurfaceViewHost().apply {
+ spec.log("$tag adding view $layout to host $this")
+ setView(layout!!, getWindowLayoutParams())
+ }
+ updateSurfacePosition()
+ }
+
+ /** Creates a [SurfaceControlViewHost] for this window manager. */
+ fun createSurfaceViewHost(): SurfaceControlViewHost =
+ SurfaceControlViewHost(context, context.display, this, javaClass.simpleName)
+
+ fun relayout() {
+ spec.log("$tag relayout...")
+ viewHost?.run {
+ relayout(getWindowLayoutParams())
+ updateSurfacePosition()
+ }
+ }
+
+ protected fun updateSurfacePosition() {
+ spec.log("$tag updateSurfacePosition on layout $layout")
+ layout?.let {
+ updateSurfacePosition(
+ spec.layout.positionFactory(
+ it,
+ compatUIInfo,
+ state.sharedState,
+ state.stateForComponent(id)
+ )
+ )
+ }
+ }
+
+ protected fun getWindowLayoutParams(width: Int, height: Int): WindowManager.LayoutParams {
+ // Cannot be wrap_content as this determines the actual window size
+ val winParams =
+ WindowManager.LayoutParams(
+ width,
+ height,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ spec.layout.layoutParamFlags,
+ PixelFormat.TRANSLUCENT
+ )
+ winParams.token = Binder()
+ winParams.title = javaClass.simpleName + compatUIInfo.taskInfo.taskId
+ winParams.privateFlags =
+ winParams.privateFlags or (WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
+ or WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
+ spec.log("$tag getWindowLayoutParams $winParams")
+ return winParams
+ }
+
+ /** Gets the layout params. */
+ protected fun getWindowLayoutParams(): WindowManager.LayoutParams =
+ layout?.run {
+ measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
+ spec.log(
+ "$tag getWindowLayoutParams size: ${measuredWidth}x$measuredHeight"
+ )
+ return getWindowLayoutParams(measuredWidth, measuredHeight)
+ } ?: WindowManager.LayoutParams()
+
+ protected fun updateSurfacePosition(position: Point) {
+ spec.log("$tag updateSurfacePosition on leash $leash")
+ leash?.run {
+ syncQueue.runInSync { t: SurfaceControl.Transaction ->
+ if (!isValid) {
+ spec.log("$tag The leash has been released.")
+ return@runInSync
+ }
+ spec.log("$tag settings position $position")
+ t.setPosition(this, position.x.toFloat(), position.y.toFloat())
+ }
+ }
+ }
+
+ private fun updateComponentState(
+ newInfo: CompatUIInfo,
+ componentState: CompatUIComponentState?
+ ) {
+ spec.log("$tag component state updating.... $componentState")
+ compatUIInfo = newInfo
+ }
+
+ private fun updateUI(state: CompatUIState) {
+ spec.log("$tag updating ui")
+ setConfiguration(compatUIInfo.taskInfo.configuration)
+ val componentState: CompatUIComponentState? = state.stateForComponent(id)
+ layout?.run {
+ spec.log("$tag viewBinder execution...")
+ spec.layout.viewBinder(this, compatUIInfo, state.sharedState, componentState)
+ relayout()
+ }
+ }
+
+ private fun initSurface(leash: SurfaceControl?) {
+ syncQueue.runInSync { t: SurfaceControl.Transaction ->
+ if (leash == null || !leash.isValid) {
+ spec.log("$tag The leash has been released.")
+ return@runInSync
+ }
+ t.setLayer(leash, spec.layout.zOrder)
+ }
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponentFactory.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponentFactory.kt
new file mode 100644
index 000000000000..55821ffdb6bd
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponentFactory.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.compatui.api
+
+/**
+ * Abstracts the component responsible for the creation of a component
+ */
+interface CompatUIComponentFactory {
+
+ fun create(
+ spec: CompatUISpec,
+ compId: String,
+ state: CompatUIState,
+ compatUIInfo: CompatUIInfo,
+ ): CompatUIComponent
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponentState.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponentState.kt
index dcaea000d0a1..ec21924fbe16 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponentState.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUIComponentState.kt
@@ -18,7 +18,6 @@ package com.android.wm.shell.compatui.api
/**
* Abstraction of all the component specific state. Each
- * component can create its own state implementing this
- * tagging interface.
+ * component can create its own state implementing this interface.
*/
-interface CompatUIComponentState \ No newline at end of file
+interface CompatUIComponentState
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUISpec.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUISpec.kt
index 022906cf568c..de400f49d64b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUISpec.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/api/CompatUISpec.kt
@@ -16,6 +16,11 @@
package com.android.wm.shell.compatui.api
+import android.content.Context
+import android.graphics.Point
+import android.view.View
+import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+import android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.protolog.ShellProtoLogGroup
@@ -39,6 +44,28 @@ class CompatUILifecyclePredicates(
)
/**
+ * Layout configuration
+ */
+data class CompatUILayout(
+ val zOrder: Int = 0,
+ val layoutParamFlags: Int = FLAG_NOT_FOCUSABLE or FLAG_NOT_TOUCH_MODAL,
+ val viewBuilder: (Context, CompatUIInfo, CompatUIComponentState?) -> View,
+ val viewBinder: (
+ View,
+ CompatUIInfo,
+ CompatUISharedState,
+ CompatUIComponentState?
+ ) -> Unit = { _, _, _, _ -> },
+ val positionFactory: (
+ View,
+ CompatUIInfo,
+ CompatUISharedState,
+ CompatUIComponentState?
+ ) -> Point,
+ val viewReleaser: () -> Unit = {}
+)
+
+/**
* Describes each compat ui component to the framework.
*/
class CompatUISpec(
@@ -47,5 +74,7 @@ class CompatUISpec(
// unique component identifier in the system.
val name: String,
// The lifecycle definition
- val lifecycle: CompatUILifecyclePredicates
+ val lifecycle: CompatUILifecyclePredicates,
+ // The layout definition
+ val layout: CompatUILayout
)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/components/RestartButtonSpec.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/components/RestartButtonSpec.kt
new file mode 100644
index 000000000000..e18cc0e5d416
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/components/RestartButtonSpec.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 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.compatui.components
+
+import android.annotation.SuppressLint
+import android.graphics.Point
+import android.view.LayoutInflater
+import android.view.View
+import android.window.TaskConstants
+import com.android.wm.shell.R
+import com.android.wm.shell.compatui.api.CompatUILayout
+import com.android.wm.shell.compatui.api.CompatUILifecyclePredicates
+import com.android.wm.shell.compatui.api.CompatUISpec
+
+/**
+ * CompatUISpec for the Restart Button
+ */
+@SuppressLint("InflateParams")
+val RestartButtonSpec = CompatUISpec(
+ name = "restartButton",
+ lifecycle = CompatUILifecyclePredicates(
+ creationPredicate = { info, _ ->
+ info.taskInfo.appCompatTaskInfo.isTopActivityInSizeCompat
+ },
+ removalPredicate = { info, _, _ ->
+ !info.taskInfo.appCompatTaskInfo.isTopActivityInSizeCompat
+ }
+ ),
+ layout = CompatUILayout(
+ zOrder = TaskConstants.TASK_CHILD_LAYER_COMPAT_UI + 10,
+ viewBuilder = { ctx, _, _ ->
+ LayoutInflater.from(ctx).inflate(
+ R.layout.compat_ui_restart_button_layout,
+ null
+ )
+ },
+ viewBinder = { view, _, _, _ ->
+ view.visibility = View.VISIBLE
+ view.findViewById<View>(R.id.size_compat_restart_button)?.visibility = View.VISIBLE
+ },
+ // TODO(b/360288344): Calculate right position from stable bounds
+ positionFactory = { _, _, _, _ -> Point(500, 500) }
+ )
+)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/DefaultCompatUIComponentFactory.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/DefaultCompatUIComponentFactory.kt
new file mode 100644
index 000000000000..4eea6a31dd27
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/DefaultCompatUIComponentFactory.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 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.compatui.impl
+
+import android.content.Context
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.compatui.api.CompatUIComponent
+import com.android.wm.shell.compatui.api.CompatUIComponentFactory
+import com.android.wm.shell.compatui.api.CompatUIInfo
+import com.android.wm.shell.compatui.api.CompatUISpec
+import com.android.wm.shell.compatui.api.CompatUIState
+
+/**
+ * Default {@link CompatUIComponentFactory } implementation
+ */
+class DefaultCompatUIComponentFactory(
+ private val context: Context,
+ private val syncQueue: SyncTransactionQueue,
+ private val displayController: DisplayController
+) : CompatUIComponentFactory {
+ override fun create(
+ spec: CompatUISpec,
+ compId: String,
+ state: CompatUIState,
+ compatUIInfo: CompatUIInfo
+ ): CompatUIComponent =
+ CompatUIComponent(
+ spec,
+ compId,
+ context,
+ state,
+ compatUIInfo,
+ syncQueue,
+ displayController.getDisplayLayout(compatUIInfo.taskInfo.displayId)
+ )
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandler.kt
index a7d1b4218a24..02db85a4f99d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandler.kt
@@ -16,7 +16,8 @@
package com.android.wm.shell.compatui.impl
-import com.android.wm.shell.compatui.api.CompatUIComponent
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.compatui.api.CompatUIComponentFactory
import com.android.wm.shell.compatui.api.CompatUIComponentIdGenerator
import com.android.wm.shell.compatui.api.CompatUIEvent
import com.android.wm.shell.compatui.api.CompatUIHandler
@@ -24,7 +25,6 @@ import com.android.wm.shell.compatui.api.CompatUIInfo
import com.android.wm.shell.compatui.api.CompatUIRepository
import com.android.wm.shell.compatui.api.CompatUIState
import java.util.function.Consumer
-import java.util.function.IntSupplier
/**
* Default implementation of {@link CompatUIHandler} to handle CompatUI components
@@ -32,7 +32,9 @@ import java.util.function.IntSupplier
class DefaultCompatUIHandler(
private val compatUIRepository: CompatUIRepository,
private val compatUIState: CompatUIState,
- private val componentIdGenerator: CompatUIComponentIdGenerator
+ private val componentIdGenerator: CompatUIComponentIdGenerator,
+ private val componentFactory: CompatUIComponentFactory,
+ private val executor: ShellExecutor
) : CompatUIHandler {
private var compatUIEventSender: Consumer<CompatUIEvent>? = null
@@ -41,23 +43,36 @@ class DefaultCompatUIHandler(
compatUIRepository.iterateOn { spec ->
// We get the identifier for the component depending on the task and spec
val componentId = componentIdGenerator.generateId(compatUIInfo, spec)
- // We check in the state if the component already exists
- var comp = compatUIState.getUIComponent(componentId)
- if (comp == null) {
+ spec.log("Evaluating component $componentId")
+ // We check in the state if the component does not yet exist
+ var component = compatUIState.getUIComponent(componentId)
+ if (component == null) {
+ spec.log("Component $componentId not present")
// We evaluate the predicate
if (spec.lifecycle.creationPredicate(compatUIInfo, compatUIState.sharedState)) {
+ spec.log("Component $componentId should be created")
// We create the component and store in the
// global state
- comp = CompatUIComponent(spec, componentId)
+ component =
+ componentFactory.create(spec, componentId, compatUIState, compatUIInfo)
+ spec.log("Component $componentId created $component")
// We initialize the state for the component
val compState = spec.lifecycle.stateBuilder(
compatUIInfo,
compatUIState.sharedState
)
- compatUIState.registerUIComponent(componentId, comp, compState)
+ spec.log("Component $componentId initial state $compState")
+ compatUIState.registerUIComponent(componentId, component, compState)
+ spec.log("Component $componentId registered")
+ // We initialize the layout for the component
+ component.initLayout(compatUIInfo)
+ spec.log("Component $componentId layout created")
// Now we can invoke the update passing the shared state and
// the state specific to the component
- comp.update(compatUIInfo, compatUIState)
+ executor.execute {
+ component.update(compatUIInfo)
+ spec.log("Component $componentId updated with $compatUIInfo")
+ }
}
} else {
// The component is present. We check if we need to remove it
@@ -66,13 +81,18 @@ class DefaultCompatUIHandler(
compatUIState.sharedState,
compatUIState.stateForComponent(componentId)
)) {
+ spec.log("Component $componentId should be removed")
// We clean the component
- comp.release()
- // We remove the component
+ component.release()
+ spec.log("Component $componentId released")
compatUIState.unregisterUIComponent(componentId)
+ spec.log("Component $componentId removed from registry")
} else {
- // The component exists so we need to invoke the update methods
- comp.update(compatUIInfo, compatUIState)
+ executor.execute {
+ // The component exists so we need to invoke the update methods
+ component.update(compatUIInfo)
+ spec.log("Component $componentId updated with $compatUIInfo")
+ }
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
index 011093718671..33e4fd8c1a46 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
@@ -30,9 +30,9 @@ import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.dagger.pip.TvPipModule;
import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.splitscreen.tv.TvSplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 04cd225ea4a3..98536bf98f0b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -62,7 +62,6 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TabletopModeController;
import com.android.wm.shell.common.TaskStackListenerImpl;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.pip.PhonePipKeepClearAlgorithm;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
@@ -77,10 +76,13 @@ import com.android.wm.shell.compatui.CompatUIConfiguration;
import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.compatui.CompatUIShellCommandHandler;
import com.android.wm.shell.compatui.CompatUIStatusManager;
+import com.android.wm.shell.compatui.api.CompatUIComponentFactory;
import com.android.wm.shell.compatui.api.CompatUIComponentIdGenerator;
import com.android.wm.shell.compatui.api.CompatUIHandler;
import com.android.wm.shell.compatui.api.CompatUIRepository;
import com.android.wm.shell.compatui.api.CompatUIState;
+import com.android.wm.shell.compatui.components.RestartButtonSpecKt;
+import com.android.wm.shell.compatui.impl.DefaultCompatUIComponentFactory;
import com.android.wm.shell.compatui.impl.DefaultCompatUIHandler;
import com.android.wm.shell.compatui.impl.DefaultCompatUIRepository;
import com.android.wm.shell.compatui.impl.DefaultComponentIdGenerator;
@@ -102,6 +104,7 @@ import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.recents.RecentsTransitionHandler;
import com.android.wm.shell.recents.TaskStackTransitionObserver;
import com.android.wm.shell.shared.ShellTransitions;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.annotations.ShellAnimationThread;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.shared.annotations.ShellMainThread;
@@ -260,13 +263,15 @@ public abstract class WMShellBaseModule {
CompatUIRepository compatUIRepository,
@NonNull CompatUIState compatUIState,
@NonNull CompatUIComponentIdGenerator componentIdGenerator,
+ @NonNull CompatUIComponentFactory compatUIComponentFactory,
CompatUIStatusManager compatUIStatusManager) {
if (!context.getResources().getBoolean(R.bool.config_enableCompatUIController)) {
return Optional.empty();
}
if (Flags.appCompatUiFramework()) {
- return Optional.of(new DefaultCompatUIHandler(compatUIRepository, compatUIState,
- componentIdGenerator));
+ return Optional.of(
+ new DefaultCompatUIHandler(compatUIRepository, compatUIState,
+ componentIdGenerator, compatUIComponentFactory, mainExecutor));
}
return Optional.of(
new CompatUIController(
@@ -308,6 +313,15 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
+ static CompatUIComponentFactory provideCompatUIComponentFactory(
+ @NonNull Context context,
+ @NonNull SyncTransactionQueue syncQueue,
+ @NonNull DisplayController displayController) {
+ return new DefaultCompatUIComponentFactory(context, syncQueue, displayController);
+ }
+
+ @WMSingleton
+ @Provides
static CompatUIComponentIdGenerator provideCompatUIComponentIdGenerator() {
return new DefaultComponentIdGenerator();
}
@@ -315,7 +329,10 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static CompatUIRepository provideCompatUIRepository() {
- return new DefaultCompatUIRepository();
+ // TODO(b/360288344) Integrate Dagger Multibinding
+ final CompatUIRepository repository = new DefaultCompatUIRepository();
+ repository.addSpec(RestartButtonSpecKt.getRestartButtonSpec());
+ return repository;
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 63a25730f1aa..ce054a833107 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -56,10 +56,10 @@ import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerImpl;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.dagger.back.ShellBackAnimationModule;
import com.android.wm.shell.dagger.pip.PipModule;
import com.android.wm.shell.desktopmode.DefaultDragToDesktopTransitionHandler;
+import com.android.wm.shell.desktopmode.DesktopModeDragAndDropTransitionHandler;
import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
@@ -84,6 +84,7 @@ import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.recents.RecentsTransitionHandler;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.annotations.ShellAnimationThread;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.shared.annotations.ShellMainThread;
@@ -303,6 +304,7 @@ public abstract class WMShellModule {
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
+ LaunchAdjacentController launchAdjacentController,
WindowDecorViewModel windowDecorViewModel) {
// TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
// override for this controller from the base module
@@ -310,7 +312,7 @@ public abstract class WMShellModule {
? shellInit
: null;
return new FreeformTaskListener(context, init, shellTaskOrganizer,
- desktopModeTaskRepository, windowDecorViewModel);
+ desktopModeTaskRepository, launchAdjacentController, windowDecorViewModel);
}
@WMSingleton
@@ -558,6 +560,7 @@ public abstract class WMShellModule {
ReturnToDragStartAnimator returnToDragStartAnimator,
EnterDesktopTaskTransitionHandler enterDesktopTransitionHandler,
ExitDesktopTaskTransitionHandler exitDesktopTransitionHandler,
+ DesktopModeDragAndDropTransitionHandler desktopModeDragAndDropTransitionHandler,
ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
DragToDesktopTransitionHandler dragToDesktopTransitionHandler,
@DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
@@ -573,7 +576,8 @@ public abstract class WMShellModule {
displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,
dragAndDropController, transitions, keyguardManager,
returnToDragStartAnimator, enterDesktopTransitionHandler,
- exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler,
+ exitDesktopTransitionHandler, desktopModeDragAndDropTransitionHandler,
+ toggleResizeDesktopTaskTransitionHandler,
dragToDesktopTransitionHandler, desktopModeTaskRepository,
desktopModeLoggerTransitionObserver, launchAdjacentController,
recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter,
@@ -608,8 +612,8 @@ public abstract class WMShellModule {
@WMSingleton
@Provides
static ReturnToDragStartAnimator provideReturnToDragStartAnimator(
- InteractionJankMonitor interactionJankMonitor) {
- return new ReturnToDragStartAnimator(interactionJankMonitor);
+ Context context, InteractionJankMonitor interactionJankMonitor) {
+ return new ReturnToDragStartAnimator(context, interactionJankMonitor);
}
@@ -655,6 +659,14 @@ public abstract class WMShellModule {
@WMSingleton
@Provides
+ static DesktopModeDragAndDropTransitionHandler provideDesktopModeDragAndDropTransitionHandler(
+ Transitions transitions
+ ) {
+ return new DesktopModeDragAndDropTransitionHandler(transitions);
+ }
+
+ @WMSingleton
+ @Provides
@DynamicOverride
static DesktopModeTaskRepository provideDesktopModeTaskRepository() {
return new DesktopModeTaskRepository();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeDragAndDropTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeDragAndDropTransitionHandler.kt
new file mode 100644
index 000000000000..a7a4a1036b5d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeDragAndDropTransitionHandler.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.desktopmode
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.os.IBinder
+import android.view.SurfaceControl
+import android.view.WindowManager.TRANSIT_OPEN
+import android.window.TransitionInfo
+import android.window.TransitionRequestInfo
+import android.window.WindowContainerTransaction
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TransitionFinishCallback
+
+/**
+ * Transition handler for drag-and-drop (i.e., tab tear) transitions that occur in desktop mode.
+ */
+class DesktopModeDragAndDropTransitionHandler(private val transitions: Transitions) :
+ Transitions.TransitionHandler {
+ private val pendingTransitionTokens: MutableList<IBinder> = mutableListOf()
+
+ /**
+ * Begin a transition when a [android.app.PendingIntent] is dropped without a window to
+ * accept it.
+ */
+ fun handleDropEvent(wct: WindowContainerTransaction): IBinder {
+ val token = transitions.startTransition(TRANSIT_OPEN, wct, this)
+ pendingTransitionTokens.add(token)
+ return token
+ }
+
+ override fun startAnimation(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction,
+ finishCallback: TransitionFinishCallback
+ ): Boolean {
+ if (!pendingTransitionTokens.contains(transition)) return false
+ val change = findRelevantChange(info)
+ val leash = change.leash
+ val endBounds = change.endAbsBounds
+ startTransaction.hide(leash)
+ .setWindowCrop(leash, endBounds.width(), endBounds.height())
+ .apply()
+ val animator = ValueAnimator()
+ animator.setFloatValues(0f, 1f)
+ animator.setDuration(FADE_IN_ANIMATION_DURATION)
+ val t = SurfaceControl.Transaction()
+ animator.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator) {
+ t.show(leash)
+ t.apply()
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+ finishCallback.onTransitionFinished(null)
+ }
+ })
+ animator.addUpdateListener { animation: ValueAnimator ->
+ t.setAlpha(leash, animation.animatedFraction)
+ t.apply()
+ }
+ animator.start()
+ pendingTransitionTokens.remove(transition)
+ return true
+ }
+
+ private fun findRelevantChange(info: TransitionInfo): TransitionInfo.Change {
+ val matchingChanges =
+ info.changes.filter { c ->
+ isValidTaskChange(c) && c.mode == TRANSIT_OPEN
+ }
+ if (matchingChanges.size != 1) {
+ throw IllegalStateException(
+ "Expected 1 relevant change but found: ${matchingChanges.size}"
+ )
+ }
+ return matchingChanges.first()
+ }
+
+ private fun isValidTaskChange(change: TransitionInfo.Change): Boolean {
+ return change.taskInfo != null && change.taskInfo?.taskId != -1
+ }
+
+ override fun handleRequest(
+ transition: IBinder,
+ request: TransitionRequestInfo
+ ): WindowContainerTransaction? {
+ return null
+ }
+
+ companion object {
+ const val FADE_IN_ANIMATION_DURATION = 300L
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
index 6c03dc333515..b68b436f2c1b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
@@ -66,7 +66,7 @@ fun calculateInitialBounds(
val initialSize: Size =
when (taskInfo.configuration.orientation) {
ORIENTATION_LANDSCAPE -> {
- if (taskInfo.isResizeable) {
+ if (taskInfo.canChangeAspectRatio) {
if (isFixedOrientationPortrait(topActivityInfo.screenOrientation)) {
// For portrait resizeable activities, respect apps fullscreen width but
// apply ideal size height.
@@ -85,7 +85,7 @@ fun calculateInitialBounds(
ORIENTATION_PORTRAIT -> {
val customPortraitWidthForLandscapeApp =
screenBounds.width() - (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2)
- if (taskInfo.isResizeable) {
+ if (taskInfo.canChangeAspectRatio) {
if (isFixedOrientationLandscape(topActivityInfo.screenOrientation)) {
// For landscape resizeable activities, respect apps fullscreen height and
// apply custom app width.
@@ -189,6 +189,13 @@ private fun positionInScreen(desiredSize: Size, stableBounds: Rect): Rect =
}
/**
+ * Whether the activity's aspect ratio can be changed or if it should be maintained as if it was
+ * unresizeable.
+ */
+private val TaskInfo.canChangeAspectRatio: Boolean
+ get() = isResizeable && !appCompatTaskInfo.hasMinAspectRatioOverride()
+
+/**
* Adjusts bounds to be positioned in the middle of the area provided, not necessarily the
* entire screen, as area can be offset by left and top start.
*/
@@ -204,7 +211,7 @@ fun centerInArea(desiredSize: Size, areaBounds: Rect, leftStart: Int, topStart:
return Rect(newLeft, newTop, newRight, newBottom)
}
-fun TaskInfo.hasPortraitTopActivity(): Boolean {
+private fun TaskInfo.hasPortraitTopActivity(): Boolean {
val topActivityScreenOrientation =
topActivityInfo?.screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED
val appBounds = configuration.windowConfiguration.appBounds
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index 09f9139cb1d5..bfc0ee803591 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -16,7 +16,6 @@
package com.android.wm.shell.desktopmode;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -29,7 +28,6 @@ import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.WindowConfiguration;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PixelFormat;
@@ -70,6 +68,37 @@ public class DesktopModeVisualIndicator {
TO_SPLIT_RIGHT_INDICATOR
}
+ /**
+ * The conditions surrounding the drag event that led to the indicator's creation.
+ */
+ public enum DragStartState {
+ /** The indicator is resulting from a freeform task drag. */
+ FROM_FREEFORM,
+ /** The indicator is resulting from a split screen task drag */
+ FROM_SPLIT,
+ /** The indicator is resulting from a fullscreen task drag */
+ FROM_FULLSCREEN,
+ /** The indicator is resulting from an Intent generated during a drag-and-drop event */
+ DRAGGED_INTENT;
+
+ /**
+ * Get the {@link DragStartState} of a drag event based on the windowing mode of the task.
+ * Note that DRAGGED_INTENT will be specified by the caller if needed and not returned
+ * here.
+ */
+ public static DesktopModeVisualIndicator.DragStartState getDragStartState(
+ ActivityManager.RunningTaskInfo taskInfo
+ ) {
+ if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+ return FROM_FULLSCREEN;
+ } else if (taskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
+ return FROM_SPLIT;
+ } else if (taskInfo.isFreeform()) {
+ return FROM_FREEFORM;
+ } else return null;
+ }
+ }
+
private final Context mContext;
private final DisplayController mDisplayController;
private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer;
@@ -82,11 +111,13 @@ public class DesktopModeVisualIndicator {
private View mView;
private IndicatorType mCurrentType;
+ private DragStartState mDragStartState;
public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue,
ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController,
Context context, SurfaceControl taskSurface,
- RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer) {
+ RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer,
+ DragStartState dragStartState) {
mSyncQueue = syncQueue;
mTaskInfo = taskInfo;
mDisplayController = displayController;
@@ -94,6 +125,7 @@ public class DesktopModeVisualIndicator {
mTaskSurface = taskSurface;
mRootTdaOrganizer = taskDisplayAreaOrganizer;
mCurrentType = IndicatorType.NO_INDICATOR;
+ mDragStartState = dragStartState;
}
/**
@@ -101,7 +133,7 @@ public class DesktopModeVisualIndicator {
* display, including no visible indicator.
*/
@NonNull
- IndicatorType updateIndicatorType(PointF inputCoordinates, int windowingMode) {
+ IndicatorType updateIndicatorType(PointF inputCoordinates) {
final DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId);
// If we are in freeform, we don't want a visible indicator in the "freeform" drag zone.
IndicatorType result = IndicatorType.NO_INDICATOR;
@@ -111,14 +143,13 @@ public class DesktopModeVisualIndicator {
// account for the possibility of the task going off the top of the screen by captionHeight
final int captionHeight = mContext.getResources().getDimensionPixelSize(
com.android.wm.shell.R.dimen.desktop_mode_freeform_decor_caption_height);
- final Region fullscreenRegion = calculateFullscreenRegion(layout, windowingMode,
+ final Region fullscreenRegion = calculateFullscreenRegion(layout, captionHeight);
+ final Region splitLeftRegion = calculateSplitLeftRegion(layout, transitionAreaWidth,
captionHeight);
- final Region splitLeftRegion = calculateSplitLeftRegion(layout, windowingMode,
- transitionAreaWidth, captionHeight);
- final Region splitRightRegion = calculateSplitRightRegion(layout, windowingMode,
- transitionAreaWidth, captionHeight);
- final Region toDesktopRegion = calculateToDesktopRegion(layout, windowingMode,
- splitLeftRegion, splitRightRegion, fullscreenRegion);
+ final Region splitRightRegion = calculateSplitRightRegion(layout, transitionAreaWidth,
+ captionHeight);
+ final Region toDesktopRegion = calculateToDesktopRegion(layout, splitLeftRegion,
+ splitRightRegion, fullscreenRegion);
if (fullscreenRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) {
result = IndicatorType.TO_FULLSCREEN_INDICATOR;
}
@@ -131,20 +162,22 @@ public class DesktopModeVisualIndicator {
if (toDesktopRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) {
result = IndicatorType.TO_DESKTOP_INDICATOR;
}
- transitionIndicator(result);
+ if (mDragStartState != DragStartState.DRAGGED_INTENT) {
+ transitionIndicator(result);
+ }
return result;
}
@VisibleForTesting
- Region calculateFullscreenRegion(DisplayLayout layout,
- @WindowConfiguration.WindowingMode int windowingMode, int captionHeight) {
+ Region calculateFullscreenRegion(DisplayLayout layout, int captionHeight) {
final Region region = new Region();
- int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM
+ int transitionHeight = mDragStartState == DragStartState.FROM_FREEFORM
+ || mDragStartState == DragStartState.DRAGGED_INTENT
? mContext.getResources().getDimensionPixelSize(
com.android.wm.shell.R.dimen.desktop_mode_transition_region_thickness)
: 2 * layout.stableInsets().top;
// A Rect at the top of the screen that takes up the center 40%.
- if (windowingMode == WINDOWING_MODE_FREEFORM) {
+ if (mDragStartState == DragStartState.FROM_FREEFORM) {
final float toFullscreenScale = mContext.getResources().getFloat(
R.dimen.desktop_mode_fullscreen_region_scale);
final float toFullscreenWidth = (layout.width() * toFullscreenScale);
@@ -153,9 +186,11 @@ public class DesktopModeVisualIndicator {
(int) ((layout.width() / 2f) + (toFullscreenWidth / 2f)),
transitionHeight));
}
- // A screen-wide Rect if the task is in fullscreen or split.
- if (windowingMode == WINDOWING_MODE_FULLSCREEN
- || windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
+ // A screen-wide Rect if the task is in fullscreen, split, or a dragged intent.
+ if (mDragStartState == DragStartState.FROM_FULLSCREEN
+ || mDragStartState == DragStartState.FROM_SPLIT
+ || mDragStartState == DragStartState.DRAGGED_INTENT
+ ) {
region.union(new Rect(0,
-captionHeight,
layout.width(),
@@ -166,12 +201,11 @@ public class DesktopModeVisualIndicator {
@VisibleForTesting
Region calculateToDesktopRegion(DisplayLayout layout,
- @WindowConfiguration.WindowingMode int windowingMode,
Region splitLeftRegion, Region splitRightRegion,
Region toFullscreenRegion) {
final Region region = new Region();
// If in desktop, we need no region. Otherwise it's the same for all windowing modes.
- if (windowingMode != WINDOWING_MODE_FREEFORM) {
+ if (mDragStartState != DragStartState.FROM_FREEFORM) {
region.union(new Rect(0, 0, layout.width(), layout.height()));
region.op(splitLeftRegion, Region.Op.DIFFERENCE);
region.op(splitRightRegion, Region.Op.DIFFERENCE);
@@ -182,11 +216,10 @@ public class DesktopModeVisualIndicator {
@VisibleForTesting
Region calculateSplitLeftRegion(DisplayLayout layout,
- @WindowConfiguration.WindowingMode int windowingMode,
int transitionEdgeWidth, int captionHeight) {
final Region region = new Region();
// In freeform, keep the top corners clear.
- int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM
+ int transitionHeight = mDragStartState == DragStartState.FROM_FREEFORM
? mContext.getResources().getDimensionPixelSize(
com.android.wm.shell.R.dimen.desktop_mode_split_from_desktop_height) :
-captionHeight;
@@ -196,11 +229,10 @@ public class DesktopModeVisualIndicator {
@VisibleForTesting
Region calculateSplitRightRegion(DisplayLayout layout,
- @WindowConfiguration.WindowingMode int windowingMode,
int transitionEdgeWidth, int captionHeight) {
final Region region = new Region();
// In freeform, keep the top corners clear.
- int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM
+ int transitionHeight = mDragStartState == DragStartState.FROM_FREEFORM
? mContext.getResources().getDimensionPixelSize(
com.android.wm.shell.R.dimen.desktop_mode_split_from_desktop_height) :
-captionHeight;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 544c2dd5c484..33794d242c03 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -34,10 +34,12 @@ import android.graphics.Point
import android.graphics.PointF
import android.graphics.Rect
import android.graphics.Region
+import android.os.Binder
import android.os.IBinder
import android.os.SystemProperties
import android.util.Size
import android.view.Display.DEFAULT_DISPLAY
+import android.view.DragEvent
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
@@ -67,10 +69,9 @@ import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.SingleInstanceRemoteListener
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener
+import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.DragStartState
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType
import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener
import com.android.wm.shell.draganddrop.DragAndDropController
@@ -79,6 +80,7 @@ import com.android.wm.shell.recents.RecentTasksController
import com.android.wm.shell.recents.RecentsTransitionHandler
import com.android.wm.shell.recents.RecentsTransitionStateListener
import com.android.wm.shell.shared.TransitionUtil
+import com.android.wm.shell.shared.ShellSharedConstants
import com.android.wm.shell.shared.annotations.ExternalThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags
@@ -86,12 +88,13 @@ import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVI
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useDesktopOverrideDensity
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DESKTOP_MODE
import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
-import com.android.wm.shell.sysui.ShellSharedConstants
import com.android.wm.shell.transition.OneShotRemoteHandler
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.windowdecor.DragPositioningCallbackUtility
@@ -121,6 +124,7 @@ class DesktopTasksController(
private val returnToDragStartAnimator: ReturnToDragStartAnimator,
private val enterDesktopTaskTransitionHandler: EnterDesktopTaskTransitionHandler,
private val exitDesktopTaskTransitionHandler: ExitDesktopTaskTransitionHandler,
+ private val desktopModeDragAndDropTransitionHandler: DesktopModeDragAndDropTransitionHandler,
private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler,
private val dragToDesktopTransitionHandler: DragToDesktopTransitionHandler,
private val taskRepository: DesktopModeTaskRepository,
@@ -146,12 +150,6 @@ class DesktopTasksController(
visualIndicator?.releaseVisualIndicator(t)
visualIndicator = null
}
- private val taskVisibilityListener =
- object : VisibleTasksListener {
- override fun onTasksVisibilityChanged(displayId: Int, visibleTasksCount: Int) {
- launchAdjacentController.launchAdjacentEnabled = visibleTasksCount == 0
- }
- }
private val dragToDesktopStateListener =
object : DragToDesktopStateListener {
override fun onCommitToDesktopAnimationStart(tx: SurfaceControl.Transaction) {
@@ -176,6 +174,9 @@ class DesktopTasksController(
private var recentsAnimationRunning = false
private lateinit var splitScreenController: SplitScreenController
+ // Launch cookie used to identify a drag and drop transition to fullscreen after it has begun.
+ // Used to prevent handleRequest from moving the new fullscreen task to freeform.
+ private var dragAndDropFullscreenCookie: Binder? = null
init {
desktopMode = DesktopModeImpl()
@@ -194,7 +195,6 @@ class DesktopTasksController(
this
)
transitions.addHandler(this)
- taskRepository.addVisibleTasksListener(taskVisibilityListener, mainExecutor)
dragToDesktopTransitionHandler.dragToDesktopStateListener = dragToDesktopStateListener
recentsTransitionHandler.addTransitionStateListener(
object : RecentsTransitionStateListener {
@@ -858,6 +858,7 @@ class DesktopTasksController(
val triggerTask = request.triggerTask
var shouldHandleMidRecentsFreeformLaunch =
recentsAnimationRunning && isFreeformRelaunch(triggerTask, request)
+ val isDragAndDropFullscreenTransition = taskContainsDragAndDropCookie(triggerTask)
val shouldHandleRequest =
when {
// Handle freeform relaunch during recents animation
@@ -866,6 +867,13 @@ class DesktopTasksController(
reason = "recents animation is running"
false
}
+ // Don't handle request if this was a tear to fullscreen transition.
+ // handleFullscreenTaskLaunch moves fullscreen intents to freeform;
+ // this is an exception to the rule
+ isDragAndDropFullscreenTransition -> {
+ dragAndDropFullscreenCookie = null
+ false
+ }
// Handle task closing for the last window if wallpaper is available
shouldHandleTaskClosing(request) -> true
// Only handle open or to front transitions
@@ -884,8 +892,7 @@ class DesktopTasksController(
false
}
// Only handle fullscreen or freeform tasks
- triggerTask.windowingMode != WINDOWING_MODE_FULLSCREEN &&
- triggerTask.windowingMode != WINDOWING_MODE_FREEFORM -> {
+ !triggerTask.isFullscreen && !triggerTask.isFreeform -> {
reason = "windowingMode not handled (${triggerTask.windowingMode})"
false
}
@@ -920,6 +927,9 @@ class DesktopTasksController(
return result
}
+ private fun taskContainsDragAndDropCookie(taskInfo: RunningTaskInfo?) =
+ taskInfo?.launchCookies?.any { it == dragAndDropFullscreenCookie } ?: false
+
/**
* Applies the proper surface states (rounded corners) to tasks when desktop mode is active.
* This is intended to be used when desktop mode is part of another animation but isn't, itself,
@@ -1319,15 +1329,17 @@ class DesktopTasksController(
taskBounds: Rect
) {
if (taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) return
- updateVisualIndicator(taskInfo, taskSurface, inputX, taskBounds.top.toFloat())
+ updateVisualIndicator(taskInfo, taskSurface, inputX, taskBounds.top.toFloat(),
+ DragStartState.FROM_FREEFORM)
}
fun updateVisualIndicator(
taskInfo: RunningTaskInfo,
- taskSurface: SurfaceControl,
+ taskSurface: SurfaceControl?,
inputX: Float,
- taskTop: Float
- ): IndicatorType {
+ taskTop: Float,
+ dragStartState: DragStartState
+ ): DesktopModeVisualIndicator.IndicatorType {
// If the visual indicator does not exist, create it.
val indicator =
visualIndicator
@@ -1337,10 +1349,11 @@ class DesktopTasksController(
displayController,
context,
taskSurface,
- rootTaskDisplayAreaOrganizer
+ rootTaskDisplayAreaOrganizer,
+ dragStartState
)
if (visualIndicator == null) visualIndicator = indicator
- return indicator.updateIndicatorType(PointF(inputX, taskTop), taskInfo.windowingMode)
+ return indicator.updateIndicatorType(PointF(inputX, taskTop))
}
/**
@@ -1373,7 +1386,6 @@ class DesktopTasksController(
val indicatorType =
indicator.updateIndicatorType(
PointF(inputCoordinate.x, currentDragBounds.top.toFloat()),
- taskInfo.windowingMode
)
when (indicatorType) {
IndicatorType.TO_FULLSCREEN_INDICATOR -> {
@@ -1434,7 +1446,7 @@ class DesktopTasksController(
// End the drag_hold CUJ interaction.
interactionJankMonitor.end(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
val indicator = getVisualIndicator() ?: return IndicatorType.NO_INDICATOR
- val indicatorType = indicator.updateIndicatorType(inputCoordinates, taskInfo.windowingMode)
+ val indicatorType = indicator.updateIndicatorType(inputCoordinates)
when (indicatorType) {
IndicatorType.TO_DESKTOP_INDICATOR -> {
// Start a new jank interaction for the drag release to desktop window animation.
@@ -1486,9 +1498,10 @@ class DesktopTasksController(
taskRepository.setExclusionRegionListener(listener, callbackExecutor)
}
+ // TODO(b/358114479): Move this implementation into a separate class.
override fun onUnhandledDrag(
launchIntent: PendingIntent,
- dragSurface: SurfaceControl,
+ dragEvent: DragEvent,
onFinishCallback: Consumer<Boolean>
): Boolean {
// TODO(b/320797628): Pass through which display we are dropping onto
@@ -1496,7 +1509,6 @@ class DesktopTasksController(
// Not currently in desktop mode, ignore the drop
return false
}
-
val launchComponent = getComponent(launchIntent)
if (!multiInstanceHelper.supportsMultiInstanceSplit(launchComponent)) {
// TODO(b/320797628): Should only return early if there is an existing running task, and
@@ -1504,20 +1516,69 @@ class DesktopTasksController(
logV("Dropped intent does not support multi-instance")
return false
}
-
+ val taskInfo = getFocusedFreeformTask(DEFAULT_DISPLAY) ?: return false
+ // TODO(b/358114479): Update drag and drop handling to give us visibility into when another
+ // window will accept a drag event. This way, we can hide the indicator when we won't
+ // be handling the transition here, allowing us to display the indicator accurately.
+ // For now, we create the indicator only on drag end and immediately dispose it.
+ val indicatorType = updateVisualIndicator(taskInfo, dragEvent.dragSurface,
+ dragEvent.x, dragEvent.y,
+ DragStartState.DRAGGED_INTENT)
+ releaseVisualIndicator()
+ val windowingMode = when (indicatorType) {
+ IndicatorType.TO_FULLSCREEN_INDICATOR -> {
+ WINDOWING_MODE_FULLSCREEN
+ }
+ IndicatorType.TO_SPLIT_LEFT_INDICATOR,
+ IndicatorType.TO_SPLIT_RIGHT_INDICATOR,
+ IndicatorType.TO_DESKTOP_INDICATOR
+ -> {
+ WINDOWING_MODE_FREEFORM
+ }
+ else -> error("Invalid indicator type: $indicatorType")
+ }
+ val displayLayout = displayController.getDisplayLayout(DEFAULT_DISPLAY) ?: return false
+ val newWindowBounds = Rect()
+ when (indicatorType) {
+ IndicatorType.TO_DESKTOP_INDICATOR -> {
+ // Use default bounds, but with the top-center at the drop point.
+ newWindowBounds.set(getDefaultDesktopTaskBounds(displayLayout))
+ newWindowBounds.offsetTo(
+ dragEvent.x.toInt() - (newWindowBounds.width() / 2),
+ dragEvent.y.toInt()
+ )
+ }
+ IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
+ newWindowBounds.set(getSnapBounds(taskInfo, SnapPosition.RIGHT))
+ }
+ IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
+ newWindowBounds.set(getSnapBounds(taskInfo, SnapPosition.LEFT))
+ }
+ else -> {
+ // Use empty bounds for the fullscreen case.
+ }
+ }
// Start a new transition to launch the app
val opts =
ActivityOptions.makeBasic().apply {
- launchWindowingMode = WINDOWING_MODE_FREEFORM
+ launchWindowingMode = windowingMode
+ launchBounds = newWindowBounds
+ pendingIntentBackgroundActivityStartMode =
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
pendingIntentLaunchFlags =
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
- setPendingIntentBackgroundActivityStartMode(
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED
- )
}
+ if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ dragAndDropFullscreenCookie = Binder()
+ opts.launchCookie = dragAndDropFullscreenCookie
+ }
val wct = WindowContainerTransaction()
wct.sendPendingIntent(launchIntent, null, opts.toBundle())
- transitions.startTransition(TRANSIT_OPEN, wct, null /* handler */)
+ if (windowingMode == WINDOWING_MODE_FREEFORM) {
+ desktopModeDragAndDropTransitionHandler.handleDropEvent(wct)
+ } else {
+ transitions.startTransition(TRANSIT_OPEN, wct, null)
+ }
// Report that this is handled by the listener
onFinishCallback.accept(true)
@@ -1525,7 +1586,7 @@ class DesktopTasksController(
// We've assumed responsibility of cleaning up the drag surface, so do that now
// TODO(b/320797628): Do an actual animation here for the drag surface
val t = SurfaceControl.Transaction()
- t.remove(dragSurface)
+ t.remove(dragEvent.dragSurface)
t.apply()
return true
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index 9874f4c269a4..1a103d345ca7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -35,13 +35,13 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.animation.FloatProperties
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition
import com.android.wm.shell.protolog.ShellProtoLogGroup
import com.android.wm.shell.shared.TransitionUtil
import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ReturnToDragStartAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ReturnToDragStartAnimator.kt
index be67a40560aa..24a7d77c983f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ReturnToDragStartAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ReturnToDragStartAnimator.kt
@@ -19,23 +19,27 @@ package com.android.wm.shell.desktopmode
import android.animation.Animator
import android.animation.RectEvaluator
import android.animation.ValueAnimator
+import android.content.Context
import android.graphics.Rect
import android.view.SurfaceControl
+import android.widget.Toast
import androidx.core.animation.addListener
import com.android.internal.jank.InteractionJankMonitor
+import com.android.wm.shell.R
import com.android.wm.shell.windowdecor.OnTaskRepositionAnimationListener
import java.util.function.Supplier
/** Animates the task surface moving from its current drag position to its pre-drag position. */
class ReturnToDragStartAnimator(
+ private val context: Context,
private val transactionSupplier: Supplier<SurfaceControl.Transaction>,
private val interactionJankMonitor: InteractionJankMonitor
) {
private var boundsAnimator: Animator? = null
private lateinit var taskRepositionAnimationListener: OnTaskRepositionAnimationListener
- constructor(interactionJankMonitor: InteractionJankMonitor) :
- this(Supplier { SurfaceControl.Transaction() }, interactionJankMonitor)
+ constructor(context: Context, interactionJankMonitor: InteractionJankMonitor) :
+ this(context, Supplier { SurfaceControl.Transaction() }, interactionJankMonitor)
/** Sets a listener for the start and end of the reposition animation. */
fun setTaskRepositionAnimationListener(listener: OnTaskRepositionAnimationListener) {
@@ -76,7 +80,11 @@ class ReturnToDragStartAnimator(
.apply()
taskRepositionAnimationListener.onAnimationEnd(taskId)
boundsAnimator = null
- // TODO(b/354658237) - show toast with relevant string
+ Toast.makeText(
+ context,
+ R.string.desktop_mode_non_resizable_snap_text,
+ Toast.LENGTH_SHORT
+ ).show()
// TODO(b/339582583) - add Jank CUJ using interactionJankMonitor
}
)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index e00353d6ac82..cf02fb5fde8e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -32,7 +32,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -70,6 +70,7 @@ import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.annotations.ExternalMainThread;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
@@ -127,7 +128,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
* drag.
*/
default boolean onUnhandledDrag(@NonNull PendingIntent launchIntent,
- @NonNull SurfaceControl dragSurface,
+ @NonNull DragEvent dragEvent,
@NonNull Consumer<Boolean> onFinishCallback) {
return false;
}
@@ -329,9 +330,18 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
return false;
}
+ DragSession dragSession = null;
if (event.getAction() == ACTION_DRAG_STARTED) {
mActiveDragDisplay = displayId;
- pd.isHandlingDrag = DragUtils.canHandleDrag(event);
+ dragSession = new DragSession(ActivityTaskManager.getInstance(),
+ mDisplayController.getDisplayLayout(displayId), event.getClipData(),
+ event.getDragFlags());
+ dragSession.initialize();
+ final ActivityManager.RunningTaskInfo taskInfo = dragSession.runningTaskInfo;
+ // Desktop tasks will have their own drag handling.
+ final boolean isDesktopDrag = taskInfo != null && taskInfo.isFreeform()
+ && DesktopModeStatus.canEnterDesktopMode(mContext);
+ pd.isHandlingDrag = DragUtils.canHandleDrag(event) && !isDesktopDrag;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
"Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s flags=%s",
pd.isHandlingDrag, event.getClipData().getItemCount(),
@@ -349,10 +359,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
Slog.w(TAG, "Unexpected drag start during an active drag");
return false;
}
- pd.dragSession = new DragSession(ActivityTaskManager.getInstance(),
- mDisplayController.getDisplayLayout(displayId), event.getClipData(),
- event.getDragFlags());
- pd.dragSession.initialize();
+ pd.dragSession = dragSession;
pd.activeDragCount++;
pd.dragLayout.prepare(pd.dragSession, mLogger.logStart(pd.dragSession));
if (pd.dragSession.hideDragSourceTaskId != -1) {
@@ -437,7 +444,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
}
final boolean handled = notifyListeners(
- l -> l.onUnhandledDrag(launchIntent, dragEvent.getDragSurface(), onFinishCallback));
+ l -> l.onUnhandledDrag(launchIntent, dragEvent, onFinishCallback));
if (!handled) {
// Nobody handled this, we still have to notify WM
onFinishCallback.accept(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 7e0362475f21..6fec0c1c20bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -32,15 +32,15 @@ import static android.content.Intent.EXTRA_USER;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-import static com.android.wm.shell.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.shared.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
@@ -69,8 +69,8 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.lang.annotation.Retention;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index d03a561cd3ea..3fecbe7fff74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -21,15 +21,14 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -61,9 +60,9 @@ import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.io.PrintWriter;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index 18cd2d84d32d..f9749ec1e2b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -16,10 +16,9 @@
package com.android.wm.shell.draganddrop;
-import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.wm.shell.shared.animation.Interpolators.FAST_OUT_SLOW_IN;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 456767a1c9af..83cc18baf6cc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -27,6 +27,7 @@ import android.view.SurfaceControl;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
@@ -49,6 +50,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
private final WindowDecorViewModel mWindowDecorationViewModel;
+ private final LaunchAdjacentController mLaunchAdjacentController;
private final SparseArray<State> mTasks = new SparseArray<>();
@@ -62,11 +64,13 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
+ LaunchAdjacentController launchAdjacentController,
WindowDecorViewModel windowDecorationViewModel) {
mContext = context;
mShellTaskOrganizer = shellTaskOrganizer;
mWindowDecorationViewModel = windowDecorationViewModel;
mDesktopModeTaskRepository = desktopModeTaskRepository;
+ mLaunchAdjacentController = launchAdjacentController;
if (shellInit != null) {
shellInit.addInitCallback(this::onInit, this);
}
@@ -106,6 +110,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
}
});
}
+ updateLaunchAdjacentController();
}
@Override
@@ -123,6 +128,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
mWindowDecorationViewModel.destroyWindowDecoration(taskInfo);
}
+ updateLaunchAdjacentController();
}
@Override
@@ -144,6 +150,17 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
taskInfo.isVisible);
});
}
+ updateLaunchAdjacentController();
+ }
+
+ private void updateLaunchAdjacentController() {
+ for (int i = 0; i < mTasks.size(); i++) {
+ if (mTasks.valueAt(i).mTaskInfo.isVisible) {
+ mLaunchAdjacentController.setLaunchAdjacentEnabled(false);
+ return;
+ }
+ }
+ mLaunchAdjacentController.setLaunchAdjacentEnabled(true);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 962309f7c534..1827923aad90 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -23,7 +23,7 @@ import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING;
import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED;
import android.annotation.BinderThread;
import android.content.ComponentName;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 852382ddfba1..b0c896fbe516 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -40,9 +40,9 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.transition.Transitions;
import java.lang.annotation.Retention;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 86777dfb3d6b..b3beb4ab79c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -25,8 +25,6 @@ import static android.util.RotationUtils.rotateBounds;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START;
@@ -42,6 +40,8 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI
import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import static com.android.wm.shell.pip.PipAnimationController.isRemovePipDirection;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
@@ -76,7 +76,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
@@ -90,6 +89,7 @@ import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index da6221efdaee..5ec0c11109a0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -32,7 +32,7 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index f92938989637..0d2b8e70422d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -37,8 +37,8 @@ import com.android.wm.shell.bubbles.DismissViewUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.bubbles.DismissCircleView;
import com.android.wm.shell.common.bubbles.DismissView;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.android.wm.shell.common.pip.PipUiEventLogger;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import kotlin.Unit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 0d7f7f66032a..c8b52c6b00c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -63,11 +63,11 @@ import android.widget.LinearLayout;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.animation.Interpolators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index 999ab95ccb1e..82fbfadc162a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -39,7 +39,6 @@ import com.android.wm.shell.R;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.android.wm.shell.common.pip.PipAppOpsListener;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipPerfHintController;
@@ -49,6 +48,7 @@ import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
import com.android.wm.shell.shared.annotations.ShellMainThread;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index dc21f82c326c..eb6caba0600c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -19,7 +19,7 @@ package com.android.wm.shell.pip2.phone;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
import android.app.ActivityManager;
import android.app.PictureInPictureParams;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java
index e7e797096c0e..e04178e6d58c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java
@@ -37,8 +37,8 @@ import com.android.wm.shell.bubbles.DismissViewUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.bubbles.DismissCircleView;
import com.android.wm.shell.common.bubbles.DismissView;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.android.wm.shell.common.pip.PipUiEventLogger;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import kotlin.Unit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
index c54e4cd90f57..a29104c4aafd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
@@ -61,11 +61,11 @@ import android.widget.LinearLayout;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.animation.Interpolators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index 83253c6006fb..218d456e9596 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -42,7 +42,6 @@ import com.android.internal.util.Preconditions;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.common.FloatingContentCoordinator;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.android.wm.shell.common.pip.PipAppOpsListener;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
@@ -51,6 +50,7 @@ import com.android.wm.shell.common.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip2.animation.PipResizeAnimator;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index da7e03f465e9..2f0af8557538 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -19,7 +19,7 @@ package com.android.wm.shell.recents;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.pm.PackageManager.FEATURE_PC;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index ad3f4f8c9beb..7a9eb1c582b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -29,7 +29,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION;
import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
import android.annotation.Nullable;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 06c57bd7092d..a6233dc927a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -25,9 +25,9 @@ import android.os.Bundle;
import android.window.RemoteTransition;
import com.android.internal.logging.InstanceId;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.shared.annotations.ExternalThread;
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import java.util.concurrent.Executor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 83f827ae54da..7e165afce7d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -27,16 +27,16 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.wm.shell.common.MultiInstanceHelper.getComponent;
import static com.android.wm.shell.common.MultiInstanceHelper.getShortcutComponent;
import static com.android.wm.shell.common.MultiInstanceHelper.samePackage;
-import static com.android.wm.shell.common.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.common.split.SplitScreenUtils.isValidToSplit;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -90,16 +90,16 @@ import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.annotations.ExternalThread;
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
index af11ebc515d7..e1b474d9804a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
@@ -16,7 +16,7 @@
package com.android.wm.shell.splitscreen;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
import com.android.wm.shell.sysui.ShellCommandHandler;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index c1f603839ef6..840049412db4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -21,12 +21,12 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
-import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.FADE_DURATION;
-import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
+import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_IN;
+import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_OUT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.FADE_DURATION;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
@@ -47,9 +47,9 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.protolog.ProtoLog;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.transition.OneShotRemoteHandler;
import com.android.wm.shell.transition.Transitions;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
index a0bf843444df..27ded57b38d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
@@ -32,8 +32,8 @@ import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED_
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__UNKNOWN_EXIT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_DRAG;
import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_LAUNCHER;
import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_MULTI_INSTANCE;
@@ -58,7 +58,7 @@ import android.util.Slog;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason;
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 9bf515933b22..0b5c75104f65 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -34,16 +34,16 @@ import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
-import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-import static com.android.wm.shell.common.split.SplitScreenConstants.splitPositionToString;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.splitPositionToString;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -125,16 +125,16 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.common.split.SplitWindowManager;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason;
import com.android.wm.shell.transition.DefaultMixedHandler;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index f19eb3f8291e..99f3832192e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -22,9 +22,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java
index e0f63940663a..bb2f60b64a4a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java
@@ -39,8 +39,8 @@ import android.view.WindowManagerGlobal;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.split.SplitScreenConstants;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.split.SplitScreenConstants;
/**
* Handles the interaction logic with the {@link TvSplitMenuView}.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuView.java
index 88e9757a9b31..b758b531075a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuView.java
@@ -19,8 +19,8 @@ package com.android.wm.shell.splitscreen.tv;
import static android.view.KeyEvent.ACTION_DOWN;
import static android.view.KeyEvent.KEYCODE_BACK;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import android.content.Context;
import android.util.AttributeSet;
@@ -31,7 +31,7 @@ import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.android.wm.shell.R;
-import com.android.wm.shell.common.split.SplitScreenConstants;
+import com.android.wm.shell.shared.split.SplitScreenConstants;
/**
* A View for the Menu Window.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
index b65e97899f3e..34681569a16c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
@@ -32,8 +32,8 @@ import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.splitscreen.StageCoordinator;
import com.android.wm.shell.sysui.ShellCommandHandler;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
index 81ca48fa6b3d..4451ee887363 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
@@ -28,9 +28,9 @@ import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.common.split.SplitScreenConstants;
import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.shared.TransactionPool;
+import com.android.wm.shell.shared.split.SplitScreenConstants;
import com.android.wm.shell.splitscreen.StageCoordinator;
import com.android.wm.shell.transition.Transitions;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
index edb5aba1e46b..42b8b73cfb80 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -29,7 +29,8 @@ import android.window.SplashScreenView;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.wm.shell.R;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
+import com.android.wm.shell.shared.startingsurface.SplashScreenExitAnimationUtils;
/**
* Default animation for exiting the splash screen window.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 759f97f54a9e..b18feefe7eb3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -78,8 +78,8 @@ import com.android.internal.policy.PhoneWindow;
import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.TransactionPool;
import java.util.List;
import java.util.function.Consumer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 97a695f34cf7..fac3592896ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -46,8 +46,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.annotations.ShellSplashscreenThread;
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index fa084c585a59..7cb8e8aa7b49 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -23,7 +23,7 @@ import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SOLID_COLOR
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_WINDOWLESS;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.TaskInfo;
@@ -48,7 +48,7 @@ import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java
index bad5baf24651..2a22d4dd0cb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java
@@ -36,7 +36,7 @@ import android.window.StartingWindowInfo;
import android.window.TaskSnapshot;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
class WindowlessSnapshotWindowCreator {
private static final int DEFAULT_FADEOUT_DURATION = 233;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java
index 1a38449fa447..e1d760058711 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSplashWindowCreator.java
@@ -36,7 +36,7 @@ import android.window.StartingWindowInfo;
import android.window.StartingWindowRemovalInfo;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
class WindowlessSplashWindowCreator extends AbsSplashWindowCreator {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index de6887a2173b..a9a4e1093392 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -18,8 +18,8 @@ package com.android.wm.shell.transition;
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
import static android.app.ActivityOptions.ANIM_CUSTOM;
-import static android.app.ActivityOptions.ANIM_NONE;
import static android.app.ActivityOptions.ANIM_FROM_STYLE;
+import static android.app.ActivityOptions.ANIM_NONE;
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
@@ -112,8 +112,8 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
index 8cc7f212af25..30d7245436be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
@@ -20,8 +20,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
-import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningMode;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
index 391c5fe3473c..fd4d568326d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
@@ -18,7 +18,7 @@ package com.android.wm.shell.transition;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.transition.DefaultMixedHandler.handoverTransitionLeashes;
import static com.android.wm.shell.transition.MixedTransitionHelper.animateEnterPipFromSplit;
import static com.android.wm.shell.transition.MixedTransitionHelper.animateKeyguard;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index 195882553602..0bf9d368ab74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -47,7 +47,7 @@ import android.window.TransitionInfo;
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import java.util.ArrayList;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 001bf26ddd0f..68217c0cc98a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -38,12 +38,12 @@ import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_NO_ANIMATION;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
-import static com.android.window.flags.Flags.ensureWallpaperInTransitions;
import static com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary;
+import static com.android.window.flags.Flags.ensureWallpaperInTransitions;
import static com.android.window.flags.Flags.migratePredictiveBackTransition;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -85,12 +85,12 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.IHomeTransitionListener;
import com.android.wm.shell.shared.IShellTransitions;
import com.android.wm.shell.shared.ShellTransitions;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.shared.annotations.ExternalThread;
import com.android.wm.shell.sysui.ShellCommandHandler;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java
index e6d35e83116b..2ca749c276e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java
@@ -23,7 +23,7 @@ import android.util.SparseArray;
import android.view.SurfaceControl;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener;
import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index 88bfebf9331e..f783b45589b3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -34,7 +34,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.protolog.ProtoLog;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
index bb5d54652460..d28287da83b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
@@ -19,8 +19,8 @@ package com.android.wm.shell.unfold.animation;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -41,7 +41,7 @@ import android.view.WindowInsets;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreen.SplitScreenListener;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java
index 3e06d2d0e797..88b752822a20 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java
@@ -19,7 +19,7 @@ import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
import java.util.Objects;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 8c8f205ca353..457b5112076e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -34,13 +34,13 @@ import static android.view.MotionEvent.ACTION_UP;
import static android.view.WindowInsets.Type.statusBars;
import static com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.compatui.AppCompatUtils.isTopActivityExemptFromDesktopWindowing;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import android.annotation.NonNull;
@@ -74,6 +74,7 @@ import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
+import android.widget.Toast;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -96,7 +97,6 @@ import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
@@ -105,6 +105,7 @@ import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -469,7 +470,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
if (!decoration.mTaskInfo.isResizeable
&& DesktopModeFlags.DISABLE_SNAP_RESIZE.isEnabled(mContext)) {
- //TODO(b/354658237) - show toast with relevant string
+ Toast.makeText(mContext,
+ R.string.desktop_mode_non_resizable_snap_text, Toast.LENGTH_SHORT).show();
} else {
mDesktopTasksController.snapToHalfScreen(decoration.mTaskInfo,
decoration.mTaskInfo.configuration.windowConfiguration.getBounds(),
@@ -1029,7 +1031,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
final boolean shouldStartTransitionDrag =
relevantDecor.checkTouchEventInFocusedCaptionHandle(ev)
- || Flags.enableAdditionalWindowsAboveStatusBar();
+ || Flags.enableAdditionalWindowsAboveStatusBar();
if (dragFromStatusBarAllowed && shouldStartTransitionDrag) {
mTransitionDragActive = true;
}
@@ -1037,8 +1039,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
case MotionEvent.ACTION_UP: {
if (mTransitionDragActive) {
+ final DesktopModeVisualIndicator.DragStartState dragStartState =
+ DesktopModeVisualIndicator.DragStartState
+ .getDragStartState(relevantDecor.mTaskInfo);
+ if (dragStartState == null) return;
mDesktopTasksController.updateVisualIndicator(relevantDecor.mTaskInfo,
- relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY());
+ relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY(),
+ dragStartState);
mTransitionDragActive = false;
if (mMoveToDesktopAnimator != null) {
// Though this isn't a hover event, we need to update handle's hover state
@@ -1078,10 +1085,15 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
&& mMoveToDesktopAnimator == null) {
return;
}
+ final DesktopModeVisualIndicator.DragStartState dragStartState =
+ DesktopModeVisualIndicator.DragStartState
+ .getDragStartState(relevantDecor.mTaskInfo);
+ if (dragStartState == null) return;
final DesktopModeVisualIndicator.IndicatorType indicatorType =
mDesktopTasksController.updateVisualIndicator(
relevantDecor.mTaskInfo,
- relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY());
+ relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY(),
+ dragStartState);
if (indicatorType != TO_FULLSCREEN_INDICATOR) {
if (mMoveToDesktopAnimator == null) {
mMoveToDesktopAnimator = new MoveToDesktopAnimator(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index b5f5bb931c02..75a6cd7b720e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -27,7 +27,7 @@ import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
import static com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeEdgeHandleSize;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index c16c16f5dfa2..34de94eb3352 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -45,7 +45,7 @@ import androidx.compose.ui.graphics.toArgb
import androidx.core.view.isGone
import com.android.window.flags.Flags
import com.android.wm.shell.R
-import com.android.wm.shell.common.split.SplitScreenConstants
+import com.android.wm.shell.shared.split.SplitScreenConstants
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
index e3d22342cc9b..9590ccdc3b97 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
@@ -30,7 +30,7 @@ import android.widget.Button
import androidx.core.animation.doOnEnd
import androidx.core.view.children
import com.android.wm.shell.R
-import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.animation.Interpolators
/** Animates the Handle Menu opening. */
class HandleMenuAnimator(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
index 095d33736595..114c33114421 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
@@ -59,10 +59,10 @@ import androidx.compose.ui.graphics.toArgb
import androidx.core.animation.addListener
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
-import com.android.wm.shell.animation.Interpolators.EMPHASIZED_DECELERATE
-import com.android.wm.shell.animation.Interpolators.FAST_OUT_LINEAR_IN
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.shared.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.wm.shell.shared.animation.Interpolators.FAST_OUT_LINEAR_IN
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.OPACITY_12
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
index 753723cd73d6..510032ba4480 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
@@ -31,7 +31,7 @@ import android.view.WindowManager
import android.widget.ImageButton
import com.android.window.flags.Flags
import com.android.wm.shell.R
-import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.animation.Interpolators
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
/**
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 311b1c5ffd21..90e3f7fdb973 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -83,10 +83,10 @@ import com.android.internal.util.test.FakeSettingsProvider;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
+import com.android.wm.shell.shared.ShellSharedConstants;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.sysui.ShellSharedConstants;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
index 654d7a8ecf91..f8f0db930e6c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -43,6 +43,7 @@ import android.view.inputmethod.ImeTracker;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
import org.junit.Before;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index cfe8e07aa6e5..09fcd8b02010 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -19,9 +19,9 @@ package com.android.wm.shell.common.split;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_END_AND_DISMISS;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_START_AND_DISMISS;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_END_AND_DISMISS;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_START_AND_DISMISS;
import static com.google.common.truth.Truth.assertThat;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIComponentTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIComponentTest.kt
new file mode 100644
index 000000000000..2c203c466c6e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIComponentTest.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2024 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.compatui.impl
+
+import android.app.ActivityManager
+import android.graphics.Point
+import android.testing.AndroidTestingRunner
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.compatui.api.CompatUIComponent
+import com.android.wm.shell.compatui.api.CompatUIComponentState
+import com.android.wm.shell.compatui.api.CompatUIInfo
+import com.android.wm.shell.compatui.api.CompatUIState
+import junit.framework.Assert.assertEquals
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+/**
+ * Tests for {@link CompatUIComponent}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:CompatUIComponentTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class CompatUIComponentTest : ShellTestCase() {
+
+ private lateinit var component: CompatUIComponent
+ private lateinit var layout: FakeCompatUILayout
+ private lateinit var spec: FakeCompatUISpec
+ private lateinit var state: CompatUIState
+ private lateinit var info: CompatUIInfo
+ private lateinit var syncQueue: SyncTransactionQueue
+ private lateinit var displayLayout: DisplayLayout
+ private lateinit var view: View
+ private lateinit var position: Point
+ private lateinit var componentState: CompatUIComponentState
+
+ @JvmField
+ @Rule
+ val compatUIHandlerRule: CompatUIHandlerRule = CompatUIHandlerRule()
+
+ @Before
+ fun setUp() {
+ state = CompatUIState()
+ view = View(mContext)
+ position = Point(123, 456)
+ layout = FakeCompatUILayout(viewBuilderReturn = view, positionBuilderReturn = position)
+ spec = FakeCompatUISpec("comp", layout = layout)
+ info = testCompatUIInfo()
+ syncQueue = mock<SyncTransactionQueue>()
+ displayLayout = mock<DisplayLayout>()
+ component =
+ CompatUIComponent(spec.getSpec(),
+ "compId",
+ mContext,
+ state,
+ info,
+ syncQueue,
+ displayLayout)
+ componentState = object : CompatUIComponentState {}
+ state.registerUIComponent("compId", component, componentState)
+ }
+
+ @Test
+ fun `when initLayout is invoked spec fields are used`() {
+ compatUIHandlerRule.postBlocking {
+ component.initLayout(info)
+ }
+ with(layout) {
+ assertViewBuilderInvocation(1)
+ assertEquals(info, lastViewBuilderCompatUIInfo)
+ assertEquals(componentState, lastViewBuilderCompState)
+ assertViewBinderInvocation(0)
+ assertPositionFactoryInvocation(1)
+ assertEquals(info, lastPositionFactoryCompatUIInfo)
+ assertEquals(view, lastPositionFactoryView)
+ assertEquals(componentState, lastPositionFactoryCompState)
+ assertEquals(state.sharedState, lastPositionFactorySharedState)
+ }
+ }
+
+ @Test
+ fun `when update is invoked only position and binder spec fields are used`() {
+ compatUIHandlerRule.postBlocking {
+ component.initLayout(info)
+ layout.resetState()
+ component.update(info)
+ }
+ with(layout) {
+ assertViewBuilderInvocation(0)
+ assertViewBinderInvocation(1)
+ assertPositionFactoryInvocation(1)
+ }
+ }
+
+ private fun testCompatUIInfo(): CompatUIInfo {
+ val taskInfo = ActivityManager.RunningTaskInfo()
+ taskInfo.taskId = 1
+ return CompatUIInfo(taskInfo, null)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIHandlerRule.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIHandlerRule.kt
new file mode 100644
index 000000000000..4b8b65c784e9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIHandlerRule.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2024 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.compatui.impl
+
+import android.os.HandlerThread
+import java.util.concurrent.CountDownLatch
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Utility {@link TestRule} to manage Handlers in Compat UI tests.
+ */
+class CompatUIHandlerRule : TestRule {
+
+ private lateinit var handler: HandlerThread
+
+ /**
+ * Makes the HandlerThread available during the test
+ */
+ override fun apply(base: Statement?, description: Description?): Statement {
+ handler = HandlerThread("CompatUIHandler").apply {
+ start()
+ }
+ return object : Statement() {
+ @Throws(Throwable::class)
+ override fun evaluate() {
+ try {
+ base!!.evaluate()
+ } finally {
+ handler.quitSafely()
+ }
+ }
+ }
+ }
+
+ /**
+ * Posts a {@link Runnable} for the Handler
+ * @param runnable The Runnable to execute
+ */
+ fun postBlocking(runnable: Runnable) {
+ val countDown = CountDownLatch(/* count = */ 1)
+ handler.threadHandler.post{
+ runnable.run()
+ countDown.countDown()
+ }
+ try {
+ countDown.await()
+ } catch (e: InterruptedException) {
+ // No-op
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIStateUtil.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIStateUtil.kt
index 43bd41275daa..4f0e5b9cbfbf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIStateUtil.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/CompatUIStateUtil.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.compatui.impl
import com.android.wm.shell.compatui.api.CompatUIComponentState
-import com.android.wm.shell.compatui.api.CompatUISpec
import com.android.wm.shell.compatui.api.CompatUIState
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandlerTest.kt
index 8136074b7aa6..66852ad5ab5d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIHandlerTest.kt
@@ -18,13 +18,21 @@ package com.android.wm.shell.compatui.impl
import android.app.ActivityManager
import android.testing.AndroidTestingRunner
+import android.view.View
import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.compatui.api.CompatUIComponentState
import com.android.wm.shell.compatui.api.CompatUIInfo
import com.android.wm.shell.compatui.api.CompatUIState
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
/**
* Tests for {@link DefaultCompatUIHandler}.
@@ -34,20 +42,37 @@ import org.junit.runner.RunWith
*/
@RunWith(AndroidTestingRunner::class)
@SmallTest
-class DefaultCompatUIHandlerTest {
+class DefaultCompatUIHandlerTest : ShellTestCase() {
+
+ @JvmField
+ @Rule
+ val compatUIHandlerRule: CompatUIHandlerRule = CompatUIHandlerRule()
lateinit var compatUIRepository: FakeCompatUIRepository
lateinit var compatUIHandler: DefaultCompatUIHandler
lateinit var compatUIState: CompatUIState
lateinit var fakeIdGenerator: FakeCompatUIComponentIdGenerator
+ lateinit var syncQueue: SyncTransactionQueue
+ lateinit var displayController: DisplayController
+ lateinit var shellExecutor: TestShellExecutor
+ lateinit var componentFactory: FakeCompatUIComponentFactory
@Before
fun setUp() {
+ shellExecutor = TestShellExecutor()
compatUIRepository = FakeCompatUIRepository()
compatUIState = CompatUIState()
fakeIdGenerator = FakeCompatUIComponentIdGenerator("compId")
- compatUIHandler = DefaultCompatUIHandler(compatUIRepository, compatUIState,
- fakeIdGenerator)
+ syncQueue = mock<SyncTransactionQueue>()
+ displayController = mock<DisplayController>()
+ componentFactory = FakeCompatUIComponentFactory(mContext, syncQueue, displayController)
+ compatUIHandler =
+ DefaultCompatUIHandler(
+ compatUIRepository,
+ compatUIState,
+ fakeIdGenerator,
+ componentFactory,
+ shellExecutor)
}
@Test
@@ -57,12 +82,18 @@ class DefaultCompatUIHandlerTest {
creationReturn = false,
removalReturn = false
)
- val fakeCompatUISpec = FakeCompatUISpec("one", fakeLifecycle).getSpec()
+ val fakeCompatUILayout = FakeCompatUILayout(viewBuilderReturn = View(mContext))
+ val fakeCompatUISpec =
+ FakeCompatUISpec(name = "one",
+ lifecycle = fakeLifecycle,
+ layout = fakeCompatUILayout).getSpec()
compatUIRepository.addSpec(fakeCompatUISpec)
val generatedId = fakeIdGenerator.generatedComponentId
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeIdGenerator.assertGenerateInvocations(1)
fakeLifecycle.assertCreationInvocation(1)
@@ -71,7 +102,9 @@ class DefaultCompatUIHandlerTest {
compatUIState.assertHasNoStateFor(generatedId)
compatUIState.assertHasNoComponentFor(generatedId)
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeLifecycle.assertCreationInvocation(2)
fakeLifecycle.assertRemovalInvocation(0)
fakeLifecycle.assertInitialStateInvocation(0)
@@ -86,12 +119,18 @@ class DefaultCompatUIHandlerTest {
creationReturn = true,
removalReturn = false
)
- val fakeCompatUISpec = FakeCompatUISpec("one", fakeLifecycle).getSpec()
+ val fakeCompatUILayout = FakeCompatUILayout(viewBuilderReturn = View(mContext))
+ val fakeCompatUISpec =
+ FakeCompatUISpec(name = "one",
+ lifecycle = fakeLifecycle,
+ layout = fakeCompatUILayout).getSpec()
compatUIRepository.addSpec(fakeCompatUISpec)
val generatedId = fakeIdGenerator.generatedComponentId
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeLifecycle.assertCreationInvocation(1)
fakeLifecycle.assertRemovalInvocation(0)
@@ -99,7 +138,9 @@ class DefaultCompatUIHandlerTest {
compatUIState.assertHasNoStateFor(generatedId)
compatUIState.assertHasComponentFor(generatedId)
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeLifecycle.assertCreationInvocation(1)
fakeLifecycle.assertRemovalInvocation(1)
@@ -117,12 +158,18 @@ class DefaultCompatUIHandlerTest {
removalReturn = false,
initialState = { _, _ -> fakeComponentState }
)
- val fakeCompatUISpec = FakeCompatUISpec("one", fakeLifecycle).getSpec()
+ val fakeCompatUILayout = FakeCompatUILayout(viewBuilderReturn = View(mContext))
+ val fakeCompatUISpec =
+ FakeCompatUISpec(name = "one",
+ lifecycle = fakeLifecycle,
+ layout = fakeCompatUILayout).getSpec()
compatUIRepository.addSpec(fakeCompatUISpec)
val generatedId = fakeIdGenerator.generatedComponentId
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeLifecycle.assertCreationInvocation(1)
fakeLifecycle.assertRemovalInvocation(0)
@@ -130,7 +177,9 @@ class DefaultCompatUIHandlerTest {
compatUIState.assertHasStateEqualsTo(generatedId, fakeComponentState)
compatUIState.assertHasComponentFor(generatedId)
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeLifecycle.assertCreationInvocation(1)
fakeLifecycle.assertRemovalInvocation(1)
@@ -148,12 +197,18 @@ class DefaultCompatUIHandlerTest {
removalReturn = true,
initialState = { _, _ -> fakeComponentState }
)
- val fakeCompatUISpec = FakeCompatUISpec("one", fakeLifecycle).getSpec()
+ val fakeCompatUILayout = FakeCompatUILayout(viewBuilderReturn = View(mContext))
+ val fakeCompatUISpec =
+ FakeCompatUISpec(name = "one",
+ lifecycle = fakeLifecycle,
+ layout = fakeCompatUILayout).getSpec()
compatUIRepository.addSpec(fakeCompatUISpec)
val generatedId = fakeIdGenerator.generatedComponentId
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeLifecycle.assertCreationInvocation(1)
fakeLifecycle.assertRemovalInvocation(0)
@@ -161,7 +216,9 @@ class DefaultCompatUIHandlerTest {
compatUIState.assertHasStateEqualsTo(generatedId, fakeComponentState)
compatUIState.assertHasComponentFor(generatedId)
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeLifecycle.assertCreationInvocation(1)
fakeLifecycle.assertRemovalInvocation(1)
@@ -177,17 +234,56 @@ class DefaultCompatUIHandlerTest {
creationReturn = true,
removalReturn = true,
)
- val fakeCompatUISpec = FakeCompatUISpec("one", fakeLifecycle).getSpec()
+ val fakeCompatUILayout = FakeCompatUILayout(viewBuilderReturn = View(mContext))
+ val fakeCompatUISpec = FakeCompatUISpec("one", fakeLifecycle,
+ fakeCompatUILayout).getSpec()
compatUIRepository.addSpec(fakeCompatUISpec)
// Component creation
fakeIdGenerator.assertGenerateInvocations(0)
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeIdGenerator.assertGenerateInvocations(1)
- compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
fakeIdGenerator.assertGenerateInvocations(2)
}
+ @Test
+ fun `viewBuilder and viewBinder invoked if component is created and released when destroyed`() {
+ // We add a spec to the repository
+ val fakeLifecycle = FakeCompatUILifecyclePredicates(
+ creationReturn = true,
+ removalReturn = true,
+ )
+ val fakeCompatUILayout = FakeCompatUILayout(viewBuilderReturn = View(mContext))
+ val fakeCompatUISpec = FakeCompatUISpec("one", fakeLifecycle,
+ fakeCompatUILayout).getSpec()
+ compatUIRepository.addSpec(fakeCompatUISpec)
+
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
+ shellExecutor.flushAll()
+ componentFactory.assertInvocations(1)
+ fakeCompatUILayout.assertViewBuilderInvocation(1)
+ fakeCompatUILayout.assertViewBinderInvocation(1)
+ fakeCompatUILayout.assertViewReleaserInvocation(0)
+
+ compatUIHandlerRule.postBlocking {
+ compatUIHandler.onCompatInfoChanged(testCompatUIInfo())
+ }
+ shellExecutor.flushAll()
+
+ componentFactory.assertInvocations(1)
+ fakeCompatUILayout.assertViewBuilderInvocation(1)
+ fakeCompatUILayout.assertViewBinderInvocation(1)
+ fakeCompatUILayout.assertViewReleaserInvocation(1)
+ }
+
+
private fun testCompatUIInfo(): CompatUIInfo {
val taskInfo = ActivityManager.RunningTaskInfo()
taskInfo.taskId = 1
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIRepositoryTest.kt
index e35acb2ca0e9..319122d1e051 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIRepositoryTest.kt
@@ -16,9 +16,13 @@
package com.android.wm.shell.compatui.impl
+
+import android.graphics.Point
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.testing.AndroidTestingRunner
+import android.view.View
import androidx.test.filters.SmallTest
+import com.android.wm.shell.compatui.api.CompatUILayout
import com.android.wm.shell.compatui.api.CompatUILifecyclePredicates
import com.android.wm.shell.compatui.api.CompatUIRepository
import com.android.wm.shell.compatui.api.CompatUISpec
@@ -89,8 +93,14 @@ class DefaultCompatUIRepositoryTest {
}
private fun specById(name: String): CompatUISpec =
- CompatUISpec(name = name, lifecycle = CompatUILifecyclePredicates(
- creationPredicate = { _, _ -> true },
- removalPredicate = { _, _, _ -> true }
- ))
+ CompatUISpec(name = name,
+ lifecycle = CompatUILifecyclePredicates(
+ creationPredicate = { _, _ -> true },
+ removalPredicate = { _, _, _ -> true }
+ ),
+ layout = CompatUILayout(
+ viewBuilder = { ctx, _, _ -> View(ctx) },
+ positionFactory = { _, _, _, _ -> Point(0, 0) }
+ )
+ )
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUIComponentFactory.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUIComponentFactory.kt
new file mode 100644
index 000000000000..782add84a36c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUIComponentFactory.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 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.compatui.impl
+
+import android.content.Context
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.compatui.api.CompatUIComponent
+import com.android.wm.shell.compatui.api.CompatUIComponentFactory
+import com.android.wm.shell.compatui.api.CompatUIInfo
+import com.android.wm.shell.compatui.api.CompatUISpec
+import com.android.wm.shell.compatui.api.CompatUIState
+import junit.framework.Assert.assertEquals
+
+/**
+ * Fake {@link CompatUIComponentFactory} implementation.
+ */
+class FakeCompatUIComponentFactory(
+ private val context: Context,
+ private val syncQueue: SyncTransactionQueue,
+ private val displayController: DisplayController
+) : CompatUIComponentFactory {
+
+ var lastSpec: CompatUISpec? = null
+ var lastCompId: String? = null
+ var lastState: CompatUIState? = null
+ var lastInfo: CompatUIInfo? = null
+
+ var numberInvocations = 0
+
+ override fun create(
+ spec: CompatUISpec,
+ compId: String,
+ state: CompatUIState,
+ compatUIInfo: CompatUIInfo
+ ): CompatUIComponent {
+ lastSpec = spec
+ lastCompId = compId
+ lastState = state
+ lastInfo = compatUIInfo
+ numberInvocations++
+ return CompatUIComponent(
+ spec,
+ compId,
+ context,
+ state,
+ compatUIInfo,
+ syncQueue,
+ displayController.getDisplayLayout(compatUIInfo.taskInfo.displayId)
+ )
+ }
+
+ fun assertInvocations(expected: Int) =
+ assertEquals(expected, numberInvocations)
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUILayout.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUILayout.kt
new file mode 100644
index 000000000000..d7a178ab69e8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUILayout.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 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.compatui.impl
+
+import android.content.Context
+import android.graphics.Point
+import android.view.View
+import com.android.wm.shell.compatui.api.CompatUIComponentState
+import com.android.wm.shell.compatui.api.CompatUIInfo
+import com.android.wm.shell.compatui.api.CompatUILayout
+import com.android.wm.shell.compatui.api.CompatUISharedState
+import junit.framework.Assert.assertEquals
+
+/**
+ * Fake class for {@link CompatUILayout}
+ */
+class FakeCompatUILayout(
+ private val zOrderReturn: Int = 0,
+ private val layoutParamFlagsReturn: Int = 0,
+ private val viewBuilderReturn: View,
+ private val positionBuilderReturn: Point = Point(0, 0)
+) {
+
+ var viewBuilderInvocation = 0
+ var viewBinderInvocation = 0
+ var positionFactoryInvocation = 0
+ var viewReleaserInvocation = 0
+
+ var lastViewBuilderContext: Context? = null
+ var lastViewBuilderCompatUIInfo: CompatUIInfo? = null
+ var lastViewBuilderCompState: CompatUIComponentState? = null
+ var lastViewBinderView: View? = null
+ var lastViewBinderCompatUIInfo: CompatUIInfo? = null
+ var lastViewBinderSharedState: CompatUISharedState? = null
+ var lastViewBinderCompState: CompatUIComponentState? = null
+ var lastPositionFactoryView: View? = null
+ var lastPositionFactoryCompatUIInfo: CompatUIInfo? = null
+ var lastPositionFactorySharedState: CompatUISharedState? = null
+ var lastPositionFactoryCompState: CompatUIComponentState? = null
+
+ fun getLayout() = CompatUILayout(
+ zOrder = zOrderReturn,
+ layoutParamFlags = layoutParamFlagsReturn,
+ viewBuilder = { ctx, info, componentState ->
+ lastViewBuilderContext = ctx
+ lastViewBuilderCompatUIInfo = info
+ lastViewBuilderCompState = componentState
+ viewBuilderInvocation++
+ viewBuilderReturn
+ },
+ viewBinder = { view, info, sharedState, componentState ->
+ lastViewBinderView = view
+ lastViewBinderCompatUIInfo = info
+ lastViewBinderCompState = componentState
+ lastViewBinderSharedState = sharedState
+ viewBinderInvocation++
+ },
+ positionFactory = { view, info, sharedState, componentState ->
+ lastPositionFactoryView = view
+ lastPositionFactoryCompatUIInfo = info
+ lastPositionFactoryCompState = componentState
+ lastPositionFactorySharedState = sharedState
+ positionFactoryInvocation++
+ positionBuilderReturn
+ },
+ viewReleaser = { viewReleaserInvocation++ }
+ )
+
+ fun assertViewBuilderInvocation(expected: Int) =
+ assertEquals(expected, viewBuilderInvocation)
+
+ fun assertViewBinderInvocation(expected: Int) =
+ assertEquals(expected, viewBinderInvocation)
+
+ fun assertViewReleaserInvocation(expected: Int) =
+ assertEquals(expected, viewReleaserInvocation)
+
+ fun assertPositionFactoryInvocation(expected: Int) =
+ assertEquals(expected, positionFactoryInvocation)
+
+ fun resetState() {
+ viewBuilderInvocation = 0
+ viewBinderInvocation = 0
+ positionFactoryInvocation = 0
+ viewReleaserInvocation = 0
+ lastViewBuilderCompatUIInfo = null
+ lastViewBuilderCompState = null
+ lastViewBinderView = null
+ lastViewBinderCompatUIInfo = null
+ lastViewBinderSharedState = null
+ lastViewBinderCompState = null
+ lastPositionFactoryView = null
+ lastPositionFactoryCompatUIInfo = null
+ lastPositionFactorySharedState = null
+ lastPositionFactoryCompState = null
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUILifecyclePredicates.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUILifecyclePredicates.kt
index bbaa2db07aaa..f742ca32e63d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUILifecyclePredicates.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUILifecyclePredicates.kt
@@ -26,8 +26,8 @@ import junit.framework.Assert.assertEquals
* Fake class for {@link CompatUILifecycle}
*/
class FakeCompatUILifecyclePredicates(
- private val creationReturn: Boolean,
- private val removalReturn: Boolean,
+ private val creationReturn: Boolean = false,
+ private val removalReturn: Boolean = false,
private val initialState: (
CompatUIInfo,
CompatUISharedState
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUISpec.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUISpec.kt
index 1ecd52e2b3ff..0912bf115666 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUISpec.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/FakeCompatUISpec.kt
@@ -23,10 +23,13 @@ import com.android.wm.shell.compatui.api.CompatUISpec
*/
class FakeCompatUISpec(
val name: String,
- val lifecycle: FakeCompatUILifecyclePredicates
+ val lifecycle: FakeCompatUILifecyclePredicates = FakeCompatUILifecyclePredicates(),
+ val layout: FakeCompatUILayout
) {
fun getSpec(): CompatUISpec = CompatUISpec(
name = name,
- lifecycle = lifecycle.getLifecycle()
+ log = {str -> android.util.Log.d("COMPAT_UI_TEST", str)},
+ lifecycle = lifecycle.getLifecycle(),
+ layout = layout.getLayout()
)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
index 2dea43b508ae..f558e87c4ed7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
@@ -17,9 +17,6 @@
package com.android.wm.shell.desktopmode
import android.app.ActivityManager.RunningTaskInfo
-import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
-import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
-import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
import android.graphics.Rect
import android.graphics.Region
import android.testing.AndroidTestingRunner
@@ -38,6 +35,11 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.kotlin.whenever
+/**
+ * Test class for [DesktopModeVisualIndicator]
+ *
+ * Usage: atest WMShellUnitTests:DesktopModeVisualIndicatorTest
+ */
@SmallTest
@RunWith(AndroidTestingRunner::class)
class DesktopModeVisualIndicatorTest : ShellTestCase() {
@@ -52,8 +54,6 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
@Before
fun setUp() {
- visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo, displayController,
- context, taskSurface, taskDisplayAreaOrganizer)
whenever(displayLayout.width()).thenReturn(DISPLAY_BOUNDS.width())
whenever(displayLayout.height()).thenReturn(DISPLAY_BOUNDS.height())
whenever(displayLayout.stableInsets()).thenReturn(STABLE_INSETS)
@@ -61,41 +61,52 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
@Test
fun testFullscreenRegionCalculation() {
- var testRegion = visualIndicator.calculateFullscreenRegion(displayLayout,
- WINDOWING_MODE_FULLSCREEN, CAPTION_HEIGHT)
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
+ var testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, CAPTION_HEIGHT)
assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 2400, 2 * STABLE_INSETS.top))
- testRegion = visualIndicator.calculateFullscreenRegion(displayLayout,
- WINDOWING_MODE_FREEFORM, CAPTION_HEIGHT)
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FREEFORM)
+ testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, CAPTION_HEIGHT)
val transitionHeight = context.resources.getDimensionPixelSize(
R.dimen.desktop_mode_transition_region_thickness)
val toFullscreenScale = mContext.resources.getFloat(
R.dimen.desktop_mode_fullscreen_region_scale
)
val toFullscreenWidth = displayLayout.width() * toFullscreenScale
-
assertThat(testRegion.bounds).isEqualTo(Rect(
(DISPLAY_BOUNDS.width() / 2f - toFullscreenWidth / 2f).toInt(),
-50,
(DISPLAY_BOUNDS.width() / 2f + toFullscreenWidth / 2f).toInt(),
transitionHeight))
- testRegion = visualIndicator.calculateFullscreenRegion(displayLayout,
- WINDOWING_MODE_MULTI_WINDOW, CAPTION_HEIGHT)
+
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_SPLIT)
+ testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, CAPTION_HEIGHT)
assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 2400, 2 * STABLE_INSETS.top))
+
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.DRAGGED_INTENT)
+ testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, CAPTION_HEIGHT)
+ assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 2400, transitionHeight))
}
@Test
fun testSplitLeftRegionCalculation() {
val transitionHeight = context.resources.getDimensionPixelSize(
R.dimen.desktop_mode_split_from_desktop_height)
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
var testRegion = visualIndicator.calculateSplitLeftRegion(displayLayout,
- WINDOWING_MODE_FULLSCREEN, TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 32, 1600))
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FREEFORM)
testRegion = visualIndicator.calculateSplitLeftRegion(displayLayout,
- WINDOWING_MODE_FREEFORM, TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
assertThat(testRegion.bounds).isEqualTo(Rect(0, transitionHeight, 32, 1600))
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_SPLIT)
testRegion = visualIndicator.calculateSplitLeftRegion(displayLayout,
- WINDOWING_MODE_MULTI_WINDOW, TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 32, 1600))
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.DRAGGED_INTENT)
+ testRegion = visualIndicator.calculateSplitLeftRegion(displayLayout,
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 32, 1600))
}
@@ -103,27 +114,35 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
fun testSplitRightRegionCalculation() {
val transitionHeight = context.resources.getDimensionPixelSize(
R.dimen.desktop_mode_split_from_desktop_height)
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
var testRegion = visualIndicator.calculateSplitRightRegion(displayLayout,
- WINDOWING_MODE_FULLSCREEN, TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
assertThat(testRegion.bounds).isEqualTo(Rect(2368, -50, 2400, 1600))
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FREEFORM)
testRegion = visualIndicator.calculateSplitRightRegion(displayLayout,
- WINDOWING_MODE_FREEFORM, TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
assertThat(testRegion.bounds).isEqualTo(Rect(2368, transitionHeight, 2400, 1600))
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_SPLIT)
+ testRegion = visualIndicator.calculateSplitRightRegion(displayLayout,
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ assertThat(testRegion.bounds).isEqualTo(Rect(2368, -50, 2400, 1600))
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.DRAGGED_INTENT)
testRegion = visualIndicator.calculateSplitRightRegion(displayLayout,
- WINDOWING_MODE_MULTI_WINDOW, TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
assertThat(testRegion.bounds).isEqualTo(Rect(2368, -50, 2400, 1600))
}
@Test
fun testToDesktopRegionCalculation() {
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
val fullscreenRegion = visualIndicator.calculateFullscreenRegion(displayLayout,
- WINDOWING_MODE_FULLSCREEN, CAPTION_HEIGHT)
+ CAPTION_HEIGHT)
val splitLeftRegion = visualIndicator.calculateSplitLeftRegion(displayLayout,
- WINDOWING_MODE_FULLSCREEN, TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
val splitRightRegion = visualIndicator.calculateSplitRightRegion(displayLayout,
- WINDOWING_MODE_FULLSCREEN, TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
+ TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
val desktopRegion = visualIndicator.calculateToDesktopRegion(displayLayout,
- WINDOWING_MODE_FULLSCREEN, splitLeftRegion, splitRightRegion, fullscreenRegion)
+ splitLeftRegion, splitRightRegion, fullscreenRegion)
var testRegion = Region()
testRegion.union(DISPLAY_BOUNDS)
testRegion.op(splitLeftRegion, Region.Op.DIFFERENCE)
@@ -132,6 +151,11 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
assertThat(desktopRegion).isEqualTo(testRegion)
}
+ private fun createVisualIndicator(dragStartState: DesktopModeVisualIndicator.DragStartState) {
+ visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo, displayController,
+ context, taskSurface, taskDisplayAreaOrganizer, dragStartState)
+ }
+
companion object {
private const val TRANSITION_AREA_WIDTH = 32
private const val CAPTION_HEIGHT = 50
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index a630cef99474..a841e168af18 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -84,7 +84,6 @@ import com.android.wm.shell.common.MultiInstanceHelper
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource.UNKNOWN
-import com.android.wm.shell.common.split.SplitScreenConstants
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
@@ -95,6 +94,7 @@ import com.android.wm.shell.recents.RecentTasksController
import com.android.wm.shell.recents.RecentsTransitionHandler
import com.android.wm.shell.recents.RecentsTransitionStateListener
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.shared.split.SplitScreenConstants
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
@@ -160,6 +160,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Mock lateinit var mReturnToDragStartAnimator: ReturnToDragStartAnimator
@Mock lateinit var exitDesktopTransitionHandler: ExitDesktopTaskTransitionHandler
@Mock lateinit var enterDesktopTransitionHandler: EnterDesktopTaskTransitionHandler
+ @Mock lateinit var dragAndDropTransitionHandler: DesktopModeDragAndDropTransitionHandler
@Mock
lateinit var toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler
@Mock lateinit var dragToDesktopTransitionHandler: DragToDesktopTransitionHandler
@@ -254,6 +255,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
mReturnToDragStartAnimator,
enterDesktopTransitionHandler,
exitDesktopTransitionHandler,
+ dragAndDropTransitionHandler,
toggleResizeDesktopTaskTransitionHandler,
dragToDesktopTransitionHandler,
taskRepository,
@@ -867,6 +869,18 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ fun addMoveToDesktopChanges_landscapeDevice_portraitResizableApp_aspectRatioOverridden() {
+ setUpLandscapeDisplay()
+ val task = setUpFullscreenTask(screenOrientation = SCREEN_ORIENTATION_PORTRAIT,
+ shouldLetterbox = true, aspectRatioOverrideApplied = true)
+ val wct = WindowContainerTransaction()
+ controller.addMoveToDesktopChanges(wct, task)
+
+ assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_PORTRAIT_BOUNDS)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
fun addMoveToDesktopChanges_portraitDevice_userFullscreenOverride_defaultPortraitBounds() {
setUpPortraitDisplay()
val task = setUpFullscreenTask(enableUserFullscreenOverride = true)
@@ -888,6 +902,19 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ fun addMoveToDesktopChanges_portraitDevice_landscapeResizableApp_aspectRatioOverridden() {
+ setUpPortraitDisplay()
+ val task = setUpFullscreenTask(screenOrientation = SCREEN_ORIENTATION_LANDSCAPE,
+ deviceOrientation = ORIENTATION_PORTRAIT,
+ shouldLetterbox = true, aspectRatioOverrideApplied = true)
+ val wct = WindowContainerTransaction()
+ controller.addMoveToDesktopChanges(wct, task)
+
+ assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_LANDSCAPE_BOUNDS)
+ }
+
+ @Test
fun moveToDesktop_tdaFullscreen_windowingModeSetToFreeform() {
val task = setUpFullscreenTask()
val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
@@ -2237,27 +2264,6 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
- fun desktopTasksVisibilityChange_visible_setLaunchAdjacentDisabled() {
- val task = setUpFreeformTask()
- clearInvocations(launchAdjacentController)
-
- markTaskVisible(task)
- shellExecutor.flushAll()
- verify(launchAdjacentController).launchAdjacentEnabled = false
- }
-
- @Test
- fun desktopTasksVisibilityChange_invisible_setLaunchAdjacentEnabled() {
- val task = setUpFreeformTask()
- markTaskVisible(task)
- clearInvocations(launchAdjacentController)
-
- markTaskHidden(task)
- shellExecutor.flushAll()
- verify(launchAdjacentController).launchAdjacentEnabled = true
- }
-
- @Test
fun moveFocusedTaskToDesktop_fullscreenTaskIsMovedToDesktop() {
val task1 = setUpFullscreenTask()
val task2 = setUpFullscreenTask()
@@ -2362,7 +2368,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_landscapeDevice_resizable_undefinedOrientation_defaultLandscapeBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task = setUpFullscreenTask()
@@ -2378,7 +2384,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_landscapeDevice_resizable_landscapeOrientation_defaultLandscapeBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task = setUpFullscreenTask(screenOrientation = SCREEN_ORIENTATION_LANDSCAPE)
@@ -2394,7 +2400,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_landscapeDevice_resizable_portraitOrientation_resizablePortraitBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task =
@@ -2411,7 +2417,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_landscapeDevice_unResizable_landscapeOrientation_defaultLandscapeBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task =
@@ -2428,7 +2434,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_landscapeDevice_unResizable_portraitOrientation_unResizablePortraitBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task =
@@ -2448,7 +2454,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_portraitDevice_resizable_undefinedOrientation_defaultPortraitBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task = setUpFullscreenTask(deviceOrientation = ORIENTATION_PORTRAIT)
@@ -2464,7 +2470,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_portraitDevice_resizable_portraitOrientation_defaultPortraitBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task =
@@ -2483,7 +2489,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_portraitDevice_resizable_landscapeOrientation_resizableLandscapeBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task =
@@ -2503,7 +2509,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_portraitDevice_unResizable_portraitOrientation_defaultPortraitBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task =
@@ -2523,7 +2529,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun dragToDesktop_portraitDevice_unResizable_landscapeOrientation_unResizableLandscapeBounds() {
val spyController = spy(controller)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
val task =
@@ -2580,7 +2586,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val currentDragBounds = Rect(100, 200, 500, 1000)
whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
- whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull(), anyOrNull()))
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
.thenReturn(DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR)
spyController.onDragPositioningEnd(
@@ -2896,7 +2902,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
shouldLetterbox: Boolean = false,
gravity: Int = Gravity.NO_GRAVITY,
enableUserFullscreenOverride: Boolean = false,
- enableSystemFullscreenOverride: Boolean = false
+ enableSystemFullscreenOverride: Boolean = false,
+ aspectRatioOverrideApplied: Boolean = false
): RunningTaskInfo {
val task = createFullscreenTask(displayId)
val activityInfo = ActivityInfo()
@@ -2911,6 +2918,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
appCompatTaskInfo.isSystemFullscreenOverrideEnabled = enableSystemFullscreenOverride
if (shouldLetterbox) {
+ appCompatTaskInfo.setHasMinAspectRatioOverride(aspectRatioOverrideApplied)
if (deviceOrientation == ORIENTATION_LANDSCAPE &&
screenOrientation == SCREEN_ORIENTATION_PORTRAIT) {
// Letterbox to portrait size
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index c97bcfb1a4cb..16a234b9e2f2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -20,8 +20,8 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestRunningTaskInfoBuilder
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 97fa8d6ceca9..645b296930f8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -27,9 +27,9 @@ import static android.content.ClipDescription.MIMETYPE_TEXT_INTENT;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
index 6ec6bed860bd..763d0153071e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
+import android.view.SurfaceControl;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -35,6 +36,7 @@ import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
+import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.sysui.ShellInit;
@@ -65,7 +67,11 @@ public final class FreeformTaskListenerTests extends ShellTestCase {
@Mock
private WindowDecorViewModel mWindowDecorViewModel;
@Mock
+ private SurfaceControl mMockSurfaceControl;
+ @Mock
private DesktopModeTaskRepository mDesktopModeTaskRepository;
+ @Mock
+ private LaunchAdjacentController mLaunchAdjacentController;
private FreeformTaskListener mFreeformTaskListener;
private StaticMockitoSession mMockitoSession;
@@ -80,6 +86,7 @@ public final class FreeformTaskListenerTests extends ShellTestCase {
mShellInit,
mTaskOrganizer,
Optional.of(mDesktopModeTaskRepository),
+ mLaunchAdjacentController,
mWindowDecorViewModel);
}
@@ -107,6 +114,31 @@ public final class FreeformTaskListenerTests extends ShellTestCase {
.addOrMoveFreeformTaskToTop(fullscreenTask.displayId, fullscreenTask.taskId);
}
+ @Test
+ public void testVisibilityTaskChanged_visible_setLaunchAdjacentDisabled() {
+ ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ task.isVisible = true;
+
+ mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
+
+ verify(mLaunchAdjacentController).setLaunchAdjacentEnabled(false);
+ }
+
+ @Test
+ public void testVisibilityTaskChanged_NotVisible_setLaunchAdjacentEnabled() {
+ ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ task.isVisible = true;
+
+ mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
+
+ task.isVisible = false;
+ mFreeformTaskListener.onTaskInfoChanged(task);
+
+ verify(mLaunchAdjacentController).setLaunchAdjacentEnabled(true);
+ }
+
@After
public void tearDown() {
mMockitoSession.finishMocking();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 8ad3d2a72617..7d063a0a773f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -48,10 +48,10 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.shared.ShellSharedConstants;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.sysui.ShellSharedConstants;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 75d21457b60b..6ddb6781c80c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -67,10 +67,10 @@ import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
+import com.android.wm.shell.shared.ShellSharedConstants;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.sysui.ShellSharedConstants;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
index 15b73c541ed8..6736593bba5b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.recents
import android.app.ActivityManager
-import android.app.ActivityManager.RecentTaskInfo
import android.graphics.Rect
import android.os.Parcel
import android.testing.AndroidTestingRunner
@@ -25,7 +24,7 @@ import android.window.IWindowContainerToken
import android.window.WindowContainerToken
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50
+import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50
import com.android.wm.shell.util.GroupedRecentTaskInfo
import com.android.wm.shell.util.GroupedRecentTaskInfo.CREATOR
import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index a0aab2e6c8a4..e1fe4e9054c0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -22,7 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -68,11 +68,11 @@ import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
+import com.android.wm.shell.shared.ShellSharedConstants;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.sysui.ShellSharedConstants;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.SplitBounds;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/SplitBoundsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/SplitBoundsTest.java
index b790aee6fb0e..bfb760b6fc8c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/SplitBoundsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/SplitBoundsTest.java
@@ -1,6 +1,6 @@
package com.android.wm.shell.recents;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/magnetictarget/MagnetizedObjectTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/magnetictarget/MagnetizedObjectTest.kt
index 8bb182de7668..8711ee01601c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/magnetictarget/MagnetizedObjectTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/magnetictarget/MagnetizedObjectTest.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.wm.shell.common.magnetictarget
+package com.android.wm.shell.shared.magnetictarget
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -33,13 +33,13 @@ import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.Mockito
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when`
@TestableLooper.RunWithLooper
@RunWith(AndroidTestingRunner::class)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitScreenConstantsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/split/SplitScreenConstantsTest.kt
index fe261107d65b..19c18be44ab1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitScreenConstantsTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/split/SplitScreenConstantsTest.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.common.split
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.wm.shell.shared.split.SplitScreenConstants
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 1c5d5e963156..9260a07fd945 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -23,8 +23,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
@@ -70,14 +70,14 @@ import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.shared.ShellSharedConstants;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.sysui.ShellSharedConstants;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index 29d3fb4cc04e..aa96c45489dd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -35,9 +35,9 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 1990fe7946e9..abe3dcc1eb80 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -76,9 +76,9 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.transition.DefaultMixedHandler;
import com.android.wm.shell.transition.TestRemoteTransition;
import com.android.wm.shell.transition.TransitionInfoBuilder;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index ff6c7eeb9d1a..0054cb6ccc8c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -19,13 +19,12 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
-import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS;
import static com.google.common.truth.Truth.assertThat;
@@ -69,9 +68,9 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.splitscreen.SplitScreen.SplitScreenListener;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index af6c077303c4..5f7542332c80 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -74,7 +74,7 @@ import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
index ff76a2f13527..7fd1c11e61ae 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
@@ -42,11 +42,11 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.ShellSharedConstants;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.sysui.ShellSharedConstants;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
index 6bc7e499159c..0c18229f38d0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
@@ -48,7 +48,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
import org.junit.After;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
index 0db10ef65a74..d2adae181f7b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
@@ -51,8 +51,8 @@ import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.shared.IHomeTransitionListener;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/MockTransactionPool.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/MockTransactionPool.java
index 574a87ac4b17..a5a27e2568a3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/MockTransactionPool.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/MockTransactionPool.java
@@ -21,7 +21,7 @@ import static org.mockito.Mockito.mock;
import android.view.SurfaceControl;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.util.StubTransaction;
public class MockTransactionPool extends TransactionPool {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 81e6d071045a..7c63fdad660a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -107,12 +107,12 @@ import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.recents.RecentsTransitionHandler;
+import com.android.wm.shell.shared.ShellSharedConstants;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.sysui.ShellSharedConstants;
import com.android.wm.shell.util.StubTransaction;
import org.junit.Before;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldAnimationControllerTest.java
index 8196c5ab08e4..8fe0c386b7fe 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldAnimationControllerTest.java
@@ -35,7 +35,7 @@ import android.view.SurfaceControl.Transaction;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
index acc0bce5cce9..cf2de91bad88 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
@@ -40,7 +40,7 @@ import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.TransitionInfoBuilder;
import com.android.wm.shell.transition.Transitions;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index a734689abe35..4d6b3b907a65 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -56,6 +56,7 @@ import android.view.SurfaceControl
import android.view.SurfaceView
import android.view.View
import android.view.WindowInsets.Type.statusBars
+import android.widget.Toast
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp
import androidx.test.filters.SmallTest
@@ -93,6 +94,8 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopM
import java.util.Optional
import java.util.function.Consumer
import java.util.function.Supplier
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -117,8 +120,7 @@ import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
-import junit.framework.Assert.assertFalse
-import junit.framework.Assert.assertTrue
+
/**
* Tests of [DesktopModeWindowDecorViewModel]
@@ -158,6 +160,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
@Mock private lateinit var mockWindowManager: IWindowManager
@Mock private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
@Mock private lateinit var mockGenericLinksParser: AppToWebGenericLinksParser
+ @Mock private lateinit var mockToast: Toast
private val bgExecutor = TestShellExecutor()
@Mock private lateinit var mockMultiInstanceHelper: MultiInstanceHelper
private lateinit var spyContext: TestableContext
@@ -181,6 +184,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
.strictness(Strictness.LENIENT)
.spyStatic(DesktopModeStatus::class.java)
.spyStatic(DragPositioningCallbackUtility::class.java)
+ .spyStatic(Toast::class.java)
.startMocking()
doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(Mockito.any()) }
@@ -218,6 +222,8 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
whenever(mockDisplayLayout.stableInsets()).thenReturn(STABLE_INSETS)
whenever(mockInputMonitorFactory.create(any(), any())).thenReturn(mockInputMonitor)
+ doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) }
+
// InputChannel cannot be mocked because it passes to InputEventReceiver.
val inputChannels = InputChannel.openInputChannelPair(TAG)
inputChannels.first().dispose()
@@ -614,6 +620,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
verify(mockDesktopTasksController, never())
.snapToHalfScreen(decor.mTaskInfo, currentBounds, SnapPosition.LEFT)
+ verify(mockToast).show()
}
@Test
@@ -679,6 +686,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
verify(mockDesktopTasksController, never())
.snapToHalfScreen(decor.mTaskInfo, currentBounds, SnapPosition.RIGHT)
+ verify(mockToast).show()
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
index a1c794748c21..627dfe718521 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
@@ -41,9 +41,9 @@ import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestRunningTaskInfoBuilder
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 822a387351e3..0fa31c7a832e 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -107,7 +107,7 @@ AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& co
}
AssetManager2::AssetManager2() {
- configurations_.resize(1);
+ configurations_.emplace_back();
}
bool AssetManager2::SetApkAssets(ApkAssetsList apk_assets, bool invalidate_caches) {
@@ -438,8 +438,8 @@ bool AssetManager2::ContainsAllocatedTable() const {
return false;
}
-void AssetManager2::SetConfigurations(std::vector<ResTable_config> configurations,
- bool force_refresh) {
+void AssetManager2::SetConfigurations(std::span<const ResTable_config> configurations,
+ bool force_refresh) {
int diff = 0;
if (force_refresh) {
diff = -1;
@@ -452,8 +452,10 @@ void AssetManager2::SetConfigurations(std::vector<ResTable_config> configuration
}
}
}
- configurations_ = std::move(configurations);
-
+ configurations_.clear();
+ for (auto&& config : configurations) {
+ configurations_.emplace_back(config);
+ }
if (diff) {
RebuildFilterList();
InvalidateCaches(static_cast<uint32_t>(diff));
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index ac46bc5c179f..0fdeefa09e26 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -32,6 +32,7 @@
#include "androidfw/AssetManager.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/Util.h"
+#include "ftl/small_vector.h"
namespace android {
@@ -159,9 +160,10 @@ class AssetManager2 {
// Sets/resets the configuration for this AssetManager. This will cause all
// caches that are related to the configuration change to be invalidated.
- void SetConfigurations(std::vector<ResTable_config> configurations, bool force_refresh = false);
+ void SetConfigurations(std::span<const ResTable_config> configurations,
+ bool force_refresh = false);
- inline const std::vector<ResTable_config>& GetConfigurations() const {
+ std::span<const ResTable_config> GetConfigurations() const {
return configurations_;
}
@@ -470,13 +472,13 @@ class AssetManager2 {
// An array mapping package ID to index into package_groups. This keeps the lookup fast
// without taking too much memory.
- std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_;
+ std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_ = {};
- uint32_t default_locale_;
+ uint32_t default_locale_ = 0;
// The current configurations set for this AssetManager. When this changes, cached resources
// may need to be purged.
- std::vector<ResTable_config> configurations_;
+ ftl::SmallVector<ResTable_config, 1> configurations_;
// Cached set of bags. These are cached because they can inherit keys from parent bags,
// which involves some calculation.
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index c62f095e9dac..3f228841f6ba 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -113,7 +113,7 @@ TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
desired_config.language[1] = 'e';
AssetManager2 assetmanager;
- assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetConfigurations({{desired_config}});
assetmanager.SetApkAssets({basic_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -137,7 +137,7 @@ TEST_F(AssetManager2Test, FindsResourceFromMultipleApkAssets) {
desired_config.language[1] = 'e';
AssetManager2 assetmanager;
- assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetConfigurations({{desired_config}});
assetmanager.SetApkAssets({basic_assets_, basic_de_fr_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -466,10 +466,10 @@ TEST_F(AssetManager2Test, ResolveDeepIdReference) {
TEST_F(AssetManager2Test, DensityOverride) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_, basic_xhdpi_assets_, basic_xxhdpi_assets_});
- assetmanager.SetConfigurations({{
+ assetmanager.SetConfigurations({{{
.density = ResTable_config::DENSITY_XHIGH,
.sdkVersion = 21,
- }});
+ }}});
auto value = assetmanager.GetResource(basic::R::string::density, false /*may_be_bag*/);
ASSERT_TRUE(value.has_value());
@@ -721,7 +721,7 @@ TEST_F(AssetManager2Test, GetLastPathWithoutEnablingReturnsEmpty) {
ResTable_config desired_config;
AssetManager2 assetmanager;
- assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetConfigurations({{desired_config}});
assetmanager.SetApkAssets({basic_assets_});
assetmanager.SetResourceResolutionLoggingEnabled(false);
@@ -736,7 +736,7 @@ TEST_F(AssetManager2Test, GetLastPathWithoutResolutionReturnsEmpty) {
ResTable_config desired_config;
AssetManager2 assetmanager;
- assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetConfigurations({{desired_config}});
assetmanager.SetApkAssets({basic_assets_});
auto result = assetmanager.GetLastResourceResolution();
@@ -751,7 +751,7 @@ TEST_F(AssetManager2Test, GetLastPathWithSingleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetResourceResolutionLoggingEnabled(true);
- assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetConfigurations({{desired_config}});
assetmanager.SetApkAssets({basic_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -774,7 +774,7 @@ TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetResourceResolutionLoggingEnabled(true);
- assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetConfigurations({{desired_config}});
assetmanager.SetApkAssets({basic_assets_, basic_de_fr_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -796,7 +796,7 @@ TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
AssetManager2 assetmanager;
assetmanager.SetResourceResolutionLoggingEnabled(true);
- assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetConfigurations({{desired_config}});
assetmanager.SetApkAssets({basic_assets_});
auto value = assetmanager.GetResource(basic::R::string::test1);
@@ -817,7 +817,7 @@ TEST_F(AssetManager2Test, GetOverlayablesToString) {
AssetManager2 assetmanager;
assetmanager.SetResourceResolutionLoggingEnabled(true);
- assetmanager.SetConfigurations({desired_config});
+ assetmanager.SetConfigurations({{desired_config}});
assetmanager.SetApkAssets({overlayable_assets_});
const auto map = assetmanager.GetOverlayableMapForPackage(0x7f);
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index e3fc0a0a4e68..ec2abb84a5d5 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -66,7 +66,7 @@ void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_
AssetManager2 assetmanager;
assetmanager.SetApkAssets(apk_assets);
if (config != nullptr) {
- assetmanager.SetConfigurations({*config});
+ assetmanager.SetConfigurations({{{*config}}});
}
while (state.KeepRunning()) {
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 181d1411fb91..afcb0c1ad964 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -260,7 +260,7 @@ TEST_F(ThemeTest, ThemeRebase) {
ResTable_config night{};
night.uiMode = ResTable_config::UI_MODE_NIGHT_YES;
night.version = 8u;
- am_night.SetConfigurations({night});
+ am_night.SetConfigurations({{night}});
auto theme = am.NewTheme();
{
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 9896f6404cda..2d7db5e6ed94 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -131,7 +131,7 @@ public final class MediaCas implements AutoCloseable {
private int mCasSystemId;
private int mUserId;
private TunerResourceManager mTunerResourceManager = null;
- private final Map<Session, Long> mSessionMap = new HashMap<>();
+ private final Map<Session, Integer> mSessionMap = new HashMap<>();
/**
* Scrambling modes used to open cas sessions.
@@ -1126,10 +1126,10 @@ public final class MediaCas implements AutoCloseable {
}
}
- private long getSessionResourceHandle() throws MediaCasException {
+ private int getSessionResourceHandle() throws MediaCasException {
validateInternalStates();
- long[] sessionResourceHandle = new long[1];
+ int[] sessionResourceHandle = new int[1];
sessionResourceHandle[0] = -1;
if (mTunerResourceManager != null) {
CasSessionRequest casSessionRequest = new CasSessionRequest();
@@ -1144,7 +1144,8 @@ public final class MediaCas implements AutoCloseable {
return sessionResourceHandle[0];
}
- private void addSessionToResourceMap(Session session, long sessionResourceHandle) {
+ private void addSessionToResourceMap(Session session, int sessionResourceHandle) {
+
if (sessionResourceHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
synchronized (mSessionMap) {
mSessionMap.put(session, sessionResourceHandle);
@@ -1177,14 +1178,13 @@ public final class MediaCas implements AutoCloseable {
* @throws MediaCasStateException for CAS-specific state exceptions.
*/
public Session openSession() throws MediaCasException {
- long sessionResourceHandle = getSessionResourceHandle();
+ int sessionResourceHandle = getSessionResourceHandle();
try {
if (mICas != null) {
try {
byte[] sessionId = mICas.openSessionDefault();
Session session = createFromSessionId(sessionId);
- addSessionToResourceMap(session, sessionResourceHandle);
Log.d(TAG, "Write Stats Log for succeed to Open Session.");
FrameworkStatsLog.write(
FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
@@ -1238,7 +1238,7 @@ public final class MediaCas implements AutoCloseable {
@Nullable
public Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode)
throws MediaCasException {
- long sessionResourceHandle = getSessionResourceHandle();
+ int sessionResourceHandle = getSessionResourceHandle();
if (mICas != null) {
try {
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 300ae5d9a26b..2c71ee01b3f1 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -293,13 +293,13 @@ public class Tuner implements AutoCloseable {
private EventHandler mHandler;
@Nullable
private FrontendInfo mFrontendInfo;
- private Long mFrontendHandle;
+ private Integer mFrontendHandle;
private Tuner mFeOwnerTuner = null;
private int mFrontendType = FrontendSettings.TYPE_UNDEFINED;
private Integer mDesiredFrontendId = null;
private int mUserId;
private Lnb mLnb;
- private Long mLnbHandle;
+ private Integer mLnbHandle;
@Nullable
private OnTuneEventListener mOnTuneEventListener;
@Nullable
@@ -322,10 +322,10 @@ public class Tuner implements AutoCloseable {
private final ReentrantLock mDemuxLock = new ReentrantLock();
private int mRequestedCiCamId;
- private Long mDemuxHandle;
- private Long mFrontendCiCamHandle;
+ private Integer mDemuxHandle;
+ private Integer mFrontendCiCamHandle;
private Integer mFrontendCiCamId;
- private Map<Long, WeakReference<Descrambler>> mDescramblers = new HashMap<>();
+ private Map<Integer, WeakReference<Descrambler>> mDescramblers = new HashMap<>();
private List<WeakReference<Filter>> mFilters = new ArrayList<WeakReference<Filter>>();
private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
@@ -947,7 +947,7 @@ public class Tuner implements AutoCloseable {
private void releaseDescramblers() {
synchronized (mDescramblers) {
if (!mDescramblers.isEmpty()) {
- for (Map.Entry<Long, WeakReference<Descrambler>> d : mDescramblers.entrySet()) {
+ for (Map.Entry<Integer, WeakReference<Descrambler>> d : mDescramblers.entrySet()) {
Descrambler descrambler = d.getValue().get();
if (descrambler != null) {
descrambler.close();
@@ -1008,7 +1008,7 @@ public class Tuner implements AutoCloseable {
/**
* Native method to open frontend of the given ID.
*/
- private native Frontend nativeOpenFrontendByHandle(long handle);
+ private native Frontend nativeOpenFrontendByHandle(int handle);
private native int nativeShareFrontend(int id);
private native int nativeUnshareFrontend();
private native void nativeRegisterFeCbListener(long nativeContext);
@@ -1037,21 +1037,21 @@ public class Tuner implements AutoCloseable {
private native int nativeSetMaxNumberOfFrontends(int frontendType, int maxNumber);
private native int nativeGetMaxNumberOfFrontends(int frontendType);
private native int nativeRemoveOutputPid(int pid);
- private native Lnb nativeOpenLnbByHandle(long handle);
+ private native Lnb nativeOpenLnbByHandle(int handle);
private native Lnb nativeOpenLnbByName(String name);
private native FrontendStatusReadiness[] nativeGetFrontendStatusReadiness(int[] statusTypes);
- private native Descrambler nativeOpenDescramblerByHandle(long handle);
- private native int nativeOpenDemuxByhandle(long handle);
+ private native Descrambler nativeOpenDescramblerByHandle(int handle);
+ private native int nativeOpenDemuxByhandle(int handle);
private native DvrRecorder nativeOpenDvrRecorder(long bufferSize);
private native DvrPlayback nativeOpenDvrPlayback(long bufferSize);
private native DemuxCapabilities nativeGetDemuxCapabilities();
- private native DemuxInfo nativeGetDemuxInfo(long demuxHandle);
+ private native DemuxInfo nativeGetDemuxInfo(int demuxHandle);
- private native int nativeCloseDemux(long handle);
- private native int nativeCloseFrontend(long handle);
+ private native int nativeCloseDemux(int handle);
+ private native int nativeCloseFrontend(int handle);
private native int nativeClose();
private static native SharedFilter nativeOpenSharedFilter(String token);
@@ -1369,7 +1369,7 @@ public class Tuner implements AutoCloseable {
}
private boolean requestFrontend() {
- long[] feHandle = new long[1];
+ int[] feHandle = new int[1];
boolean granted = false;
try {
TunerFrontendRequest request = new TunerFrontendRequest();
@@ -2377,7 +2377,7 @@ public class Tuner implements AutoCloseable {
}
private boolean requestLnb() {
- long[] lnbHandle = new long[1];
+ int[] lnbHandle = new int[1];
TunerLnbRequest request = new TunerLnbRequest();
request.clientId = mClientId;
boolean granted = mTunerResourceManager.requestLnb(request, lnbHandle);
@@ -2660,7 +2660,7 @@ public class Tuner implements AutoCloseable {
}
private boolean requestDemux() {
- long[] demuxHandle = new long[1];
+ int[] demuxHandle = new int[1];
TunerDemuxRequest request = new TunerDemuxRequest();
request.clientId = mClientId;
request.desiredFilterTypes = mDesiredDemuxInfo.getFilterTypes();
@@ -2673,14 +2673,14 @@ public class Tuner implements AutoCloseable {
}
private Descrambler requestDescrambler() {
- long[] descramblerHandle = new long[1];
+ int[] descramblerHandle = new int[1];
TunerDescramblerRequest request = new TunerDescramblerRequest();
request.clientId = mClientId;
boolean granted = mTunerResourceManager.requestDescrambler(request, descramblerHandle);
if (!granted) {
return null;
}
- long handle = descramblerHandle[0];
+ int handle = descramblerHandle[0];
Descrambler descrambler = nativeOpenDescramblerByHandle(handle);
if (descrambler != null) {
synchronized (mDescramblers) {
@@ -2694,7 +2694,7 @@ public class Tuner implements AutoCloseable {
}
private boolean requestFrontendCiCam(int ciCamId) {
- long[] ciCamHandle = new long[1];
+ int[] ciCamHandle = new int[1];
TunerCiCamRequest request = new TunerCiCamRequest();
request.clientId = mClientId;
request.ciCamId = ciCamId;
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index bb581ebe1778..d268aeba8011 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -66,7 +66,7 @@ public class TunerResourceManager {
private static final String TAG = "TunerResourceManager";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- public static final long INVALID_RESOURCE_HANDLE = -1;
+ public static final int INVALID_RESOURCE_HANDLE = -1;
public static final int INVALID_OWNER_ID = -1;
/**
* Tuner resource type to help generate resource handle
@@ -275,7 +275,7 @@ public class TunerResourceManager {
* Updates the current TRM of the TunerHAL Frontend information.
*
* <p><strong>Note:</strong> This update must happen before the first
- * {@link #requestFrontend(TunerFrontendRequest, long[])} and
+ * {@link #requestFrontend(TunerFrontendRequest, int[])} and
* {@link #releaseFrontend(int, int)} call.
*
* @param infos an array of the available {@link TunerFrontendInfo} information.
@@ -331,7 +331,7 @@ public class TunerResourceManager {
*
* @param lnbIds ids of the updating lnbs.
*/
- public void setLnbInfoList(long[] lnbIds) {
+ public void setLnbInfoList(int[] lnbIds) {
try {
mService.setLnbInfoList(lnbIds);
} catch (RemoteException e) {
@@ -406,8 +406,8 @@ public class TunerResourceManager {
*
* @return true if there is frontend granted.
*/
- public boolean requestFrontend(
- @NonNull TunerFrontendRequest request, @Nullable long[] frontendHandle) {
+ public boolean requestFrontend(@NonNull TunerFrontendRequest request,
+ @Nullable int[] frontendHandle) {
boolean result = false;
try {
result = mService.requestFrontend(request, frontendHandle);
@@ -511,7 +511,7 @@ public class TunerResourceManager {
*
* @return true if there is Demux granted.
*/
- public boolean requestDemux(@NonNull TunerDemuxRequest request, @NonNull long[] demuxHandle) {
+ public boolean requestDemux(@NonNull TunerDemuxRequest request, @NonNull int[] demuxHandle) {
boolean result = false;
try {
result = mService.requestDemux(request, demuxHandle);
@@ -544,8 +544,8 @@ public class TunerResourceManager {
*
* @return true if there is Descrambler granted.
*/
- public boolean requestDescrambler(
- @NonNull TunerDescramblerRequest request, @NonNull long[] descramblerHandle) {
+ public boolean requestDescrambler(@NonNull TunerDescramblerRequest request,
+ @NonNull int[] descramblerHandle) {
boolean result = false;
try {
result = mService.requestDescrambler(request, descramblerHandle);
@@ -577,8 +577,8 @@ public class TunerResourceManager {
*
* @return true if there is CAS session granted.
*/
- public boolean requestCasSession(
- @NonNull CasSessionRequest request, @NonNull long[] casSessionHandle) {
+ public boolean requestCasSession(@NonNull CasSessionRequest request,
+ @NonNull int[] casSessionHandle) {
boolean result = false;
try {
result = mService.requestCasSession(request, casSessionHandle);
@@ -610,7 +610,7 @@ public class TunerResourceManager {
*
* @return true if there is ciCam granted.
*/
- public boolean requestCiCam(TunerCiCamRequest request, long[] ciCamHandle) {
+ public boolean requestCiCam(TunerCiCamRequest request, int[] ciCamHandle) {
boolean result = false;
try {
result = mService.requestCiCam(request, ciCamHandle);
@@ -635,7 +635,7 @@ public class TunerResourceManager {
* <li>If no Lnb system can be granted, the API would return false.
* <ul>
*
- * <p><strong>Note:</strong> {@link #setLnbInfoList(long[])} must be called before this request.
+ * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this request.
*
* @param request {@link TunerLnbRequest} information of the current request.
* @param lnbHandle a one-element array to return the granted Lnb handle.
@@ -643,7 +643,7 @@ public class TunerResourceManager {
*
* @return true if there is Lnb granted.
*/
- public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull long[] lnbHandle) {
+ public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull int[] lnbHandle) {
boolean result = false;
try {
result = mService.requestLnb(request, lnbHandle);
@@ -664,7 +664,7 @@ public class TunerResourceManager {
* @param frontendHandle the handle of the released frontend.
* @param clientId the id of the client that is releasing the frontend.
*/
- public void releaseFrontend(long frontendHandle, int clientId) {
+ public void releaseFrontend(int frontendHandle, int clientId) {
try {
mService.releaseFrontend(frontendHandle, clientId);
} catch (RemoteException e) {
@@ -680,7 +680,7 @@ public class TunerResourceManager {
* @param demuxHandle the handle of the released Tuner Demux.
* @param clientId the id of the client that is releasing the demux.
*/
- public void releaseDemux(long demuxHandle, int clientId) {
+ public void releaseDemux(int demuxHandle, int clientId) {
try {
mService.releaseDemux(demuxHandle, clientId);
} catch (RemoteException e) {
@@ -696,7 +696,7 @@ public class TunerResourceManager {
* @param descramblerHandle the handle of the released Tuner Descrambler.
* @param clientId the id of the client that is releasing the descrambler.
*/
- public void releaseDescrambler(long descramblerHandle, int clientId) {
+ public void releaseDescrambler(int descramblerHandle, int clientId) {
try {
mService.releaseDescrambler(descramblerHandle, clientId);
} catch (RemoteException e) {
@@ -715,7 +715,7 @@ public class TunerResourceManager {
* @param casSessionHandle the handle of the released CAS session.
* @param clientId the id of the client that is releasing the cas session.
*/
- public void releaseCasSession(long casSessionHandle, int clientId) {
+ public void releaseCasSession(int casSessionHandle, int clientId) {
try {
mService.releaseCasSession(casSessionHandle, clientId);
} catch (RemoteException e) {
@@ -734,7 +734,7 @@ public class TunerResourceManager {
* @param ciCamHandle the handle of the releasing CiCam.
* @param clientId the id of the client that is releasing the CiCam.
*/
- public void releaseCiCam(long ciCamHandle, int clientId) {
+ public void releaseCiCam(int ciCamHandle, int clientId) {
try {
mService.releaseCiCam(ciCamHandle, clientId);
} catch (RemoteException e) {
@@ -747,12 +747,12 @@ public class TunerResourceManager {
*
* <p>Client must call this whenever it releases an Lnb.
*
- * <p><strong>Note:</strong> {@link #setLnbInfoList(long[])} must be called before this release.
+ * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this release.
*
* @param lnbHandle the handle of the released Tuner Lnb.
* @param clientId the id of the client that is releasing the lnb.
*/
- public void releaseLnb(long lnbHandle, int clientId) {
+ public void releaseLnb(int lnbHandle, int clientId) {
try {
mService.releaseLnb(lnbHandle, clientId);
} catch (RemoteException e) {
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index 109c791c1748..539969762a82 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -149,7 +149,7 @@ interface ITunerResourceManager {
*
* @param lnbIds ids of the updating lnbs.
*/
- void setLnbInfoList(in long[] lnbIds);
+ void setLnbInfoList(in int[] lnbIds);
/*
* This API is used by the Tuner framework to request a frontend from the TunerHAL.
@@ -185,7 +185,7 @@ interface ITunerResourceManager {
*
* @return true if there is frontend granted.
*/
- boolean requestFrontend(in TunerFrontendRequest request, out long[] frontendHandle);
+ boolean requestFrontend(in TunerFrontendRequest request, out int[] frontendHandle);
/*
* Sets the maximum usable frontends number of a given frontend type. It is used to enable or
@@ -253,7 +253,7 @@ interface ITunerResourceManager {
*
* @return true if there is demux granted.
*/
- boolean requestDemux(in TunerDemuxRequest request, out long[] demuxHandle);
+ boolean requestDemux(in TunerDemuxRequest request, out int[] demuxHandle);
/*
* This API is used by the Tuner framework to request an available descrambler from the
@@ -277,7 +277,7 @@ interface ITunerResourceManager {
*
* @return true if there is Descrambler granted.
*/
- boolean requestDescrambler(in TunerDescramblerRequest request, out long[] descramblerHandle);
+ boolean requestDescrambler(in TunerDescramblerRequest request, out int[] descramblerHandle);
/*
* This API is used by the Tuner framework to request an available Cas session. This session
@@ -303,7 +303,7 @@ interface ITunerResourceManager {
*
* @return true if there is CAS session granted.
*/
- boolean requestCasSession(in CasSessionRequest request, out long[] casSessionHandle);
+ boolean requestCasSession(in CasSessionRequest request, out int[] casSessionHandle);
/*
* This API is used by the Tuner framework to request an available CuCam.
@@ -328,7 +328,7 @@ interface ITunerResourceManager {
*
* @return true if there is CiCam granted.
*/
- boolean requestCiCam(in TunerCiCamRequest request, out long[] ciCamHandle);
+ boolean requestCiCam(in TunerCiCamRequest request, out int[] ciCamHandle);
/*
* This API is used by the Tuner framework to request an available Lnb from the TunerHAL.
@@ -352,7 +352,7 @@ interface ITunerResourceManager {
*
* @return true if there is Lnb granted.
*/
- boolean requestLnb(in TunerLnbRequest request, out long[] lnbHandle);
+ boolean requestLnb(in TunerLnbRequest request, out int[] lnbHandle);
/*
* Notifies the TRM that the given frontend has been released.
@@ -365,7 +365,7 @@ interface ITunerResourceManager {
* @param frontendHandle the handle of the released frontend.
* @param clientId the id of the client that is releasing the frontend.
*/
- void releaseFrontend(in long frontendHandle, int clientId);
+ void releaseFrontend(in int frontendHandle, int clientId);
/*
* Notifies the TRM that the Demux with the given handle was released.
@@ -375,7 +375,7 @@ interface ITunerResourceManager {
* @param demuxHandle the handle of the released Tuner Demux.
* @param clientId the id of the client that is releasing the demux.
*/
- void releaseDemux(in long demuxHandle, int clientId);
+ void releaseDemux(in int demuxHandle, int clientId);
/*
* Notifies the TRM that the Descrambler with the given handle was released.
@@ -385,7 +385,7 @@ interface ITunerResourceManager {
* @param descramblerHandle the handle of the released Tuner Descrambler.
* @param clientId the id of the client that is releasing the descrambler.
*/
- void releaseDescrambler(in long descramblerHandle, int clientId);
+ void releaseDescrambler(in int descramblerHandle, int clientId);
/*
* Notifies the TRM that the given Cas session has been released.
@@ -397,7 +397,7 @@ interface ITunerResourceManager {
* @param casSessionHandle the handle of the released CAS session.
* @param clientId the id of the client that is releasing the cas session.
*/
- void releaseCasSession(in long casSessionHandle, int clientId);
+ void releaseCasSession(in int casSessionHandle, int clientId);
/**
* Notifies the TRM that the given CiCam has been released.
@@ -410,7 +410,7 @@ interface ITunerResourceManager {
* @param ciCamHandle the handle of the releasing CiCam.
* @param clientId the id of the client that is releasing the CiCam.
*/
- void releaseCiCam(in long ciCamHandle, int clientId);
+ void releaseCiCam(in int ciCamHandle, int clientId);
/*
* Notifies the TRM that the Lnb with the given handle was released.
@@ -422,7 +422,7 @@ interface ITunerResourceManager {
* @param lnbHandle the handle of the released Tuner Lnb.
* @param clientId the id of the client that is releasing the lnb.
*/
- void releaseLnb(in long lnbHandle, int clientId);
+ void releaseLnb(in int lnbHandle, int clientId);
/*
* Compare two clients' priority.
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl
index 7984c38d33ab..c14caf50fa14 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl
@@ -26,7 +26,7 @@ parcelable TunerDemuxInfo {
/**
* Demux handle
*/
- long handle;
+ int handle;
/**
* Supported filter types (defined in {@link android.media.tv.tuner.filter.Filter})
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
index 274367e9aeb6..8981ce00d509 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
@@ -26,7 +26,7 @@ parcelable TunerFrontendInfo {
/**
* Frontend Handle
*/
- long handle;
+ int handle;
/**
* Frontend Type
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5eb2485b8dd6..00b0e57c09ea 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -1448,7 +1448,7 @@ jobject JTuner::getFrontendIds() {
return obj;
}
-jobject JTuner::openFrontendByHandle(jlong feHandle) {
+jobject JTuner::openFrontendByHandle(int feHandle) {
// TODO: Handle reopening frontend with different handle
sp<FrontendClient> feClient = sTunerClient->openFrontend(feHandle);
if (feClient == nullptr) {
@@ -1824,7 +1824,7 @@ jobjectArray JTuner::getFrontendStatusReadiness(jintArray types) {
return valObj;
}
-jobject JTuner::openLnbByHandle(jlong handle) {
+jobject JTuner::openLnbByHandle(int handle) {
if (sTunerClient == nullptr) {
return nullptr;
}
@@ -1833,7 +1833,7 @@ jobject JTuner::openLnbByHandle(jlong handle) {
sp<LnbClientCallbackImpl> callback = new LnbClientCallbackImpl();
lnbClient = sTunerClient->openLnb(handle);
if (lnbClient == nullptr) {
- ALOGD("Failed to open lnb, handle = %ld", handle);
+ ALOGD("Failed to open lnb, handle = %d", handle);
return nullptr;
}
@@ -1947,7 +1947,7 @@ int JTuner::setLna(bool enable) {
return (int)result;
}
-Result JTuner::openDemux(jlong handle) {
+Result JTuner::openDemux(int handle) {
if (sTunerClient == nullptr) {
return Result::NOT_INITIALIZED;
}
@@ -2215,7 +2215,7 @@ jobject JTuner::getDemuxCaps() {
numBytesInSectionFilter, filterCaps, filterCapsList, linkCaps, bTimeFilter);
}
-jobject JTuner::getDemuxInfo(jlong handle) {
+jobject JTuner::getDemuxInfo(int handle) {
if (sTunerClient == nullptr) {
ALOGE("tuner is not initialized");
return nullptr;
@@ -3768,8 +3768,8 @@ static jobject android_media_tv_Tuner_get_frontend_ids(JNIEnv *env, jobject thiz
return tuner->getFrontendIds();
}
-static jobject android_media_tv_Tuner_open_frontend_by_handle(JNIEnv *env, jobject thiz,
- jlong handle) {
+static jobject android_media_tv_Tuner_open_frontend_by_handle(
+ JNIEnv *env, jobject thiz, jint handle) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->openFrontendByHandle(handle);
}
@@ -3901,7 +3901,7 @@ static jobject android_media_tv_Tuner_get_frontend_info(JNIEnv *env, jobject thi
return tuner->getFrontendInfo(id);
}
-static jobject android_media_tv_Tuner_open_lnb_by_handle(JNIEnv *env, jobject thiz, jlong handle) {
+static jobject android_media_tv_Tuner_open_lnb_by_handle(JNIEnv *env, jobject thiz, jint handle) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->openLnbByHandle(handle);
}
@@ -4622,7 +4622,7 @@ static int android_media_tv_Tuner_time_filter_close(JNIEnv *env, jobject filter)
return (int)r;
}
-static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz, jlong) {
+static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz, jint) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->openDescrambler();
}
@@ -4690,12 +4690,12 @@ static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz)
return tuner->getDemuxCaps();
}
-static jobject android_media_tv_Tuner_get_demux_info(JNIEnv *env, jobject thiz, jlong handle) {
+static jobject android_media_tv_Tuner_get_demux_info(JNIEnv* env, jobject thiz, jint handle) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->getDemuxInfo(handle);
}
-static jint android_media_tv_Tuner_open_demux(JNIEnv *env, jobject thiz, jlong handle) {
+static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint handle) {
sp<JTuner> tuner = getTuner(env, thiz);
return (jint)tuner->openDemux(handle);
}
@@ -4706,7 +4706,7 @@ static jint android_media_tv_Tuner_close_tuner(JNIEnv* env, jobject thiz) {
return (jint)tuner->close();
}
-static jint android_media_tv_Tuner_close_demux(JNIEnv *env, jobject thiz, jlong /* handle */) {
+static jint android_media_tv_Tuner_close_demux(JNIEnv* env, jobject thiz, jint /* handle */) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->closeDemux();
}
@@ -4766,7 +4766,7 @@ static jobjectArray android_media_tv_Tuner_get_frontend_status_readiness(JNIEnv
return tuner->getFrontendStatusReadiness(types);
}
-static jint android_media_tv_Tuner_close_frontend(JNIEnv *env, jobject thiz, jlong /* handle */) {
+static jint android_media_tv_Tuner_close_frontend(JNIEnv* env, jobject thiz, jint /* handle */) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->closeFrontend();
}
@@ -5035,7 +5035,7 @@ static const JNINativeMethod gTunerMethods[] = {
{ "nativeGetTunerVersion", "()I", (void *)android_media_tv_Tuner_native_get_tuner_version },
{ "nativeGetFrontendIds", "()Ljava/util/List;",
(void *)android_media_tv_Tuner_get_frontend_ids },
- { "nativeOpenFrontendByHandle", "(J)Landroid/media/tv/tuner/Tuner$Frontend;",
+ { "nativeOpenFrontendByHandle", "(I)Landroid/media/tv/tuner/Tuner$Frontend;",
(void *)android_media_tv_Tuner_open_frontend_by_handle },
{ "nativeShareFrontend", "(I)I",
(void *)android_media_tv_Tuner_share_frontend },
@@ -5074,11 +5074,11 @@ static const JNINativeMethod gTunerMethods[] = {
(void *)android_media_tv_Tuner_open_filter },
{ "nativeOpenTimeFilter", "()Landroid/media/tv/tuner/filter/TimeFilter;",
(void *)android_media_tv_Tuner_open_time_filter },
- { "nativeOpenLnbByHandle", "(J)Landroid/media/tv/tuner/Lnb;",
+ { "nativeOpenLnbByHandle", "(I)Landroid/media/tv/tuner/Lnb;",
(void *)android_media_tv_Tuner_open_lnb_by_handle },
{ "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;",
(void *)android_media_tv_Tuner_open_lnb_by_name },
- { "nativeOpenDescramblerByHandle", "(J)Landroid/media/tv/tuner/Descrambler;",
+ { "nativeOpenDescramblerByHandle", "(I)Landroid/media/tv/tuner/Descrambler;",
(void *)android_media_tv_Tuner_open_descrambler },
{ "nativeOpenDvrRecorder", "(J)Landroid/media/tv/tuner/dvr/DvrRecorder;",
(void *)android_media_tv_Tuner_open_dvr_recorder },
@@ -5086,12 +5086,12 @@ static const JNINativeMethod gTunerMethods[] = {
(void *)android_media_tv_Tuner_open_dvr_playback },
{ "nativeGetDemuxCapabilities", "()Landroid/media/tv/tuner/DemuxCapabilities;",
(void *)android_media_tv_Tuner_get_demux_caps },
- { "nativeGetDemuxInfo", "(J)Landroid/media/tv/tuner/DemuxInfo;",
+ { "nativeGetDemuxInfo", "(I)Landroid/media/tv/tuner/DemuxInfo;",
(void *)android_media_tv_Tuner_get_demux_info },
- { "nativeOpenDemuxByhandle", "(J)I", (void *)android_media_tv_Tuner_open_demux },
+ { "nativeOpenDemuxByhandle", "(I)I", (void *)android_media_tv_Tuner_open_demux },
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_tuner },
- { "nativeCloseFrontend", "(J)I", (void *)android_media_tv_Tuner_close_frontend },
- { "nativeCloseDemux", "(J)I", (void *)android_media_tv_Tuner_close_demux },
+ { "nativeCloseFrontend", "(I)I", (void *)android_media_tv_Tuner_close_frontend },
+ { "nativeCloseDemux", "(I)I", (void *)android_media_tv_Tuner_close_demux },
{ "nativeOpenSharedFilter",
"(Ljava/lang/String;)Landroid/media/tv/tuner/filter/SharedFilter;",
(void *)android_media_tv_Tuner_open_shared_filter},
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 7af2cd7bd5b7..3de3ab91326c 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -206,7 +206,7 @@ struct JTuner : public RefBase {
int disconnectCiCam();
int unlinkCiCam(jint id);
jobject getFrontendIds();
- jobject openFrontendByHandle(jlong feHandle);
+ jobject openFrontendByHandle(int feHandle);
int shareFrontend(int feId);
int unshareFrontend();
void registerFeCbListener(JTuner* jtuner);
@@ -221,16 +221,16 @@ struct JTuner : public RefBase {
int setLnb(sp<LnbClient> lnbClient);
bool isLnaSupported();
int setLna(bool enable);
- jobject openLnbByHandle(jlong handle);
+ jobject openLnbByHandle(int handle);
jobject openLnbByName(jstring name);
jobject openFilter(DemuxFilterType type, int bufferSize);
jobject openTimeFilter();
jobject openDescrambler();
jobject openDvr(DvrType type, jlong bufferSize);
jobject getDemuxCaps();
- jobject getDemuxInfo(jlong handle);
+ jobject getDemuxInfo(int handle);
jobject getFrontendStatus(jintArray types);
- Result openDemux(jlong handle);
+ Result openDemux(int handle);
jint close();
jint closeFrontend();
jint closeDemux();
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index 0097710f5c64..ea623d97a394 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -56,7 +56,7 @@ vector<int32_t> TunerClient::getFrontendIds() {
return ids;
}
-sp<FrontendClient> TunerClient::openFrontend(int64_t frontendHandle) {
+sp<FrontendClient> TunerClient::openFrontend(int32_t frontendHandle) {
if (mTunerService != nullptr) {
shared_ptr<ITunerFrontend> tunerFrontend;
Status s = mTunerService->openFrontend(frontendHandle, &tunerFrontend);
@@ -94,7 +94,7 @@ shared_ptr<FrontendInfo> TunerClient::getFrontendInfo(int32_t id) {
return nullptr;
}
-sp<DemuxClient> TunerClient::openDemux(int64_t demuxHandle) {
+sp<DemuxClient> TunerClient::openDemux(int32_t demuxHandle) {
if (mTunerService != nullptr) {
shared_ptr<ITunerDemux> tunerDemux;
Status s = mTunerService->openDemux(demuxHandle, &tunerDemux);
@@ -107,7 +107,7 @@ sp<DemuxClient> TunerClient::openDemux(int64_t demuxHandle) {
return nullptr;
}
-shared_ptr<DemuxInfo> TunerClient::getDemuxInfo(int64_t demuxHandle) {
+shared_ptr<DemuxInfo> TunerClient::getDemuxInfo(int32_t demuxHandle) {
if (mTunerService != nullptr) {
DemuxInfo aidlDemuxInfo;
Status s = mTunerService->getDemuxInfo(demuxHandle, &aidlDemuxInfo);
@@ -141,7 +141,7 @@ shared_ptr<DemuxCapabilities> TunerClient::getDemuxCaps() {
return nullptr;
}
-sp<DescramblerClient> TunerClient::openDescrambler(int64_t descramblerHandle) {
+sp<DescramblerClient> TunerClient::openDescrambler(int32_t descramblerHandle) {
if (mTunerService != nullptr) {
shared_ptr<ITunerDescrambler> tunerDescrambler;
Status s = mTunerService->openDescrambler(descramblerHandle, &tunerDescrambler);
@@ -154,7 +154,7 @@ sp<DescramblerClient> TunerClient::openDescrambler(int64_t descramblerHandle) {
return nullptr;
}
-sp<LnbClient> TunerClient::openLnb(int64_t lnbHandle) {
+sp<LnbClient> TunerClient::openLnb(int32_t lnbHandle) {
if (mTunerService != nullptr) {
shared_ptr<ITunerLnb> tunerLnb;
Status s = mTunerService->openLnb(lnbHandle, &tunerLnb);
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index a348586454b8..6ab120b56d97 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -65,7 +65,7 @@ public:
* @param frontendHandle the handle of the frontend granted by TRM.
* @return a newly created FrontendClient interface.
*/
- sp<FrontendClient> openFrontend(int64_t frontendHandle);
+ sp<FrontendClient> openFrontend(int32_t frontendHandle);
/**
* Retrieve the granted frontend's information.
@@ -81,7 +81,7 @@ public:
* @param demuxHandle the handle of the demux granted by TRM.
* @return a newly created DemuxClient interface.
*/
- sp<DemuxClient> openDemux(int64_t demuxHandle);
+ sp<DemuxClient> openDemux(int32_t demuxHandle);
/**
* Retrieve the DemuxInfo of a specific demux
@@ -89,7 +89,7 @@ public:
* @param demuxHandle the handle of the demux to query demux info for
* @return the demux info
*/
- shared_ptr<DemuxInfo> getDemuxInfo(int64_t demuxHandle);
+ shared_ptr<DemuxInfo> getDemuxInfo(int32_t demuxHandle);
/**
* Retrieve a list of demux info
@@ -111,7 +111,7 @@ public:
* @param descramblerHandle the handle of the descrambler granted by TRM.
* @return a newly created DescramblerClient interface.
*/
- sp<DescramblerClient> openDescrambler(int64_t descramblerHandle);
+ sp<DescramblerClient> openDescrambler(int32_t descramblerHandle);
/**
* Open a new interface of LnbClient given an lnbHandle.
@@ -119,7 +119,7 @@ public:
* @param lnbHandle the handle of the LNB granted by TRM.
* @return a newly created LnbClient interface.
*/
- sp<LnbClient> openLnb(int64_t lnbHandle);
+ sp<LnbClient> openLnb(int32_t lnbHandle);
/**
* Open a new interface of LnbClient given a LNB name.
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 03372b206f48..0605dbe130d3 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -914,7 +914,8 @@ public final class CardEmulation {
* otherwise a call to this method will fail and throw {@link SecurityException}.
* @param activity The Activity that requests NFC controller routing table to be changed.
* @param protocol ISO-DEP route destination, which can be "DH" or "UICC" or "ESE".
- * @param technology Tech-A, Tech-B route destination, which can be "DH" or "UICC" or "ESE".
+ * @param technology Tech-A, Tech-B and Tech-F route destination, which can be "DH" or "UICC"
+ * or "ESE".
* @throws SecurityException if the caller is not the preferred NFC service
* @throws IllegalArgumentException if the activity is not resumed or the caller is not in the
* foreground, or both protocol route and technology route are null.
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
index 69ef718200b9..0d4ce5be7b0e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -53,9 +53,11 @@ import androidx.annotation.Nullable;
import com.android.settingslib.R;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Comparator;
import java.util.Objects;
/**
@@ -88,6 +90,33 @@ public class ZenMode implements Parcelable {
.allowPriorityChannels(false)
.build();
+ private static final Comparator<Integer> PRIORITIZED_TYPE_COMPARATOR = new Comparator<>() {
+
+ private static final ImmutableList</* @AutomaticZenRule.Type */ Integer>
+ PRIORITIZED_TYPES = ImmutableList.of(
+ AutomaticZenRule.TYPE_BEDTIME,
+ AutomaticZenRule.TYPE_DRIVING);
+
+ @Override
+ public int compare(Integer first, Integer second) {
+ if (PRIORITIZED_TYPES.contains(first) && PRIORITIZED_TYPES.contains(second)) {
+ return PRIORITIZED_TYPES.indexOf(first) - PRIORITIZED_TYPES.indexOf(second);
+ } else if (PRIORITIZED_TYPES.contains(first)) {
+ return -1;
+ } else if (PRIORITIZED_TYPES.contains(second)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ };
+
+ // Manual DND first, Bedtime/Driving, then alphabetically.
+ static final Comparator<ZenMode> PRIORITIZING_COMPARATOR = Comparator
+ .comparing(ZenMode::isManualDnd).reversed()
+ .thenComparing(ZenMode::getType, PRIORITIZED_TYPE_COMPARATOR)
+ .thenComparing(ZenMode::getName);
+
public enum Status {
ENABLED,
ENABLED_AND_ACTIVE,
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModesBackend.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModesBackend.java
index 64e503b323b8..c8a12f481c6e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModesBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModesBackend.java
@@ -34,7 +34,6 @@ import com.android.settingslib.R;
import java.time.Duration;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.List;
import java.util.Map;
@@ -92,10 +91,7 @@ public class ZenModesBackend {
}
}
- // Manual DND first, then alphabetically.
- modes.sort(Comparator.comparing(ZenMode::isManualDnd).reversed()
- .thenComparing(ZenMode::getName));
-
+ modes.sort(ZenMode.PRIORITIZING_COMPARATOR);
return modes;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java
index f46424773fef..bab4bc3b0bf5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java
@@ -16,6 +16,12 @@
package com.android.settingslib.notification.modes;
+import static android.app.AutomaticZenRule.TYPE_BEDTIME;
+import static android.app.AutomaticZenRule.TYPE_DRIVING;
+import static android.app.AutomaticZenRule.TYPE_IMMERSIVE;
+import static android.app.AutomaticZenRule.TYPE_OTHER;
+import static android.app.AutomaticZenRule.TYPE_THEATER;
+import static android.app.AutomaticZenRule.TYPE_UNKNOWN;
import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS;
import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
@@ -38,6 +44,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
public class ZenModeTest {
@@ -46,7 +55,7 @@ public class ZenModeTest {
private static final AutomaticZenRule ZEN_RULE =
new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
.setPackage("com.some.driving.thing")
- .setType(AutomaticZenRule.TYPE_DRIVING)
+ .setType(TYPE_DRIVING)
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
.setZenPolicy(ZEN_POLICY)
.build();
@@ -226,6 +235,28 @@ public class ZenModeTest {
}
@Test
+ public void comparator_prioritizes() {
+ ZenMode manualDnd = TestModeBuilder.MANUAL_DND_INACTIVE;
+ ZenMode driving1 = new TestModeBuilder().setName("b1").setType(TYPE_DRIVING).build();
+ ZenMode driving2 = new TestModeBuilder().setName("b2").setType(TYPE_DRIVING).build();
+ ZenMode bedtime1 = new TestModeBuilder().setName("c1").setType(TYPE_BEDTIME).build();
+ ZenMode bedtime2 = new TestModeBuilder().setName("c2").setType(TYPE_BEDTIME).build();
+ ZenMode other = new TestModeBuilder().setName("a1").setType(TYPE_OTHER).build();
+ ZenMode immersive = new TestModeBuilder().setName("a2").setType(TYPE_IMMERSIVE).build();
+ ZenMode unknown = new TestModeBuilder().setName("a3").setType(TYPE_UNKNOWN).build();
+ ZenMode theater = new TestModeBuilder().setName("a4").setType(TYPE_THEATER).build();
+
+ ArrayList<ZenMode> list = new ArrayList<>(List.of(other, theater, bedtime1, unknown,
+ driving2, manualDnd, driving1, bedtime2, immersive));
+ list.sort(ZenMode.PRIORITIZING_COMPARATOR);
+
+ assertThat(list)
+ .containsExactly(manualDnd, bedtime1, bedtime2, driving1, driving2, other,
+ immersive, unknown, theater)
+ .inOrder();
+ }
+
+ @Test
public void writeToParcel_equals() {
assertUnparceledIsEqualToOriginal("example",
new ZenMode("id", ZEN_RULE, zenConfigRuleFor(ZEN_RULE, false)));
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index 75f8384321b0..3e62b7b2cf6e 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -32,6 +32,7 @@ android_library {
"unsupportedappusage",
],
static_libs: [
+ "aconfig_device_paths_java",
"aconfig_new_storage_flags_lib",
"aconfigd_java_utils",
"aconfig_demo_flags_java_lib",
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index 8b0772bb644d..121bd3e6e771 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -20,8 +20,10 @@ import static android.provider.Settings.Config.SYNC_DISABLED_MODE_NONE;
import static android.provider.Settings.Config.SYNC_DISABLED_MODE_PERSISTENT;
import static android.provider.Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT;
-import android.aconfig.Aconfig.parsed_flag;
-import android.aconfig.Aconfig.parsed_flags;
+import android.aconfig.DeviceProtos;
+import android.aconfig.nano.Aconfig;
+import android.aconfig.nano.Aconfig.parsed_flag;
+import android.aconfig.nano.Aconfig.parsed_flags;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.AttributionSource;
@@ -42,7 +44,6 @@ import android.provider.Settings.Config.SyncDisabledMode;
import android.provider.UpdatableDeviceConfigServiceReadiness;
import android.util.Slog;
-import com.android.internal.pm.pkg.component.AconfigFlags;
import com.android.internal.util.FastPrintWriter;
import java.io.File;
@@ -136,11 +137,8 @@ public final class DeviceConfigService extends Binder {
continue;
}
- for (parsed_flag flag : parsedFlags.getParsedFlagList()) {
- String namespace = flag.getNamespace();
- String packageName = flag.getPackage();
- String name = flag.getName();
- nameSet.add(namespace + "/" + packageName + "." + name);
+ for (parsed_flag flag : parsedFlags.parsedFlag) {
+ nameSet.add(flag.namespace + "/" + flag.package_ + "." + flag.name);
}
}
} catch (IOException e) {
@@ -169,6 +167,7 @@ public final class DeviceConfigService extends Binder {
static final class MyShellCommand extends ShellCommand {
final SettingsProvider mProvider;
+ private HashMap<String, parsed_flag> mAconfigParsedFlags;
enum CommandVerb {
GET,
@@ -186,6 +185,51 @@ public final class DeviceConfigService extends Binder {
MyShellCommand(SettingsProvider provider) {
mProvider = provider;
+
+ if (Flags.checkRootAndReadOnly()) {
+ List<parsed_flag> parsedFlags;
+ try {
+ parsedFlags = DeviceProtos.loadAndParseFlagProtos();
+ } catch (IOException e) {
+ throw new IllegalStateException("failed to parse aconfig protos");
+ }
+
+ mAconfigParsedFlags = new HashMap();
+ for (parsed_flag flag : parsedFlags) {
+ mAconfigParsedFlags.put(flag.package_ + "." + flag.name, flag);
+ }
+ }
+ }
+
+ /**
+ * Return true if a flag is aconfig.
+ */
+ private boolean isAconfigFlag(String name) {
+ return mAconfigParsedFlags.get(name) != null;
+ }
+
+ /**
+ * Return true if a flag is both aconfig and read-only.
+ *
+ * @return true if a flag is both aconfig and read-only
+ */
+ private boolean isReadOnly(String name) {
+ parsed_flag flag = mAconfigParsedFlags.get(name);
+ if (flag != null) {
+ if (flag.permission == Aconfig.READ_ONLY) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return true if the calling process is root.
+ *
+ * @return true if a flag is aconfig, and the calling process is root
+ */
+ private boolean isRoot() {
+ return Binder.getCallingUid() == Process.ROOT_UID;
}
public static HashMap<String, String> getAllFlags(IContentProvider provider) {
@@ -414,21 +458,71 @@ public final class DeviceConfigService extends Binder {
pout.println(DeviceConfig.getProperty(namespace, key));
break;
case PUT:
+ if (Flags.checkRootAndReadOnly()) {
+ if (isAconfigFlag(key)) {
+ if (!isRoot()) {
+ pout.println("Error: must be root to write aconfig flag");
+ break;
+ }
+
+ if (isReadOnly(key)) {
+ pout.println("Error: cannot write read-only flag");
+ break;
+ }
+ }
+ }
+
DeviceConfig.setProperty(namespace, key, value, makeDefault);
break;
case OVERRIDE:
- AconfigFlags.Permission permission =
- (new AconfigFlags()).getFlagPermission(key);
- if (permission == AconfigFlags.Permission.READ_ONLY) {
- pout.println("cannot override read-only flag " + key);
- } else {
- DeviceConfig.setLocalOverride(namespace, key, value);
+ if (Flags.checkRootAndReadOnly()) {
+ if (isAconfigFlag(key)) {
+ if (!isRoot()) {
+ pout.println("Error: must be root to write aconfig flag");
+ break;
+ }
+
+ if (isReadOnly(key)) {
+ pout.println("Error: cannot write read-only flag");
+ break;
+ }
+ }
}
+
+ DeviceConfig.setLocalOverride(namespace, key, value);
break;
case CLEAR_OVERRIDE:
+ if (Flags.checkRootAndReadOnly()) {
+ if (isAconfigFlag(key)) {
+ if (!isRoot()) {
+ pout.println("Error: must be root to write aconfig flag");
+ break;
+ }
+
+ if (isReadOnly(key)) {
+ pout.println("Error: cannot write read-only flag");
+ break;
+ }
+ }
+ }
+
DeviceConfig.clearLocalOverride(namespace, key);
break;
case DELETE:
+ if (Flags.checkRootAndReadOnly()) {
+ if (isAconfigFlag(key)) {
+ if (!isRoot()) {
+ pout.println("Error: must be root to write aconfig flag");
+ break;
+ }
+
+ if (isReadOnly(key)) {
+ pout.println("Error: cannot write read-only flag");
+ break;
+ }
+ }
+ }
+
pout.println(delete(iprovider, namespace, key)
? "Successfully deleted " + key + " from " + namespace
: "Failed to delete " + key + " from " + namespace);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
index b1e6d6650226..006e644b2ac7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
+++ b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
@@ -70,3 +70,14 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "check_root_and_read_only"
+ namespace: "core_experiments_team_internal"
+ description: "Check root and aconfig flag permissions in adb shell device_config commands."
+ bug: "342636474"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 5ea75be11c47..3aa89eec54ff 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -838,14 +838,6 @@ android_app {
],
manifest: "tests/AndroidManifest-base.xml",
- srcs: [
- "src/**/*.kt",
- "src/**/*.java",
- "src/**/I*.aidl",
- ":ReleaseJavaFiles",
- "compose/features/src/**/*.kt",
- "compose/facade/enabled/src/**/*.kt",
- ],
static_libs: [
"//frameworks/libs/systemui:compilelib",
"SystemUI-tests-base",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1d9f46971502..398c915b02b3 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -480,6 +480,7 @@
<activity android:name=".touchpad.tutorial.ui.view.TouchpadTutorialActivity"
android:exported="true"
+ android:screenOrientation="userLandscape"
android:theme="@style/Theme.AppCompat.NoActionBar">
<intent-filter>
<action android:name="com.android.systemui.action.TOUCHPAD_TUTORIAL"/>
@@ -489,6 +490,7 @@
<activity android:name=".inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity"
android:exported="true"
+ android:screenOrientation="userLandscape"
android:theme="@style/Theme.AppCompat.NoActionBar">
<intent-filter>
<action android:name="com.android.systemui.action.TOUCHPAD_KEYBOARD_TUTORIAL"/>
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 3a46882c0ab9..aeba67bd121c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -66,7 +66,7 @@ constructor(
override val destinationScenes: Flow<Map<UserAction, UserActionResult>> =
actionsViewModel.actions
- override suspend fun activate() {
+ override suspend fun activate(): Nothing {
actionsViewModel.activate()
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index 7fe1b3e619c1..7f059d766307 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -49,7 +49,7 @@ constructor(
override val destinationScenes: Flow<Map<UserAction, UserActionResult>> =
actionsViewModel.actions
- override suspend fun activate() {
+ override suspend fun activate(): Nothing {
actionsViewModel.activate()
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
index 0cb8bd3a7efb..666e324c8d36 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
@@ -72,7 +72,7 @@ constructor(
override val destinationScenes: Flow<Map<UserAction, UserActionResult>> =
actionsViewModel.actions
- override suspend fun activate() {
+ override suspend fun activate(): Nothing {
actionsViewModel.activate()
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 9db8bf14e5e0..e0647242b7ad 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -139,7 +139,7 @@ constructor(
override val destinationScenes: Flow<Map<UserAction, UserActionResult>> =
actionsViewModel.actions
- override suspend fun activate() {
+ override suspend fun activate(): Nothing {
actionsViewModel.activate()
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index f15e87b4514d..3e221056c2db 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -58,7 +58,7 @@ constructor(
override val destinationScenes: Flow<Map<UserAction, UserActionResult>> =
actionsViewModel.actions
- override suspend fun activate() {
+ override suspend fun activate(): Nothing {
actionsViewModel.activate()
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 7dc53eaf53ac..d15bda0b362b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -167,7 +167,7 @@ constructor(
actionsViewModelFactory.create()
}
- override suspend fun activate() {
+ override suspend fun activate(): Nothing {
actionsViewModel.activate()
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index 79b38563b8f9..5e963811729a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -245,9 +245,7 @@ interface OverscrollScope : Density {
interface ElementContentPicker {
/**
* Return the content in which [element] should be drawn (when using `Modifier.element(key)`) or
- * composed (when using `MovableElement(key)`) during the given [transition]. If this element
- * should not be drawn or composed in neither [transition.fromContent] nor
- * [transition.toContent], return `null`.
+ * composed (when using `MovableElement(key)`) during the given [transition].
*
* Important: For [MovableElements][ContentScope.MovableElement], this content picker will
* *always* be used during transitions to decide whether we should compose that element in a
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorTest.kt
index d6712f09cd4e..c5518b029bc1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorTest.kt
@@ -53,6 +53,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -78,6 +79,7 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() {
private val underTest by lazy { kosmos.communalSceneTransitionInteractor }
private val keyguardTransitionRepository by lazy { kosmos.realKeyguardTransitionRepository }
+ private val keyguardRepository by lazy { kosmos.fakeKeyguardRepository }
private val ownerName = CommunalSceneTransitionInteractor::class.java.simpleName
private val progress = MutableSharedFlow<Float>()
@@ -789,4 +791,47 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() {
)
)
}
+
+ /** Verifies that we correctly transition to GONE after keyguard goes away */
+ @Test
+ fun transition_to_blank_after_unlock_should_go_to_gone() =
+ testScope.runTest {
+ keyguardRepository.setKeyguardShowing(true)
+ sceneTransitions.value = Idle(CommunalScenes.Communal)
+
+ val currentStep by collectLastValue(keyguardTransitionRepository.transitions)
+
+ assertThat(currentStep)
+ .isEqualTo(
+ TransitionStep(
+ from = LOCKSCREEN,
+ to = GLANCEABLE_HUB,
+ transitionState = FINISHED,
+ value = 1f,
+ ownerName = ownerName,
+ )
+ )
+
+ // Keyguard starts exiting after a while, then fully exits after some time.
+ advanceTimeBy(1.seconds)
+ keyguardRepository.setKeyguardGoingAway(true)
+ advanceTimeBy(2.seconds)
+ keyguardRepository.setKeyguardGoingAway(false)
+ keyguardRepository.setKeyguardShowing(false)
+ runCurrent()
+
+ // We snap to the blank scene as a result of keyguard going away.
+ sceneTransitions.value = Idle(CommunalScenes.Blank)
+
+ assertThat(currentStep)
+ .isEqualTo(
+ TransitionStep(
+ from = GLANCEABLE_HUB,
+ to = GONE,
+ transitionState = FINISHED,
+ value = 1f,
+ ownerName = ownerName,
+ )
+ )
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/EditWidgetsActivityControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/EditWidgetsActivityControllerTest.kt
deleted file mode 100644
index 50fdb31b0414..000000000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/EditWidgetsActivityControllerTest.kt
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2024 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.communal.widgets
-
-import android.app.Activity
-import android.app.Application.ActivityLifecycleCallbacks
-import android.os.Bundle
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.kotlin.argumentCaptor
-import org.mockito.kotlin.clearInvocations
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.never
-import org.mockito.kotlin.verify
-
-@ExperimentalCoroutinesApi
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class EditWidgetsActivityControllerTest : SysuiTestCase() {
- @Test
- fun activityLifecycle_stoppedWhenNotWaitingForResult() {
- val activity = mock<Activity>()
- val controller = EditWidgetsActivity.ActivityController(activity)
-
- val callbackCapture = argumentCaptor<ActivityLifecycleCallbacks>()
- verify(activity).registerActivityLifecycleCallbacks(callbackCapture.capture())
-
- callbackCapture.lastValue.onActivityStopped(activity)
-
- verify(activity).finish()
- }
-
- @Test
- fun activityLifecycle_notStoppedWhenNotWaitingForResult() {
- val activity = mock<Activity>()
- val controller = EditWidgetsActivity.ActivityController(activity)
-
- val callbackCapture = argumentCaptor<ActivityLifecycleCallbacks>()
- verify(activity).registerActivityLifecycleCallbacks(callbackCapture.capture())
-
- controller.onWaitingForResult(true)
- callbackCapture.lastValue.onActivityStopped(activity)
-
- verify(activity, never()).finish()
- }
-
- @Test
- fun activityLifecycle_stoppedAfterResultReturned() {
- val activity = mock<Activity>()
- val controller = EditWidgetsActivity.ActivityController(activity)
-
- val callbackCapture = argumentCaptor<ActivityLifecycleCallbacks>()
- verify(activity).registerActivityLifecycleCallbacks(callbackCapture.capture())
-
- controller.onWaitingForResult(true)
- controller.onWaitingForResult(false)
- callbackCapture.lastValue.onActivityStopped(activity)
-
- verify(activity).finish()
- }
-
- @Test
- fun activityLifecycle_statePreservedThroughInstanceSave() {
- val activity = mock<Activity>()
- val bundle = Bundle(1)
-
- run {
- val controller = EditWidgetsActivity.ActivityController(activity)
- val callbackCapture = argumentCaptor<ActivityLifecycleCallbacks>()
- verify(activity).registerActivityLifecycleCallbacks(callbackCapture.capture())
-
- controller.onWaitingForResult(true)
- callbackCapture.lastValue.onActivitySaveInstanceState(activity, bundle)
- }
-
- clearInvocations(activity)
-
- run {
- val controller = EditWidgetsActivity.ActivityController(activity)
- val callbackCapture = argumentCaptor<ActivityLifecycleCallbacks>()
- verify(activity).registerActivityLifecycleCallbacks(callbackCapture.capture())
-
- callbackCapture.lastValue.onActivityCreated(activity, bundle)
- callbackCapture.lastValue.onActivityStopped(activity)
-
- verify(activity, never()).finish()
- }
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
index 400f736ba882..9c308a60d3f0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
@@ -25,15 +25,19 @@ import androidx.core.util.component1
import androidx.core.util.component2
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.keyguard.keyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.widgetTrampolineInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.backgroundCoroutineContext
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.testKosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -41,12 +45,14 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.eq
import org.mockito.kotlin.isNull
import org.mockito.kotlin.mock
import org.mockito.kotlin.refEq
import org.mockito.kotlin.verify
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class WidgetInteractionHandlerTest : SysuiTestCase() {
@@ -70,8 +76,10 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
underTest =
WidgetInteractionHandler(
applicationScope = applicationCoroutineScope,
+ uiBackgroundContext = backgroundCoroutineContext,
activityStarter = activityStarter,
communalSceneInteractor = communalSceneInteractor,
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
logBuffer = logcatLogBuffer(),
widgetTrampolineInteractor = widgetTrampolineInteractor,
)
@@ -95,16 +103,21 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
// Verify that we set the state correctly
assertTrue(launching!!)
// Verify that we pass in a non-null Communal animation controller
+
+ val callbackCaptor = argumentCaptor<Runnable>()
verify(activityStarter)
.startPendingIntentMaybeDismissingKeyguard(
/* intent = */ eq(testIntent),
/* dismissShade = */ eq(false),
- /* intentSentUiThreadCallback = */ isNull(),
+ /* intentSentUiThreadCallback = */ callbackCaptor.capture(),
/* animationController = */ any<CommunalTransitionAnimatorController>(),
/* fillInIntent = */ refEq(fillInIntent),
/* extraOptions = */ refEq(activityOptions.toBundle()),
/* customMessage */ isNull(),
)
+ callbackCaptor.firstValue.run()
+ runCurrent()
+ verify(keyguardUpdateMonitor).awakenFromDream()
}
}
}
@@ -123,7 +136,7 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
.startPendingIntentMaybeDismissingKeyguard(
/* intent = */ eq(testIntent),
/* dismissShade = */ eq(false),
- /* intentSentUiThreadCallback = */ isNull(),
+ /* intentSentUiThreadCallback = */ any(),
/* animationController = */ isNull(),
/* fillInIntent = */ refEq(fillInIntent),
/* extraOptions = */ refEq(activityOptions.toBundle()),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt
index 5dd6c228e014..f82beff11d8f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt
@@ -51,6 +51,7 @@ class ContextualEducationRepositoryTest : SysuiTestCase() {
}
private val testUserId = 1111
+ private val secondTestUserId = 1112
// For deleting any test files created after the test
@get:Rule val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build()
@@ -73,12 +74,21 @@ class ContextualEducationRepositoryTest : SysuiTestCase() {
assertThat(model?.signalCount).isEqualTo(1)
// User is changed.
- underTest.setUser(1112)
+ underTest.setUser(secondTestUserId)
// Assert count is 0 after user is changed.
assertThat(model?.signalCount).isEqualTo(0)
}
@Test
+ fun changeUserIdForNewUser() =
+ testScope.runTest {
+ val model by collectLastValue(underTest.readGestureEduModelFlow(BACK))
+ assertThat(model?.userId).isEqualTo(testUserId)
+ underTest.setUser(secondTestUserId)
+ assertThat(model?.userId).isEqualTo(secondTestUserId)
+ }
+
+ @Test
fun dataChangedOnUpdate() =
testScope.runTest {
val newModel =
@@ -88,6 +98,7 @@ class ContextualEducationRepositoryTest : SysuiTestCase() {
lastShortcutTriggeredTime = kosmos.fakeEduClock.instant(),
lastEducationTime = kosmos.fakeEduClock.instant(),
usageSessionStartTime = kosmos.fakeEduClock.instant(),
+ userId = testUserId
)
underTest.updateGestureEduModel(BACK) { newModel }
val model by collectLastValue(underTest.readGestureEduModelFlow(BACK))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
index 6867089473da..23f923a6fb09 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
@@ -109,7 +109,8 @@ class KeyboardTouchpadEduInteractorTest : SysuiTestCase() {
.isEqualTo(
GestureEduModel(
signalCount = 1,
- usageSessionStartTime = secondSignalReceivedTime
+ usageSessionStartTime = secondSignalReceivedTime,
+ userId = 0
)
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
index 1f733472cbed..e075b7edda40 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
@@ -16,6 +16,8 @@
package com.android.systemui.education.domain.ui.view
+import android.app.Notification
+import android.app.NotificationManager
import android.content.applicationContext
import android.widget.Toast
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -30,27 +32,35 @@ import com.android.systemui.education.ui.view.ContextualEduUiCoordinator
import com.android.systemui.education.ui.viewmodel.ContextualEduViewModel
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.any
import org.mockito.kotlin.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
class ContextualEduUiCoordinatorTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val interactor = kosmos.contextualEducationInteractor
private lateinit var underTest: ContextualEduUiCoordinator
@Mock private lateinit var toast: Toast
-
+ @Mock private lateinit var notificationManager: NotificationManager
@get:Rule val mockitoRule = MockitoJUnit.rule()
+ private var toastContent = ""
@Before
fun setUp() {
@@ -60,23 +70,76 @@ class ContextualEduUiCoordinatorTest : SysuiTestCase() {
kosmos.keyboardTouchpadEduInteractor
)
underTest =
- ContextualEduUiCoordinator(kosmos.applicationCoroutineScope, viewModel) { _ -> toast }
+ ContextualEduUiCoordinator(
+ kosmos.applicationCoroutineScope,
+ viewModel,
+ kosmos.applicationContext,
+ notificationManager
+ ) { content ->
+ toastContent = content
+ toast
+ }
underTest.start()
kosmos.keyboardTouchpadEduInteractor.start()
}
@Test
- @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun showToastOnNewEdu() =
testScope.runTest {
triggerEducation(BACK)
- runCurrent()
verify(toast).show()
}
- private suspend fun triggerEducation(gestureType: GestureType) {
+ @Test
+ fun showNotificationOn2ndEdu() =
+ testScope.runTest {
+ triggerEducation(BACK)
+ triggerEducation(BACK)
+ verify(notificationManager).notifyAsUser(any(), anyInt(), any(), any())
+ }
+
+ @Test
+ fun verifyBackEduToastContent() =
+ testScope.runTest {
+ triggerEducation(BACK)
+ assertThat(toastContent).isEqualTo(context.getString(R.string.back_edu_toast_content))
+ }
+
+ @Test
+ fun verifyBackEduNotificationContent() =
+ testScope.runTest {
+ val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java)
+ triggerEducation(BACK)
+ triggerEducation(BACK)
+ verify(notificationManager)
+ .notifyAsUser(any(), anyInt(), notificationCaptor.capture(), any())
+ verifyNotificationContent(
+ R.string.back_edu_notification_title,
+ R.string.back_edu_notification_content,
+ notificationCaptor.value
+ )
+ }
+
+ private fun verifyNotificationContent(
+ titleResId: Int,
+ contentResId: Int,
+ notification: Notification
+ ) {
+ val expectedContent = context.getString(contentResId)
+ val expectedTitle = context.getString(titleResId)
+ val actualContent = notification.getString(Notification.EXTRA_TEXT)
+ val actualTitle = notification.getString(Notification.EXTRA_TITLE)
+ assertThat(actualContent).isEqualTo(expectedContent)
+ assertThat(actualTitle).isEqualTo(expectedTitle)
+ }
+
+ private fun Notification.getString(key: String): String =
+ this.extras?.getCharSequence(key).toString()
+
+ private suspend fun TestScope.triggerEducation(gestureType: GestureType) {
for (i in 1..KeyboardTouchpadEduInteractor.MAX_SIGNAL_COUNT) {
interactor.incrementSignalCount(gestureType)
}
+ runCurrent()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
index 46b370fedf37..976dc52b2602 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
@@ -154,7 +154,7 @@ class SysUiViewModelTest : SysuiTestCase() {
private class FakeViewModel : SysUiViewModel() {
var isActivated = false
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
isActivated = true
try {
awaitCancellation()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropStateTest.kt
deleted file mode 100644
index b2f5765d0bc4..000000000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropStateTest.kt
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.panels.ui.compose
-
-import androidx.compose.runtime.mutableStateOf
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.common.shared.model.Text
-import com.android.systemui.qs.panels.shared.model.SizedTile
-import com.android.systemui.qs.panels.shared.model.SizedTileImpl
-import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class DragAndDropStateTest : SysuiTestCase() {
- private val listState = EditTileListState(TestEditTiles)
- private val underTest = DragAndDropState(mutableStateOf(null), listState)
-
- @Test
- fun isMoving_returnsCorrectValue() {
- // Asserts no tiles is moving
- TestEditTiles.forEach { assertThat(underTest.isMoving(it.tile.tileSpec)).isFalse() }
-
- // Start the drag movement
- underTest.onStarted(TestEditTiles[0])
-
- // Assert that the correct tile is marked as moving
- TestEditTiles.forEach {
- assertThat(underTest.isMoving(it.tile.tileSpec))
- .isEqualTo(TestEditTiles[0].tile.tileSpec == it.tile.tileSpec)
- }
- }
-
- @Test
- fun onMoved_updatesList() {
- // Start the drag movement
- underTest.onStarted(TestEditTiles[0])
-
- // Move the tile to the end of the list
- underTest.onMoved(listState.tiles[5].tile.tileSpec)
- assertThat(underTest.currentPosition()).isEqualTo(5)
-
- // Move the tile to the middle of the list
- underTest.onMoved(listState.tiles[2].tile.tileSpec)
- assertThat(underTest.currentPosition()).isEqualTo(2)
- }
-
- @Test
- fun onDrop_resetsMovingTile() {
- // Start the drag movement
- underTest.onStarted(TestEditTiles[0])
-
- // Move the tile to the end of the list
- underTest.onMoved(listState.tiles[5].tile.tileSpec)
-
- // Drop the tile
- underTest.onDrop()
-
- // Asserts no tiles is moving
- TestEditTiles.forEach { assertThat(underTest.isMoving(it.tile.tileSpec)).isFalse() }
- }
-
- @Test
- fun onMoveOutOfBounds_removeMovingTileFromCurrentList() {
- // Start the drag movement
- underTest.onStarted(TestEditTiles[0])
-
- // Move the tile outside of the list
- underTest.movedOutOfBounds()
-
- // Asserts the moving tile is not current
- assertThat(
- listState.tiles.firstOrNull { it.tile.tileSpec == TestEditTiles[0].tile.tileSpec }
- )
- .isNull()
- }
-
- companion object {
- private fun createEditTile(tileSpec: String): SizedTile<EditTileViewModel> {
- return SizedTileImpl(
- EditTileViewModel(
- tileSpec = TileSpec.create(tileSpec),
- icon = Icon.Resource(0, null),
- label = Text.Loaded("unused"),
- appName = null,
- isCurrent = true,
- availableEditActions = emptySet(),
- ),
- 1,
- )
- }
-
- private val TestEditTiles =
- listOf(
- createEditTile("tileA"),
- createEditTile("tileB"),
- createEditTile("tileC"),
- createEditTile("tileD"),
- createEditTile("tileE"),
- createEditTile("tileF"),
- )
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
new file mode 100644
index 000000000000..4d1dd1cce766
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.compose
+
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.hasContentDescription
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChildAt
+import androidx.compose.ui.test.onChildren
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.qs.panels.shared.model.SizedTile
+import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DragAndDropTest : SysuiTestCase() {
+ @get:Rule val composeRule = createComposeRule()
+
+ // TODO(ostonge): Investigate why drag isn't detected when using performTouchInput
+ @Composable
+ private fun EditTileGridUnderTest(
+ listState: EditTileListState,
+ onSetTiles: (List<TileSpec>) -> Unit
+ ) {
+ DefaultEditTileGrid(
+ currentListState = listState,
+ otherTiles = listOf(),
+ columns = 4,
+ modifier = Modifier.fillMaxSize(),
+ onAddTile = { _, _ -> },
+ onRemoveTile = {},
+ onSetTiles = onSetTiles,
+ onResize = {},
+ )
+ }
+
+ @Test
+ fun draggedTile_shouldDisappear() {
+ var tiles by mutableStateOf(TestEditTiles)
+ val listState = EditTileListState(tiles, 4)
+ composeRule.setContent {
+ EditTileGridUnderTest(listState) {
+ tiles = it.map { tileSpec -> createEditTile(tileSpec.spec) }
+ }
+ }
+ composeRule.waitForIdle()
+
+ listState.onStarted(TestEditTiles[0])
+
+ // Tile is being dragged, it should be replaced with a placeholder
+ composeRule.onNodeWithContentDescription("tileA").assertDoesNotExist()
+
+ // Available tiles should disappear
+ composeRule.onNodeWithTag(AVAILABLE_TILES_GRID_TEST_TAG).assertDoesNotExist()
+
+ // Remove drop zone should appear
+ composeRule.onNodeWithText("Remove").assertExists()
+
+ // Every other tile should still be in the same order
+ composeRule.assertTileGridContainsExactly(listOf("tileB", "tileC", "tileD_large", "tileE"))
+ }
+
+ @Test
+ fun draggedTile_shouldChangePosition() {
+ var tiles by mutableStateOf(TestEditTiles)
+ val listState = EditTileListState(tiles, 4)
+ composeRule.setContent {
+ EditTileGridUnderTest(listState) {
+ tiles = it.map { tileSpec -> createEditTile(tileSpec.spec) }
+ }
+ }
+ composeRule.waitForIdle()
+
+ listState.onStarted(TestEditTiles[0])
+ listState.onMoved(1, false)
+ listState.onDrop()
+
+ // Available tiles should re-appear
+ composeRule.onNodeWithTag(AVAILABLE_TILES_GRID_TEST_TAG).assertExists()
+
+ // Remove drop zone should disappear
+ composeRule.onNodeWithText("Remove").assertDoesNotExist()
+
+ // Tile A and B should swap places
+ composeRule.assertTileGridContainsExactly(
+ listOf("tileB", "tileA", "tileC", "tileD_large", "tileE")
+ )
+ }
+
+ @Test
+ fun draggedTileOut_shouldBeRemoved() {
+ var tiles by mutableStateOf(TestEditTiles)
+ val listState = EditTileListState(tiles, 4)
+ composeRule.setContent {
+ EditTileGridUnderTest(listState) {
+ tiles = it.map { tileSpec -> createEditTile(tileSpec.spec) }
+ }
+ }
+ composeRule.waitForIdle()
+
+ listState.onStarted(TestEditTiles[0])
+ listState.movedOutOfBounds()
+ listState.onDrop()
+
+ // Available tiles should re-appear
+ composeRule.onNodeWithTag(AVAILABLE_TILES_GRID_TEST_TAG).assertExists()
+
+ // Remove drop zone should disappear
+ composeRule.onNodeWithText("Remove").assertDoesNotExist()
+
+ // Tile A is gone
+ composeRule.assertTileGridContainsExactly(listOf("tileB", "tileC", "tileD_large", "tileE"))
+ }
+
+ @Test
+ fun draggedNewTileIn_shouldBeAdded() {
+ var tiles by mutableStateOf(TestEditTiles)
+ val listState = EditTileListState(tiles, 4)
+ composeRule.setContent {
+ EditTileGridUnderTest(listState) {
+ tiles = it.map { tileSpec -> createEditTile(tileSpec.spec) }
+ }
+ }
+ composeRule.waitForIdle()
+
+ listState.onStarted(createEditTile("newTile"))
+ // Insert after tileD, which is at index 4
+ // [ a ] [ b ] [ c ] [ empty ]
+ // [ tile d ] [ e ]
+ listState.onMoved(4, insertAfter = true)
+ listState.onDrop()
+
+ // Available tiles should re-appear
+ composeRule.onNodeWithTag(AVAILABLE_TILES_GRID_TEST_TAG).assertExists()
+
+ // Remove drop zone should disappear
+ composeRule.onNodeWithText("Remove").assertDoesNotExist()
+
+ // newTile is added after tileD
+ composeRule.assertTileGridContainsExactly(
+ listOf("tileA", "tileB", "tileC", "tileD_large", "newTile", "tileE")
+ )
+ }
+
+ private fun ComposeContentTestRule.assertTileGridContainsExactly(specs: List<String>) {
+ onNodeWithTag(CURRENT_TILES_GRID_TEST_TAG).onChildren().apply {
+ fetchSemanticsNodes().forEachIndexed { index, _ ->
+ get(index).onChildAt(0).assert(hasContentDescription(specs[index]))
+ }
+ }
+ }
+
+ companion object {
+ private const val CURRENT_TILES_GRID_TEST_TAG = "CurrentTilesGrid"
+ private const val AVAILABLE_TILES_GRID_TEST_TAG = "AvailableTilesGrid"
+
+ private fun createEditTile(tileSpec: String): SizedTile<EditTileViewModel> {
+ return SizedTileImpl(
+ EditTileViewModel(
+ tileSpec = TileSpec.create(tileSpec),
+ icon =
+ Icon.Resource(
+ android.R.drawable.star_on,
+ ContentDescription.Loaded(tileSpec)
+ ),
+ label = Text.Loaded(tileSpec),
+ appName = null,
+ isCurrent = true,
+ availableEditActions = emptySet(),
+ ),
+ getWidth(tileSpec),
+ )
+ }
+
+ private fun getWidth(tileSpec: String): Int {
+ return if (tileSpec.endsWith("large")) {
+ 2
+ } else {
+ 1
+ }
+ }
+
+ private val TestEditTiles =
+ listOf(
+ createEditTile("tileA"),
+ createEditTile("tileB"),
+ createEditTile("tileC"),
+ createEditTile("tileD_large"),
+ createEditTile("tileE"),
+ )
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt
index a3a6a33f6408..7f01fad1ce55 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt
@@ -23,6 +23,9 @@ import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.model.GridCell
+import com.android.systemui.qs.panels.ui.model.SpacerGridCell
+import com.android.systemui.qs.panels.ui.model.TileGridCell
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.google.common.truth.Truth.assertThat
@@ -32,80 +35,130 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class EditTileListStateTest : SysuiTestCase() {
- val underTest = EditTileListState(TestEditTiles)
+ private val underTest = EditTileListState(TestEditTiles, 4)
@Test
- fun movingNonExistentTile_tileAdded() {
- val newTile = createEditTile("other_tile", false)
- underTest.move(newTile, TestEditTiles[0].tile.tileSpec)
-
- assertThat(underTest.tiles[0]).isEqualTo(newTile)
- assertThat(underTest.tiles.subList(1, underTest.tiles.size))
- .containsExactly(*TestEditTiles.toTypedArray())
+ fun noDrag_listUnchanged() {
+ underTest.tiles.forEach { assertThat(it).isNotInstanceOf(SpacerGridCell::class.java) }
+ assertThat(underTest.tiles.map { (it as TileGridCell).tile.tileSpec })
+ .containsExactly(*TestEditTiles.map { it.tile.tileSpec }.toTypedArray())
}
@Test
- fun movingTileToNonExistentTarget_listUnchanged() {
- underTest.move(TestEditTiles[0], TileSpec.create("other_tile"))
+ fun startDrag_listHasSpacers() {
+ underTest.onStarted(TestEditTiles[0])
+
+ // [ a ] [ b ] [ c ] [ X ]
+ // [ Large D ] [ e ] [ X ]
+ assertThat(underTest.tiles.toStrings())
+ .isEqualTo(listOf("a", "b", "c", "spacer", "d", "e", "spacer"))
+ assertThat(underTest.isMoving(TestEditTiles[0].tile.tileSpec)).isTrue()
+ assertThat(underTest.dragInProgress).isTrue()
+ }
- assertThat(underTest.tiles).containsExactly(*TestEditTiles.toTypedArray())
+ @Test
+ fun moveDrag_listChanges() {
+ underTest.onStarted(TestEditTiles[4])
+ underTest.onMoved(3, false)
+
+ // Tile E goes to index 3
+ // [ a ] [ b ] [ c ] [ e ]
+ // [ Large D ] [ X ] [ X ]
+ assertThat(underTest.tiles.toStrings())
+ .isEqualTo(listOf("a", "b", "c", "e", "d", "spacer", "spacer"))
}
@Test
- fun movingTileToItself_listUnchanged() {
- underTest.move(TestEditTiles[0], TestEditTiles[0].tile.tileSpec)
+ fun moveDragOnSidesOfLargeTile_listChanges() {
+ val draggedCell = TestEditTiles[4]
+
+ underTest.onStarted(draggedCell)
+ underTest.onMoved(4, true)
- assertThat(underTest.tiles).containsExactly(*TestEditTiles.toTypedArray())
+ // Tile E goes to the right side of tile D, list is unchanged
+ // [ a ] [ b ] [ c ] [ X ]
+ // [ Large D ] [ e ] [ X ]
+ assertThat(underTest.tiles.toStrings())
+ .isEqualTo(listOf("a", "b", "c", "spacer", "d", "e", "spacer"))
+
+ underTest.onMoved(4, false)
+
+ // Tile E goes to the left side of tile D, they swap positions
+ // [ a ] [ b ] [ c ] [ e ]
+ // [ Large D ] [ X ] [ X ]
+ assertThat(underTest.tiles.toStrings())
+ .isEqualTo(listOf("a", "b", "c", "e", "d", "spacer", "spacer"))
}
@Test
- fun movingTileToSameSection_listUpdates() {
- // Move tile at index 0 to index 1. Tile 0 should remain current.
- underTest.move(TestEditTiles[0], TestEditTiles[1].tile.tileSpec)
+ fun moveNewTile_tileIsAdded() {
+ val newTile = createEditTile("newTile", 2)
+
+ underTest.onStarted(newTile)
+ underTest.onMoved(5, false)
+
+ // New tile goes to index 5
+ // [ a ] [ b ] [ c ] [ X ]
+ // [ Large D ] [ newTile ]
+ // [ e ] [ X ] [ X ] [ X ]
+ assertThat(underTest.tiles.toStrings())
+ .isEqualTo(
+ listOf("a", "b", "c", "spacer", "d", "newTile", "e", "spacer", "spacer", "spacer")
+ )
+ }
- // Assert the tiles 0 and 1 have changed places.
- assertThat(underTest.tiles[0]).isEqualTo(TestEditTiles[1])
- assertThat(underTest.tiles[1]).isEqualTo(TestEditTiles[0])
+ @Test
+ fun droppedNewTile_spacersDisappear() {
+ underTest.onStarted(TestEditTiles[0])
+ underTest.onDrop()
- // Assert the rest of the list is unchanged
- assertThat(underTest.tiles.subList(2, 5))
- .containsExactly(*TestEditTiles.subList(2, 5).toTypedArray())
+ assertThat(underTest.tiles.toStrings()).isEqualTo(listOf("a", "b", "c", "d", "e"))
+ assertThat(underTest.isMoving(TestEditTiles[0].tile.tileSpec)).isFalse()
+ assertThat(underTest.dragInProgress).isFalse()
}
- fun removingTile_listUpdates() {
- // Remove tile at index 0
- underTest.remove(TestEditTiles[0].tile.tileSpec)
+ @Test
+ fun movedTileOutOfBounds_tileDisappears() {
+ underTest.onStarted(TestEditTiles[0])
+ underTest.movedOutOfBounds()
+
+ assertThat(underTest.tiles.toStrings()).doesNotContain(TestEditTiles[0].tile.tileSpec.spec)
+ }
- // Assert the tile was removed
- assertThat(underTest.tiles).containsExactly(*TestEditTiles.subList(1, 6).toTypedArray())
+ private fun List<GridCell>.toStrings(): List<String> {
+ return map {
+ if (it is TileGridCell) {
+ it.tile.tileSpec.spec
+ } else {
+ "spacer"
+ }
+ }
}
companion object {
- private fun createEditTile(
- tileSpec: String,
- isCurrent: Boolean
- ): SizedTile<EditTileViewModel> {
+ private fun createEditTile(tileSpec: String, width: Int): SizedTile<EditTileViewModel> {
return SizedTileImpl(
EditTileViewModel(
tileSpec = TileSpec.create(tileSpec),
icon = Icon.Resource(0, null),
label = Text.Loaded("unused"),
appName = null,
- isCurrent = isCurrent,
+ isCurrent = true,
availableEditActions = emptySet(),
),
- 1,
+ width,
)
}
+ // [ a ] [ b ] [ c ]
+ // [ Large D ] [ e ] [ f ]
private val TestEditTiles =
listOf(
- createEditTile("tileA", true),
- createEditTile("tileB", true),
- createEditTile("tileC", true),
- createEditTile("tileD", false),
- createEditTile("tileE", false),
- createEditTile("tileF", false),
+ createEditTile("a", 1),
+ createEditTile("b", 1),
+ createEditTile("c", 1),
+ createEditTile("d", 2),
+ createEditTile("e", 1),
)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index aee3ce052d78..9122528e5c11 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -328,6 +328,16 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
}
@Test
+ fun lockDeviceLocksDevice() =
+ testScope.runTest {
+ unlockDevice()
+ assertCurrentScene(Scenes.Gone)
+
+ lockDevice()
+ assertCurrentScene(Scenes.Lockscreen)
+ }
+
+ @Test
fun deviceGoesToSleep_switchesToLockscreen() =
testScope.runTest {
unlockDevice()
@@ -616,7 +626,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
assertWithMessage("The authentication method of $authMethod is not secure, cannot lock!")
.that(authMethod.isSecure)
.isTrue()
-
+ kosmos.sceneInteractor.changeScene(Scenes.Lockscreen, "")
runCurrent()
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index edf855fe5576..64fe78d9958b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -19,8 +19,8 @@ package com.android.systemui.shared.recents.model;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index a30115568842..baf8f5aeba29 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -49,6 +49,7 @@ import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -139,6 +140,7 @@ public class Dependency {
@Inject Lazy<SysUiState> mSysUiStateFlagsContainer;
@Inject Lazy<CommandQueue> mCommandQueue;
@Inject Lazy<UiEventLogger> mUiEventLogger;
+ @Inject Lazy<StatusBarContentInsetsProvider> mContentInsetsProviderLazy;
@Inject Lazy<FeatureFlags> mFeatureFlagsLazy;
@Inject Lazy<NotificationSectionsManager> mNotificationSectionsManagerLazy;
@Inject Lazy<ScreenOffAnimationController> mScreenOffAnimationController;
@@ -184,6 +186,7 @@ public class Dependency {
mProviders.put(CommandQueue.class, mCommandQueue::get);
mProviders.put(UiEventLogger.class, mUiEventLogger::get);
mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get);
+ mProviders.put(StatusBarContentInsetsProvider.class, mContentInsetsProviderLazy::get);
mProviders.put(NotificationSectionsManager.class, mNotificationSectionsManagerLazy::get);
mProviders.put(ScreenOffAnimationController.class, mScreenOffAnimationController::get);
mProviders.put(AmbientState.class, mAmbientStateLazy::get);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index f4a1f0546135..e4b7b7e69c61 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -37,6 +37,7 @@ import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver.AccessibilityButtonMode;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.util.settings.SecureSettings;
@@ -61,6 +62,7 @@ public class AccessibilityFloatingMenuController implements
private final SecureSettings mSecureSettings;
private final DisplayTracker mDisplayTracker;
+ private final NavigationModeController mNavigationModeController;
@VisibleForTesting
IAccessibilityFloatingMenu mFloatingMenu;
private int mBtnMode;
@@ -106,7 +108,8 @@ public class AccessibilityFloatingMenuController implements
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
KeyguardUpdateMonitor keyguardUpdateMonitor,
SecureSettings secureSettings,
- DisplayTracker displayTracker) {
+ DisplayTracker displayTracker,
+ NavigationModeController navigationModeController) {
mContext = context;
mWindowManager = windowManager;
mViewCaptureAwareWindowManager = viewCaptureAwareWindowManager;
@@ -117,6 +120,7 @@ public class AccessibilityFloatingMenuController implements
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mSecureSettings = secureSettings;
mDisplayTracker = displayTracker;
+ mNavigationModeController = navigationModeController;
mIsKeyguardVisible = false;
}
@@ -191,7 +195,8 @@ public class AccessibilityFloatingMenuController implements
final Context windowContext = mContext.createWindowContext(defaultDisplay,
TYPE_NAVIGATION_BAR_PANEL, /* options= */ null);
mFloatingMenu = new MenuViewLayerController(windowContext, mWindowManager,
- mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings);
+ mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings,
+ mNavigationModeController);
}
mFloatingMenu.show();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java
index 7fd72ec8ce93..d718ae35dff0 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java
@@ -32,7 +32,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Flags;
import com.android.wm.shell.common.bubbles.DismissCircleView;
import com.android.wm.shell.common.bubbles.DismissView;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import java.util.Map;
import java.util.Objects;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 27ded747fd55..d62162b368fa 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -77,11 +77,12 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.util.Preconditions;
import com.android.systemui.Flags;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.res.R;
import com.android.systemui.util.settings.SecureSettings;
import com.android.wm.shell.bubbles.DismissViewUtils;
import com.android.wm.shell.common.bubbles.DismissView;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -142,6 +143,8 @@ class MenuViewLayer extends FrameLayout implements
private boolean mIsNotificationShown;
private Optional<MenuEduTooltipView> mEduTooltipView = Optional.empty();
private BroadcastReceiver mNotificationActionReceiver;
+ private NavigationModeController mNavigationModeController;
+ private NavigationModeController.ModeChangedListener mNavigationModeChangedListender;
@IntDef({
LayerIndex.MENU_VIEW,
@@ -220,7 +223,8 @@ class MenuViewLayer extends FrameLayout implements
MenuViewModel menuViewModel,
MenuViewAppearance menuViewAppearance, MenuView menuView,
IAccessibilityFloatingMenu floatingMenu,
- SecureSettings secureSettings) {
+ SecureSettings secureSettings,
+ NavigationModeController navigationModeController) {
super(context);
// Simplifies the translation positioning and animations
@@ -253,6 +257,8 @@ class MenuViewLayer extends FrameLayout implements
mNotificationFactory = new MenuNotificationFactory(context);
mNotificationManager = context.getSystemService(NotificationManager.class);
mStatusBarManager = context.getSystemService(StatusBarManager.class);
+ mNavigationModeController = navigationModeController;
+ mNavigationModeChangedListender = (mode -> mMenuView.onPositionChanged());
if (Flags.floatingMenuDragToEdit()) {
mDragToInteractAnimationController = new DragToInteractAnimationController(
@@ -381,6 +387,7 @@ class MenuViewLayer extends FrameLayout implements
mMigrationTooltipObserver);
mMessageView.setUndoListener(view -> undo());
getContext().registerComponentCallbacks(this);
+ mNavigationModeController.addListener(mNavigationModeChangedListender);
}
@Override
@@ -396,6 +403,7 @@ class MenuViewLayer extends FrameLayout implements
mMigrationTooltipObserver);
mHandler.removeCallbacksAndMessages(/* token= */ null);
getContext().unregisterComponentCallbacks(this);
+ mNavigationModeController.removeListener(mNavigationModeChangedListender);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
index 623536f0f928..cb96e7859fba 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
@@ -24,6 +24,7 @@ import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.util.settings.SecureSettings;
/**
@@ -37,7 +38,8 @@ class MenuViewLayerController implements IAccessibilityFloatingMenu {
MenuViewLayerController(Context context, WindowManager windowManager,
ViewCaptureAwareWindowManager viewCaptureAwareWindowManager,
- AccessibilityManager accessibilityManager, SecureSettings secureSettings) {
+ AccessibilityManager accessibilityManager, SecureSettings secureSettings,
+ NavigationModeController navigationModeController) {
mWindowManager = viewCaptureAwareWindowManager;
MenuViewModel menuViewModel = new MenuViewModel(
@@ -49,7 +51,8 @@ class MenuViewLayerController implements IAccessibilityFloatingMenu {
menuViewAppearance,
new MenuView(context, menuViewModel, menuViewAppearance, secureSettings),
this,
- secureSettings);
+ secureSettings,
+ navigationModeController);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
index e7dd974c44e5..df50e8fdb90b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
@@ -22,6 +22,7 @@ import com.android.systemui.authentication.domain.interactor.AuthenticationResul
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.lifecycle.SysUiViewModel
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -60,7 +61,7 @@ sealed class AuthMethodBouncerViewModel(
private val authenticationRequests = Channel<AuthenticationRequest>(Channel.BUFFERED)
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
authenticationRequests.receiveAsFlow().collectLatest { request ->
if (!isInputEnabled.value) {
return@collectLatest
@@ -79,6 +80,7 @@ sealed class AuthMethodBouncerViewModel(
_animateFailure.value = authenticationResult != AuthenticationResult.SUCCEEDED
clearInput()
}
+ awaitCancellation()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
index c3215b4ada9e..d746220dd7ce 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
@@ -50,6 +50,7 @@ import kotlin.math.max
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
@@ -94,9 +95,9 @@ constructor(
/** The user-facing message to show in the bouncer. */
val message: MutableStateFlow<MessageViewModel?> = MutableStateFlow(null)
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
if (!flags.isComposeBouncerOrSceneContainerEnabled()) {
- return
+ return awaitCancellation()
}
coroutineScope {
@@ -110,6 +111,7 @@ constructor(
launch { listenForBouncerEvents() }
launch { listenForFaceMessages() }
launch { listenForFingerprintMessages() }
+ awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt
index aede63b0ac23..63b6f0193502 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt
@@ -37,6 +37,7 @@ import com.android.systemui.lifecycle.SysUiViewModel
import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -137,7 +138,7 @@ constructor(
MutableStateFlow(authenticationInteractor.lockoutEndTimestamp == null)
private val isInputEnabled: StateFlow<Boolean> = _isInputEnabled.asStateFlow()
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
coroutineScope {
launch { message.activate() }
launch {
@@ -214,6 +215,8 @@ constructor(
.map { lockoutMessagePresent -> !lockoutMessagePresent }
.collectLatest { _isInputEnabled.value = it }
}
+
+ awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index 9ead7a0dcf4d..c91fd6a1a18e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -27,6 +27,7 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
@@ -81,7 +82,7 @@ constructor(
private val requests = Channel<Request>(Channel.BUFFERED)
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
coroutineScope {
launch { super.onActivated() }
launch {
@@ -125,6 +126,7 @@ constructor(
}
.collectLatest { _isImeSwitcherButtonVisible.value = it }
}
+ awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index b1df04b3f76b..4c029299e16b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -29,6 +29,7 @@ import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.sqrt
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -80,7 +81,7 @@ constructor(
override val lockoutMessageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
coroutineScope {
launch { super.onActivated() }
launch {
@@ -88,6 +89,7 @@ constructor(
.map { it.toList() }
.collectLatest { selectedDotList.value = it.toList() }
}
+ awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index cb36560545c8..c6119544d2b0 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -36,6 +36,7 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
@@ -96,7 +97,7 @@ constructor(
private val requests = Channel<Request>(Channel.BUFFERED)
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
coroutineScope {
launch { super.onActivated() }
launch {
@@ -145,6 +146,7 @@ constructor(
.map { !it }
.collectLatest { _isDigitButtonAnimationEnabled.value = it }
}
+ awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt
index c780aac5aaca..63437525515c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt
@@ -41,6 +41,8 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -85,25 +87,29 @@ constructor(
*/
private val nextKeyguardStateInternal =
combine(
- keyguardInteractor.isAbleToDream,
- keyguardInteractor.isKeyguardOccluded,
- keyguardInteractor.isKeyguardGoingAway,
- ) { dreaming, occluded, keyguardGoingAway ->
- if (keyguardGoingAway) {
- KeyguardState.GONE
- } else if (occluded && !dreaming) {
- KeyguardState.OCCLUDED
- } else if (dreaming) {
- KeyguardState.DREAMING
- } else {
- KeyguardState.LOCKSCREEN
+ keyguardInteractor.isAbleToDream,
+ keyguardInteractor.isKeyguardOccluded,
+ keyguardInteractor.isKeyguardGoingAway,
+ keyguardInteractor.isKeyguardShowing,
+ ) { dreaming, occluded, keyguardGoingAway, keyguardShowing ->
+ if (keyguardGoingAway) {
+ KeyguardState.GONE
+ } else if (occluded && !dreaming) {
+ KeyguardState.OCCLUDED
+ } else if (dreaming) {
+ KeyguardState.DREAMING
+ } else if (keyguardShowing) {
+ KeyguardState.LOCKSCREEN
+ } else {
+ null
+ }
}
- }
+ .filterNotNull()
private val nextKeyguardState: StateFlow<KeyguardState> =
combine(
repository.nextLockscreenTargetState,
- nextKeyguardStateInternal,
+ nextKeyguardStateInternal.onStart { emit(KeyguardState.LOCKSCREEN) },
) { override, nextState ->
override ?: nextState
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index 6d7cdc472f0a..b421e5932352 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -16,10 +16,7 @@
package com.android.systemui.communal.widgets
-import android.app.Activity
-import android.app.Application.ActivityLifecycleCallbacks
import android.content.Intent
-import android.content.IntentSender
import android.os.Bundle
import android.os.RemoteException
import android.util.Log
@@ -71,78 +68,12 @@ constructor(
const val EXTRA_OPEN_WIDGET_PICKER_ON_START = "open_widget_picker_on_start"
}
- /**
- * [ActivityController] handles closing the activity in the case it is backgrounded without
- * waiting for an activity result
- */
- class ActivityController(activity: Activity) {
- companion object {
- private const val STATE_EXTRA_IS_WAITING_FOR_RESULT = "extra_is_waiting_for_result"
- }
-
- private var waitingForResult: Boolean = false
-
- init {
- activity.registerActivityLifecycleCallbacks(
- object : ActivityLifecycleCallbacks {
- override fun onActivityCreated(
- activity: Activity,
- savedInstanceState: Bundle?
- ) {
- waitingForResult =
- savedInstanceState?.getBoolean(STATE_EXTRA_IS_WAITING_FOR_RESULT)
- ?: false
- }
-
- override fun onActivityStarted(activity: Activity) {
- // Nothing to implement.
- }
-
- override fun onActivityResumed(activity: Activity) {
- // Nothing to implement.
- }
-
- override fun onActivityPaused(activity: Activity) {
- // Nothing to implement.
- }
-
- override fun onActivityStopped(activity: Activity) {
- // If we're not backgrounded due to waiting for a resul (either widget
- // selection
- // or configuration), finish activity.
- if (!waitingForResult) {
- activity.finish()
- }
- }
-
- override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
- outState.putBoolean(STATE_EXTRA_IS_WAITING_FOR_RESULT, waitingForResult)
- }
-
- override fun onActivityDestroyed(activity: Activity) {
- // Nothing to implement.
- }
- }
- )
- }
-
- /**
- * Invoked when waiting for an activity result changes, either initiating such wait or
- * finishing due to the return of a result.
- */
- fun onWaitingForResult(waitingForResult: Boolean) {
- this.waitingForResult = waitingForResult
- }
- }
-
private val logger = Logger(logBuffer, "EditWidgetsActivity")
private val widgetConfigurator by lazy { widgetConfiguratorFactory.create(this) }
private var shouldOpenWidgetPickerOnStart = false
- private val activityController: ActivityController = ActivityController(this)
-
private val addWidgetActivityLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(StartActivityForResult()) { result ->
when (result.resultCode) {
@@ -267,34 +198,7 @@ constructor(
}
}
- override fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?) {
- activityController.onWaitingForResult(true)
- super.startActivityForResult(intent, requestCode, options)
- }
-
- override fun startIntentSenderForResult(
- intent: IntentSender,
- requestCode: Int,
- fillInIntent: Intent?,
- flagsMask: Int,
- flagsValues: Int,
- extraFlags: Int,
- options: Bundle?
- ) {
- activityController.onWaitingForResult(true)
- super.startIntentSenderForResult(
- intent,
- requestCode,
- fillInIntent,
- flagsMask,
- flagsValues,
- extraFlags,
- options
- )
- }
-
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- activityController.onWaitingForResult(false)
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == WidgetConfigurationController.REQUEST_CODE) {
widgetConfigurator.setConfigurationResult(resultCode)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
index 121b4a304c3a..542b98896986 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
@@ -22,6 +22,7 @@ import android.content.Intent
import android.view.View
import android.widget.RemoteViews
import com.android.app.tracing.coroutines.launch
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.Flags.communalWidgetTrampolineFix
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
@@ -29,11 +30,13 @@ import com.android.systemui.communal.domain.interactor.WidgetTrampolineInteracto
import com.android.systemui.communal.util.InteractionHandlerDelegate
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
import com.android.systemui.plugins.ActivityStarter
import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -41,8 +44,10 @@ import kotlinx.coroutines.Job
class WidgetInteractionHandler
@Inject
constructor(
- @Application applicationScope: CoroutineScope,
+ @Application private val applicationScope: CoroutineScope,
+ @UiBackground private val uiBackgroundContext: CoroutineContext,
private val activityStarter: ActivityStarter,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
communalSceneInteractor: CommunalSceneInteractor,
private val widgetTrampolineInteractor: WidgetTrampolineInteractor,
@CommunalLog val logBuffer: LogBuffer,
@@ -120,7 +125,14 @@ constructor(
activityStarter.startPendingIntentMaybeDismissingKeyguard(
pendingIntent,
/* dismissShade = */ false,
- /* intentSentUiThreadCallback = */ null,
+ {
+ applicationScope.launch("$TAG#awakenFromDream", uiBackgroundContext) {
+ // This activity could have started while the device is dreaming, in which case
+ // the dream would occlude the activity. In order to show the newly started
+ // activity, we wake from the dream.
+ keyguardUpdateMonitor.awakenFromDream()
+ }
+ },
controller,
fillInIntent,
extraOptions.toBundle(),
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 74e1dc0b0fad..a5f29aa658be 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -38,31 +38,35 @@ import com.android.systemui.util.ActivityTaskManagerProxy
import com.android.systemui.util.asIndenting
import com.android.systemui.util.indentIfPossible
import java.io.PrintWriter
+import java.util.concurrent.CopyOnWriteArraySet
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject
private fun createServiceListing(context: Context): ServiceListing {
- return ServiceListing.Builder(context).apply {
- setIntentAction(ControlsProviderService.SERVICE_CONTROLS)
- setPermission("android.permission.BIND_CONTROLS")
- setNoun("Controls Provider")
- setSetting("controls_providers")
- setTag("controls_providers")
- setAddDeviceLockedFlags(true)
- }.build()
+ return ServiceListing.Builder(context)
+ .apply {
+ setIntentAction(ControlsProviderService.SERVICE_CONTROLS)
+ setPermission("android.permission.BIND_CONTROLS")
+ setNoun("Controls Provider")
+ setSetting("controls_providers")
+ setTag("controls_providers")
+ setAddDeviceLockedFlags(true)
+ }
+ .build()
}
/**
* Provides a listing of components to be used as ControlsServiceProvider.
*
* This controller keeps track of components that satisfy:
- *
* * Has an intent-filter responding to [ControlsProviderService.CONTROLS_ACTION]
* * Has the bind permission `android.permission.BIND_CONTROLS`
*/
@SysUISingleton
-class ControlsListingControllerImpl @VisibleForTesting constructor(
+class ControlsListingControllerImpl
+@VisibleForTesting
+constructor(
private val context: Context,
@Background private val backgroundExecutor: Executor,
private val serviceListingBuilder: (Context) -> ServiceListing,
@@ -74,12 +78,12 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
@Inject
constructor(
- context: Context,
- @Background executor: Executor,
- userTracker: UserTracker,
- activityTaskManagerProxy: ActivityTaskManagerProxy,
- dumpManager: DumpManager,
- featureFlags: FeatureFlags
+ context: Context,
+ @Background executor: Executor,
+ userTracker: UserTracker,
+ activityTaskManagerProxy: ActivityTaskManagerProxy,
+ dumpManager: DumpManager,
+ featureFlags: FeatureFlags
) : this(
context,
executor,
@@ -92,7 +96,7 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
private var serviceListing = serviceListingBuilder(context)
// All operations in background thread
- private val callbacks = mutableSetOf<ControlsListingController.ControlsListingCallback>()
+ private val callbacks = CopyOnWriteArraySet<ControlsListingController.ControlsListingCallback>()
companion object {
private const val TAG = "ControlsListingControllerImpl"
@@ -104,15 +108,17 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
override var currentUserId = userTracker.userId
private set
- private val serviceListingCallback = ServiceListing.Callback { list ->
- Log.d(TAG, "ServiceConfig reloaded, count: ${list.size}")
- val newServices = list.map { ControlsServiceInfo(userTracker.userContext, it) }
- // After here, `list` is not captured, so we don't risk modifying it outside of the callback
- backgroundExecutor.execute {
- if (userChangeInProgress.get() > 0) return@execute
- updateServices(newServices)
+ private val serviceListingCallback =
+ ServiceListing.Callback { list ->
+ Log.d(TAG, "ServiceConfig reloaded, count: ${list.size}")
+ val newServices = list.map { ControlsServiceInfo(userTracker.userContext, it) }
+ // After here, `list` is not captured, so we don't risk modifying it outside of the
+ // callback
+ backgroundExecutor.execute {
+ if (userChangeInProgress.get() > 0) return@execute
+ updateServices(newServices)
+ }
}
- }
init {
Log.d(TAG, "Initializing")
@@ -124,15 +130,12 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
private fun updateServices(newServices: List<ControlsServiceInfo>) {
if (activityTaskManagerProxy.supportsMultiWindow(context)) {
- newServices.forEach {
- it.resolvePanelActivity() }
+ newServices.forEach { it.resolvePanelActivity() }
}
if (newServices != availableServices) {
availableServices = newServices
- callbacks.forEach {
- it.onServicesUpdated(getCurrentServices())
- }
+ callbacks.forEach { it.onServicesUpdated(getCurrentServices()) }
}
}
@@ -155,8 +158,8 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
/**
* Adds a callback to this controller.
*
- * The callback will be notified after it is added as well as any time that the valid
- * components change.
+ * The callback will be notified after it is added as well as any time that the valid components
+ * change.
*
* @param listener a callback to be notified
*/
@@ -188,26 +191,29 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
}
/**
- * @return a list of components that satisfy the requirements to be a
- * [ControlsProviderService]
+ * @return a list of components that satisfy the requirements to be a [ControlsProviderService]
*/
override fun getCurrentServices(): List<ControlsServiceInfo> =
- availableServices.map(ControlsServiceInfo::copy)
+ availableServices.map(ControlsServiceInfo::copy)
@WorkerThread
override fun forceReload() {
val packageManager = context.packageManager
val intent = Intent(ControlsProviderService.SERVICE_CONTROLS)
val user = userTracker.userHandle
- val flags = PackageManager.GET_SERVICES or
+ val flags =
+ PackageManager.GET_SERVICES or
PackageManager.GET_META_DATA or
PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
PackageManager.MATCH_DIRECT_BOOT_AWARE
- val services = packageManager.queryIntentServicesAsUser(
- intent,
- PackageManager.ResolveInfoFlags.of(flags.toLong()),
- user
- ).map { ControlsServiceInfo(userTracker.userContext, it.serviceInfo) }
+ val services =
+ packageManager
+ .queryIntentServicesAsUser(
+ intent,
+ PackageManager.ResolveInfoFlags.of(flags.toLong()),
+ user
+ )
+ .map { ControlsServiceInfo(userTracker.userContext, it.serviceInfo) }
updateServices(services)
}
@@ -218,8 +224,7 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
* @return a label as returned by [CandidateInfo.loadLabel] or `null`.
*/
override fun getAppLabel(name: ComponentName): CharSequence? {
- return availableServices.firstOrNull { it.componentName == name }
- ?.loadLabel()
+ return availableServices.firstOrNull { it.componentName == name }?.loadLabel()
}
override fun dump(writer: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/education/data/model/GestureEduModel.kt b/packages/SystemUI/src/com/android/systemui/education/data/model/GestureEduModel.kt
index a171f8775768..1daaa1128ba0 100644
--- a/packages/SystemUI/src/com/android/systemui/education/data/model/GestureEduModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/data/model/GestureEduModel.kt
@@ -28,4 +28,5 @@ data class GestureEduModel(
val lastShortcutTriggeredTime: Instant? = null,
val usageSessionStartTime: Instant? = null,
val lastEducationTime: Instant? = null,
+ val userId: Int
)
diff --git a/packages/SystemUI/src/com/android/systemui/education/data/repository/UserContextualEducationRepository.kt b/packages/SystemUI/src/com/android/systemui/education/data/repository/UserContextualEducationRepository.kt
index 7c3d63388aa1..4fd79d764cdd 100644
--- a/packages/SystemUI/src/com/android/systemui/education/data/repository/UserContextualEducationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/data/repository/UserContextualEducationRepository.kt
@@ -33,6 +33,7 @@ import com.android.systemui.education.data.model.GestureEduModel
import java.time.Instant
import javax.inject.Inject
import javax.inject.Provider
+import kotlin.properties.Delegates.notNull
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
@@ -79,6 +80,8 @@ constructor(
const val DATASTORE_DIR = "education/USER%s_ContextualEducation"
}
+ private var userId by notNull<Int>()
+
private var dataStoreScope: CoroutineScope? = null
private val datastore = MutableStateFlow<DataStore<Preferences>?>(null)
@@ -89,6 +92,7 @@ constructor(
override fun setUser(userId: Int) {
dataStoreScope?.cancel()
val newDsScope = dataStoreScopeProvider.get()
+ this.userId = userId
datastore.value =
PreferenceDataStoreFactory.create(
produceFile = {
@@ -123,6 +127,7 @@ constructor(
preferences[getLastEducationTimeKey(gestureType)]?.let {
Instant.ofEpochSecond(it)
},
+ userId = userId
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt
index 3a3fb8c6acbe..ad3335b7cdeb 100644
--- a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt
@@ -56,7 +56,7 @@ constructor(
if (isUsageSessionExpired(it)) {
contextualEducationInteractor.startNewUsageSession(BACK)
} else if (isEducationNeeded(it)) {
- _educationTriggered.value = EducationInfo(BACK, getEduType(it))
+ _educationTriggered.value = EducationInfo(BACK, getEduType(it), it.userId)
contextualEducationInteractor.updateOnEduTriggered(BACK)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/education/shared/model/EducationInfo.kt b/packages/SystemUI/src/com/android/systemui/education/shared/model/EducationInfo.kt
index d92fb9bff512..27c41cffc808 100644
--- a/packages/SystemUI/src/com/android/systemui/education/shared/model/EducationInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/shared/model/EducationInfo.kt
@@ -22,7 +22,11 @@ import com.android.systemui.contextualeducation.GestureType
* Model for education triggered. [gestureType] indicates what gesture it is trying to educate about
* and [educationUiType] is how we educate user in the UI
*/
-data class EducationInfo(val gestureType: GestureType, val educationUiType: EducationUiType)
+data class EducationInfo(
+ val gestureType: GestureType,
+ val educationUiType: EducationUiType,
+ val userId: Int
+)
enum class EducationUiType {
Toast,
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt
index b446ea2bcb38..e62b26bfe53d 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt
@@ -16,14 +16,24 @@
package com.android.systemui.education.ui.view
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.UserHandle
import android.widget.Toast
+import androidx.core.app.NotificationCompat
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.education.shared.model.EducationUiType
-import com.android.systemui.education.ui.viewmodel.ContextualEduContentViewModel
+import com.android.systemui.education.ui.viewmodel.ContextualEduNotificationViewModel
+import com.android.systemui.education.ui.viewmodel.ContextualEduToastViewModel
import com.android.systemui.education.ui.viewmodel.ContextualEduViewModel
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity
+import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -37,32 +47,96 @@ class ContextualEduUiCoordinator
constructor(
@Application private val applicationScope: CoroutineScope,
private val viewModel: ContextualEduViewModel,
+ private val context: Context,
+ private val notificationManager: NotificationManager,
private val createToast: (String) -> Toast
) : CoreStartable {
+ companion object {
+ private const val CHANNEL_ID = "ContextualEduNotificationChannel"
+ private const val TAG = "ContextualEduUiCoordinator"
+ private const val NOTIFICATION_ID = 1000
+ }
+
@Inject
constructor(
@Application applicationScope: CoroutineScope,
context: Context,
viewModel: ContextualEduViewModel,
+ notificationManager: NotificationManager,
) : this(
applicationScope,
viewModel,
+ context,
+ notificationManager,
createToast = { message -> Toast.makeText(context, message, Toast.LENGTH_LONG) }
)
override fun start() {
+ createEduNotificationChannel()
applicationScope.launch {
viewModel.eduContent.collect { contentModel ->
- if (contentModel.type == EducationUiType.Toast) {
- showToast(contentModel)
+ when (contentModel) {
+ is ContextualEduToastViewModel -> showToast(contentModel)
+ is ContextualEduNotificationViewModel -> showNotification(contentModel)
}
}
}
}
- private fun showToast(model: ContextualEduContentViewModel) {
+ private fun createEduNotificationChannel() {
+ val channel =
+ NotificationChannel(
+ CHANNEL_ID,
+ context.getString(com.android.internal.R.string.android_system_label),
+ // Make it as silent notification
+ NotificationManager.IMPORTANCE_LOW
+ )
+ notificationManager.createNotificationChannel(channel)
+ }
+
+ private fun showToast(model: ContextualEduToastViewModel) {
val toast = createToast(model.message)
toast.show()
}
+
+ private fun showNotification(model: ContextualEduNotificationViewModel) {
+ // Replace "System UI" app name with "Android System"
+ val extras = Bundle()
+ extras.putString(
+ Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ context.getString(com.android.internal.R.string.android_system_label)
+ )
+
+ val notification =
+ NotificationCompat.Builder(context, CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_settings)
+ .setContentTitle(model.title)
+ .setContentText(model.message)
+ .setContentIntent(createPendingIntent())
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT)
+ .setAutoCancel(true)
+ .addExtras(extras)
+ .build()
+ notificationManager.notifyAsUser(
+ TAG,
+ NOTIFICATION_ID,
+ notification,
+ UserHandle.of(model.userId)
+ )
+ }
+
+ private fun createPendingIntent(): PendingIntent {
+ val intent =
+ Intent(context, KeyboardTouchpadTutorialActivity::class.java).apply {
+ addCategory(Intent.CATEGORY_DEFAULT)
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ }
+ return PendingIntent.getActivity(
+ context,
+ /* requestCode= */ 0,
+ intent,
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
index 3cba4c8fb110..632b250512cb 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
@@ -16,6 +16,13 @@
package com.android.systemui.education.ui.viewmodel
-import com.android.systemui.education.shared.model.EducationUiType
+sealed class ContextualEduContentViewModel(open val userId: Int)
-data class ContextualEduContentViewModel(val message: String, val type: EducationUiType)
+data class ContextualEduNotificationViewModel(
+ val title: String,
+ val message: String,
+ override val userId: Int
+) : ContextualEduContentViewModel(userId)
+
+data class ContextualEduToastViewModel(val message: String, override val userId: Int) :
+ ContextualEduContentViewModel(userId)
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
index 58276e0759f6..cd4a8ad8dbda 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
@@ -17,11 +17,15 @@
package com.android.systemui.education.ui.viewmodel
import android.content.res.Resources
-import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.contextualeducation.GestureType.ALL_APPS
+import com.android.systemui.contextualeducation.GestureType.BACK
+import com.android.systemui.contextualeducation.GestureType.HOME
+import com.android.systemui.contextualeducation.GestureType.OVERVIEW
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.education.domain.interactor.KeyboardTouchpadEduInteractor
import com.android.systemui.education.shared.model.EducationInfo
+import com.android.systemui.education.shared.model.EducationUiType
import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -34,18 +38,43 @@ class ContextualEduViewModel
constructor(@Main private val resources: Resources, interactor: KeyboardTouchpadEduInteractor) {
val eduContent: Flow<ContextualEduContentViewModel> =
interactor.educationTriggered.filterNotNull().map {
- ContextualEduContentViewModel(getEduContent(it), it.educationUiType)
+ if (it.educationUiType == EducationUiType.Notification) {
+ ContextualEduNotificationViewModel(getEduTitle(it), getEduContent(it), it.userId)
+ } else {
+ ContextualEduToastViewModel(getEduContent(it), it.userId)
+ }
}
private fun getEduContent(educationInfo: EducationInfo): String {
- // Todo: also check UiType in educationInfo to determine the string
+ val resourceId =
+ if (educationInfo.educationUiType == EducationUiType.Notification) {
+ when (educationInfo.gestureType) {
+ BACK -> R.string.back_edu_notification_content
+ HOME -> R.string.home_edu_notification_content
+ OVERVIEW -> R.string.overview_edu_notification_content
+ ALL_APPS -> R.string.all_apps_edu_notification_content
+ }
+ } else {
+ when (educationInfo.gestureType) {
+ BACK -> R.string.back_edu_toast_content
+ HOME -> R.string.home_edu_toast_content
+ OVERVIEW -> R.string.overview_edu_toast_content
+ ALL_APPS -> R.string.all_apps_edu_toast_content
+ }
+ }
+
+ return resources.getString(resourceId)
+ }
+
+ private fun getEduTitle(educationInfo: EducationInfo): String {
val resourceId =
when (educationInfo.gestureType) {
- GestureType.BACK -> R.string.back_edu_toast_content
- GestureType.HOME -> R.string.home_edu_toast_content
- GestureType.OVERVIEW -> R.string.overview_edu_toast_content
- GestureType.ALL_APPS -> R.string.all_apps_edu_toast_content
+ BACK -> R.string.back_edu_notification_title
+ HOME -> R.string.home_edu_notification_title
+ OVERVIEW -> R.string.overview_edu_notification_title
+ ALL_APPS -> R.string.all_apps_edu_notification_title
}
+
return resources.getString(resourceId)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/view/KeyboardTouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/view/KeyboardTouchpadTutorialActivity.kt
deleted file mode 100644
index 3e382d669e5d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/view/KeyboardTouchpadTutorialActivity.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2024 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.inputdevice.tutorial.ui.view
-
-import android.os.Bundle
-import android.view.WindowManager
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import androidx.activity.viewModels
-import androidx.compose.runtime.Composable
-import com.android.compose.theme.PlatformTheme
-import com.android.systemui.inputdevice.tutorial.TouchpadTutorialScreensProvider
-import com.android.systemui.inputdevice.tutorial.ui.viewmodel.KeyboardTouchpadTutorialViewModel
-import java.util.Optional
-import javax.inject.Inject
-
-/**
- * Activity for out of the box experience for keyboard and touchpad. Note that it's possible that
- * either of them are actually not connected when this is launched
- */
-class KeyboardTouchpadTutorialActivity
-@Inject
-constructor(
- private val viewModelFactory: KeyboardTouchpadTutorialViewModel.Factory,
- private val touchpadTutorialScreensProvider: Optional<TouchpadTutorialScreensProvider>,
-) : ComponentActivity() {
-
- private val vm by
- viewModels<KeyboardTouchpadTutorialViewModel>(factoryProducer = { viewModelFactory })
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContent {
- PlatformTheme {
- KeyboardTouchpadTutorialContainer(vm, touchpadTutorialScreensProvider) { finish() }
- }
- }
- // required to handle 3+ fingers on touchpad
- window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
- }
-
- override fun onResume() {
- super.onResume()
- vm.onOpened()
- }
-
- override fun onPause() {
- super.onPause()
- vm.onClosed()
- }
-}
-
-@Composable
-fun KeyboardTouchpadTutorialContainer(
- vm: KeyboardTouchpadTutorialViewModel,
- touchpadTutorialScreensProvider: Optional<TouchpadTutorialScreensProvider>,
- closeTutorial: () -> Unit
-) {}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
deleted file mode 100644
index 39b1ec0f0390..000000000000
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2024 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.inputdevice.tutorial.ui.viewmodel
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
-import java.util.Optional
-import javax.inject.Inject
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-
-class KeyboardTouchpadTutorialViewModel(
- private val gesturesInteractor: Optional<TouchpadGesturesInteractor>
-) : ViewModel() {
-
- private val _screen = MutableStateFlow(Screen.BACK_GESTURE)
- val screen: StateFlow<Screen> = _screen
-
- fun goTo(screen: Screen) {
- _screen.value = screen
- }
-
- fun onOpened() {
- gesturesInteractor.ifPresent { it.disableGestures() }
- }
-
- fun onClosed() {
- gesturesInteractor.ifPresent { it.enableGestures() }
- }
-
- class Factory
- @Inject
- constructor(private val gesturesInteractor: Optional<TouchpadGesturesInteractor>) :
- ViewModelProvider.Factory {
-
- @Suppress("UNCHECKED_CAST")
- override fun <T : ViewModel> create(modelClass: Class<T>): T {
- return KeyboardTouchpadTutorialViewModel(gesturesInteractor) as T
- }
- }
-}
-
-enum class Screen {
- BACK_GESTURE,
- HOME_GESTURE,
- ACTION_KEY
-}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/KeyboardTouchpadTutorialModule.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialModule.kt
index 8e6cb077a25e..8e6cb077a25e 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/KeyboardTouchpadTutorialModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialModule.kt
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/TouchpadTutorialScreensProvider.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/TouchpadTutorialScreensProvider.kt
index bd3e771f40bc..bd3e771f40bc 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/TouchpadTutorialScreensProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/TouchpadTutorialScreensProvider.kt
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt
index 9f46846f0d91..1dbe83aeb64f 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt
@@ -16,7 +16,23 @@
package com.android.systemui.inputdevice.tutorial.data.model
-data class DeviceSchedulerInfo(var isLaunched: Boolean = false, var connectTime: Long? = null) {
+import java.time.Instant
+
+data class DeviceSchedulerInfo(
+ var launchTime: Instant? = null,
+ var firstConnectionTime: Instant? = null
+) {
+ constructor(
+ launchTimeSec: Long?,
+ firstConnectionTimeSec: Long?
+ ) : this(
+ launchTimeSec?.let { Instant.ofEpochSecond(it) },
+ firstConnectionTimeSec?.let { Instant.ofEpochSecond(it) }
+ )
+
val wasEverConnected: Boolean
- get() = connectTime != null
+ get() = firstConnectionTime != null
+
+ val isLaunched: Boolean
+ get() = launchTime != null
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt
index 36b9ac70d290..d8d4bd686f07 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt
@@ -20,7 +20,6 @@ import android.content.Context
import androidx.annotation.VisibleForTesting
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
-import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
@@ -28,6 +27,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.inputdevice.tutorial.data.model.DeviceSchedulerInfo
+import java.time.Instant
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first
@@ -43,28 +43,31 @@ class TutorialSchedulerRepository(
constructor(
@Application applicationContext: Context,
@Background backgroundScope: CoroutineScope
- ) : this(applicationContext, backgroundScope, dataStoreName = "TutorialScheduler")
+ ) : this(applicationContext, backgroundScope, dataStoreName = DATASTORE_NAME)
private val Context.dataStore: DataStore<Preferences> by
preferencesDataStore(name = dataStoreName, scope = backgroundScope)
suspend fun isLaunched(deviceType: DeviceType): Boolean = loadData()[deviceType]!!.isLaunched
+ suspend fun launchTime(deviceType: DeviceType): Instant? = loadData()[deviceType]!!.launchTime
+
suspend fun wasEverConnected(deviceType: DeviceType): Boolean =
loadData()[deviceType]!!.wasEverConnected
- suspend fun connectTime(deviceType: DeviceType): Long = loadData()[deviceType]!!.connectTime!!
+ suspend fun firstConnectionTime(deviceType: DeviceType): Instant? =
+ loadData()[deviceType]!!.firstConnectionTime
private suspend fun loadData(): Map<DeviceType, DeviceSchedulerInfo> {
return applicationContext.dataStore.data.map { pref -> getSchedulerInfo(pref) }.first()
}
- suspend fun updateConnectTime(device: DeviceType, time: Long) {
- applicationContext.dataStore.edit { pref -> pref[getConnectKey(device)] = time }
+ suspend fun updateFirstConnectionTime(device: DeviceType, time: Instant) {
+ applicationContext.dataStore.edit { pref -> pref[getConnectKey(device)] = time.epochSecond }
}
- suspend fun updateLaunch(device: DeviceType) {
- applicationContext.dataStore.edit { pref -> pref[getLaunchedKey(device)] = true }
+ suspend fun updateLaunchTime(device: DeviceType, time: Instant) {
+ applicationContext.dataStore.edit { pref -> pref[getLaunchKey(device)] = time.epochSecond }
}
private fun getSchedulerInfo(pref: Preferences): Map<DeviceType, DeviceSchedulerInfo> {
@@ -75,13 +78,13 @@ class TutorialSchedulerRepository(
}
private fun getDeviceSchedulerInfo(pref: Preferences, device: DeviceType): DeviceSchedulerInfo {
- val isLaunched = pref[getLaunchedKey(device)] ?: false
- val connectionTime = pref[getConnectKey(device)] ?: null
- return DeviceSchedulerInfo(isLaunched, connectionTime)
+ val launchTime = pref[getLaunchKey(device)]
+ val connectionTime = pref[getConnectKey(device)]
+ return DeviceSchedulerInfo(launchTime, connectionTime)
}
- private fun getLaunchedKey(device: DeviceType) =
- booleanPreferencesKey(device.name + IS_LAUNCHED_SUFFIX)
+ private fun getLaunchKey(device: DeviceType) =
+ longPreferencesKey(device.name + LAUNCH_TIME_SUFFIX)
private fun getConnectKey(device: DeviceType) =
longPreferencesKey(device.name + CONNECT_TIME_SUFFIX)
@@ -92,8 +95,9 @@ class TutorialSchedulerRepository(
}
companion object {
- const val IS_LAUNCHED_SUFFIX = "_IS_LAUNCHED"
- const val CONNECT_TIME_SUFFIX = "_CONNECTED_TIME"
+ const val DATASTORE_NAME = "TutorialScheduler"
+ const val LAUNCH_TIME_SUFFIX = "_LAUNCH_TIME"
+ const val CONNECT_TIME_SUFFIX = "_CONNECT_TIME"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/KeyboardTouchpadConnectionInteractor.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/KeyboardTouchpadConnectionInteractor.kt
new file mode 100644
index 000000000000..3f1f68ad2897
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/KeyboardTouchpadConnectionInteractor.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.inputdevice.tutorial.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.data.repository.KeyboardRepository
+import com.android.systemui.touchpad.data.repository.TouchpadRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+
+@SysUISingleton
+class KeyboardTouchpadConnectionInteractor
+@Inject
+constructor(
+ keyboardRepository: KeyboardRepository,
+ touchpadRepository: TouchpadRepository,
+) {
+
+ val connectionState: Flow<ConnectionState> =
+ combine(
+ keyboardRepository.isAnyKeyboardConnected,
+ touchpadRepository.isAnyTouchpadConnected
+ ) { keyboardConnected, touchpadConnected ->
+ ConnectionState(keyboardConnected, touchpadConnected)
+ }
+}
+
+data class ConnectionState(val keyboardConnected: Boolean, val touchpadConnected: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
index b3b8f21a4a4b..a8d7dad42a93 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
@@ -26,9 +26,11 @@ import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType.TOUC
import com.android.systemui.inputdevice.tutorial.data.repository.TutorialSchedulerRepository
import com.android.systemui.keyboard.data.repository.KeyboardRepository
import com.android.systemui.touchpad.data.repository.TouchpadRepository
+import java.time.Duration
import java.time.Instant
import javax.inject.Inject
import kotlin.time.Duration.Companion.hours
+import kotlin.time.toKotlinDuration
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.filter
@@ -84,9 +86,9 @@ constructor(
private suspend fun schedule(deviceType: DeviceType) {
if (!repo.wasEverConnected(deviceType)) {
waitForDeviceConnection(deviceType)
- repo.updateConnectTime(deviceType, Instant.now().toEpochMilli())
+ repo.updateFirstConnectionTime(deviceType, Instant.now())
}
- delay(remainingTimeMillis(start = repo.connectTime(deviceType)))
+ delay(remainingTime(start = repo.firstConnectionTime(deviceType)!!))
waitForDeviceConnection(deviceType)
}
@@ -95,9 +97,9 @@ constructor(
private suspend fun launchTutorial(tutorialType: TutorialType) {
if (tutorialType == TutorialType.KEYBOARD || tutorialType == TutorialType.BOTH)
- repo.updateLaunch(KEYBOARD)
+ repo.updateLaunchTime(KEYBOARD, Instant.now())
if (tutorialType == TutorialType.TOUCHPAD || tutorialType == TutorialType.BOTH)
- repo.updateLaunch(TOUCHPAD)
+ repo.updateLaunchTime(TOUCHPAD, Instant.now())
// TODO: launch tutorial
Log.d(TAG, "Launch tutorial for $tutorialType")
}
@@ -113,19 +115,21 @@ constructor(
return if (deviceType == KEYBOARD) TutorialType.KEYBOARD else TutorialType.TOUCHPAD
}
- private fun remainingTimeMillis(start: Long): Long {
- val elapsed = Instant.now().toEpochMilli() - start
- return LAUNCH_DELAY - elapsed
+ private fun remainingTime(start: Instant): kotlin.time.Duration {
+ val elapsed = Duration.between(start, Instant.now())
+ return LAUNCH_DELAY.minus(elapsed).toKotlinDuration()
}
companion object {
const val TAG = "TutorialSchedulerInteractor"
- private val DEFAULT_LAUNCH_DELAY = 72.hours.inWholeMilliseconds
- private val LAUNCH_DELAY: Long
+ private val DEFAULT_LAUNCH_DELAY_SEC = 72.hours.inWholeSeconds
+ private val LAUNCH_DELAY: Duration
get() =
- SystemProperties.getLong(
- "persist.peripheral_tutorial_delay_ms",
- DEFAULT_LAUNCH_DELAY
+ Duration.ofSeconds(
+ SystemProperties.getLong(
+ "persist.peripheral_tutorial_delay_sec",
+ DEFAULT_LAUNCH_DELAY_SEC
+ )
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionKeyTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
index c5b0ca78d65a..c5b0ca78d65a 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionKeyTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
index c50b7dc06265..c50b7dc06265 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionTutorialContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialComponents.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialComponents.kt
index 01ad585019d2..01ad585019d2 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialComponents.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialComponents.kt
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialScreenConfig.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt
index 0406bb9e6fef..0406bb9e6fef 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialScreenConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
new file mode 100644
index 000000000000..34ecc9518e83
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2024 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.inputdevice.tutorial.ui.view
+
+import android.os.Bundle
+import android.view.WindowManager
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.activity.viewModels
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.lifecycle.Lifecycle.State.STARTED
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import com.android.compose.theme.PlatformTheme
+import com.android.systemui.inputdevice.tutorial.TouchpadTutorialScreensProvider
+import com.android.systemui.inputdevice.tutorial.ui.composable.ActionKeyTutorialScreen
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.KeyboardTouchpadTutorialViewModel
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.KeyboardTouchpadTutorialViewModel.Factory.ViewModelFactoryAssistedProvider
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.ACTION_KEY
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.BACK_GESTURE
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.HOME_GESTURE
+import java.util.Optional
+import javax.inject.Inject
+import kotlinx.coroutines.launch
+
+/**
+ * Activity for out of the box experience for keyboard and touchpad. Note that it's possible that
+ * either of them are actually not connected when this is launched
+ */
+class KeyboardTouchpadTutorialActivity
+@Inject
+constructor(
+ private val viewModelFactoryAssistedProvider: ViewModelFactoryAssistedProvider,
+ private val touchpadTutorialScreensProvider: Optional<TouchpadTutorialScreensProvider>,
+) : ComponentActivity() {
+
+ companion object {
+ const val INTENT_TUTORIAL_TYPE_KEY = "tutorial_type"
+ const val INTENT_TUTORIAL_TYPE_TOUCHPAD = "touchpad"
+ const val INTENT_TUTORIAL_TYPE_KEYBOARD = "keyboard"
+ }
+
+ private val vm by
+ viewModels<KeyboardTouchpadTutorialViewModel>(
+ factoryProducer = {
+ viewModelFactoryAssistedProvider.create(touchpadTutorialScreensProvider.isPresent)
+ }
+ )
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ // required to handle 3+ fingers on touchpad
+ window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
+ lifecycle.addObserver(vm)
+ lifecycleScope.launch {
+ vm.closeActivity.collect { finish ->
+ if (finish) {
+ finish()
+ }
+ }
+ }
+ setContent {
+ PlatformTheme { KeyboardTouchpadTutorialContainer(vm, touchpadTutorialScreensProvider) }
+ }
+ }
+}
+
+@Composable
+fun KeyboardTouchpadTutorialContainer(
+ vm: KeyboardTouchpadTutorialViewModel,
+ touchpadScreens: Optional<TouchpadTutorialScreensProvider>,
+) {
+ val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED)
+ when (activeScreen) {
+ BACK_GESTURE ->
+ touchpadScreens
+ .get()
+ .BackGesture(onDoneButtonClicked = vm::onDoneButtonClicked, onBack = vm::onBack)
+ HOME_GESTURE ->
+ touchpadScreens
+ .get()
+ .HomeGesture(onDoneButtonClicked = vm::onDoneButtonClicked, onBack = vm::onBack)
+ ACTION_KEY ->
+ ActionKeyTutorialScreen(
+ onDoneButtonClicked = vm::onDoneButtonClicked,
+ onBack = vm::onBack
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
new file mode 100644
index 000000000000..315c102e94d0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2024 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.inputdevice.tutorial.ui.viewmodel
+
+import androidx.lifecycle.AbstractSavedStateViewModelFactory
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.android.systemui.inputdevice.tutorial.domain.interactor.ConnectionState
+import com.android.systemui.inputdevice.tutorial.domain.interactor.KeyboardTouchpadConnectionInteractor
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.RequiredHardware.KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.RequiredHardware.TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.ACTION_KEY
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.BACK_GESTURE
+import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.util.Optional
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNot
+import kotlinx.coroutines.flow.runningFold
+import kotlinx.coroutines.launch
+
+class KeyboardTouchpadTutorialViewModel(
+ private val gesturesInteractor: Optional<TouchpadGesturesInteractor>,
+ private val keyboardTouchpadConnectionInteractor: KeyboardTouchpadConnectionInteractor,
+ private val hasTouchpadTutorialScreens: Boolean,
+ handle: SavedStateHandle
+) : ViewModel(), DefaultLifecycleObserver {
+
+ private fun startingScreen(handle: SavedStateHandle): Screen {
+ val tutorialType: String? = handle[INTENT_TUTORIAL_TYPE_KEY]
+ return if (tutorialType == INTENT_TUTORIAL_TYPE_KEYBOARD) ACTION_KEY else BACK_GESTURE
+ }
+
+ private val _screen = MutableStateFlow(startingScreen(handle))
+ val screen: Flow<Screen> = _screen.filter { it.canBeShown() }
+
+ private val _closeActivity: MutableStateFlow<Boolean> = MutableStateFlow(false)
+ val closeActivity: StateFlow<Boolean> = _closeActivity
+
+ private val screensBackStack = ArrayDeque(listOf(_screen.value))
+
+ private var connectionState: ConnectionState =
+ ConnectionState(keyboardConnected = false, touchpadConnected = false)
+
+ init {
+ viewModelScope.launch {
+ keyboardTouchpadConnectionInteractor.connectionState.collect { connectionState = it }
+ }
+
+ viewModelScope.launch {
+ screen
+ .runningFold<Screen, Pair<Screen?, Screen?>>(null to null) {
+ previousScreensPair,
+ currentScreen ->
+ previousScreensPair.second to currentScreen
+ }
+ .collect { (previousScreen, currentScreen) ->
+ // ignore first empty emission
+ if (currentScreen != null) {
+ setupDeviceState(previousScreen, currentScreen)
+ }
+ }
+ }
+
+ viewModelScope.launch {
+ // close activity if screen requires touchpad but we don't have it. This can only happen
+ // when current sysui build doesn't contain touchpad module dependency
+ _screen.filterNot { it.canBeShown() }.collect { _closeActivity.value = true }
+ }
+ }
+
+ override fun onCleared() {
+ // this shouldn't be needed as onTutorialInvisible should already clear device state but
+ // it'd be really bad if we'd block gestures/shortcuts after leaving tutorial so just to be
+ // extra sure...
+ clearDeviceStateForScreen(_screen.value)
+ }
+
+ override fun onStart(owner: LifecycleOwner) {
+ setupDeviceState(previousScreen = null, currentScreen = _screen.value)
+ }
+
+ override fun onStop(owner: LifecycleOwner) {
+ clearDeviceStateForScreen(_screen.value)
+ }
+
+ fun onDoneButtonClicked() {
+ var nextScreen = _screen.value.next()
+ while (nextScreen != null) {
+ if (requiredHardwarePresent(nextScreen)) {
+ break
+ }
+ nextScreen = nextScreen.next()
+ }
+ if (nextScreen == null) {
+ _closeActivity.value = true
+ } else {
+ _screen.value = nextScreen
+ screensBackStack.add(nextScreen)
+ }
+ }
+
+ private fun Screen.canBeShown() = requiredHardware != TOUCHPAD || hasTouchpadTutorialScreens
+
+ private fun setupDeviceState(previousScreen: Screen?, currentScreen: Screen) {
+ if (previousScreen?.requiredHardware == currentScreen.requiredHardware) return
+ previousScreen?.let { clearDeviceStateForScreen(it) }
+ when (currentScreen.requiredHardware) {
+ TOUCHPAD -> gesturesInteractor.get().disableGestures()
+ KEYBOARD -> {} // TODO(b/358587037) disabled keyboard shortcuts
+ }
+ }
+
+ private fun clearDeviceStateForScreen(screen: Screen) {
+ when (screen.requiredHardware) {
+ TOUCHPAD -> gesturesInteractor.get().enableGestures()
+ KEYBOARD -> {} // TODO(b/358587037) enable keyboard shortcuts
+ }
+ }
+
+ private fun requiredHardwarePresent(screen: Screen): Boolean =
+ when (screen.requiredHardware) {
+ KEYBOARD -> connectionState.keyboardConnected
+ TOUCHPAD -> connectionState.touchpadConnected
+ }
+
+ fun onBack() {
+ if (screensBackStack.size <= 1) {
+ _closeActivity.value = true
+ } else {
+ screensBackStack.removeLast()
+ _screen.value = screensBackStack.last()
+ }
+ }
+
+ class Factory
+ @AssistedInject
+ constructor(
+ private val gesturesInteractor: Optional<TouchpadGesturesInteractor>,
+ private val keyboardTouchpadConnected: KeyboardTouchpadConnectionInteractor,
+ @Assisted private val hasTouchpadTutorialScreens: Boolean,
+ ) : AbstractSavedStateViewModelFactory() {
+
+ @AssistedFactory
+ fun interface ViewModelFactoryAssistedProvider {
+ fun create(@Assisted hasTouchpadTutorialScreens: Boolean): Factory
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(
+ key: String,
+ modelClass: Class<T>,
+ handle: SavedStateHandle
+ ): T =
+ KeyboardTouchpadTutorialViewModel(
+ gesturesInteractor,
+ keyboardTouchpadConnected,
+ hasTouchpadTutorialScreens,
+ handle
+ )
+ as T
+ }
+}
+
+enum class RequiredHardware {
+ TOUCHPAD,
+ KEYBOARD
+}
+
+enum class Screen(val requiredHardware: RequiredHardware) {
+ BACK_GESTURE(requiredHardware = TOUCHPAD),
+ HOME_GESTURE(requiredHardware = TOUCHPAD),
+ ACTION_KEY(requiredHardware = KEYBOARD);
+
+ fun next(): Screen? =
+ when (this) {
+ BACK_GESTURE -> HOME_GESTURE
+ HOME_GESTURE -> ACTION_KEY
+ ACTION_KEY -> null
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index ae830eed2c6b..1042ae32fea0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -30,7 +30,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
-import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.animation.Interpolators
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 13d54bac8339..6e04133dcb4a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -128,7 +128,7 @@ constructor(
(KeyguardWmStateRefactor.isEnabled && canWakeDirectlyToGone)
if (shouldTransitionToGone) {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
+ // TODO(b/360368320): Adapt for scene framework
if (SceneContainerFlag.isEnabled) return@collect
startTransitionTo(
toState = KeyguardState.GONE,
@@ -186,7 +186,6 @@ constructor(
* PRIMARY_BOUNCER.
*/
private fun listenForAodToPrimaryBouncer() {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
if (SceneContainerFlag.isEnabled) return
scope.launch("$TAG#listenForAodToPrimaryBouncer") {
keyguardInteractor.primaryBouncerShowing
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 90aaf0d617f7..49e4c707af18 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -107,7 +107,7 @@ constructor(
) ->
if (isWakeAndUnlock(biometricUnlockState.mode)) {
if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
+ // TODO(b/360368320): Adapt for scene framework
} else {
startTransitionTo(
KeyguardState.GONE,
@@ -138,29 +138,21 @@ constructor(
val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value
if (!deviceEntryInteractor.isLockscreenEnabled()) {
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
- } else {
+ if (!SceneContainerFlag.isEnabled) {
startTransitionTo(KeyguardState.GONE)
}
} else if (canDismissLockscreen()) {
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
- } else {
+ if (!SceneContainerFlag.isEnabled) {
startTransitionTo(KeyguardState.GONE)
}
} else if (primaryBouncerShowing) {
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
- } else {
+ if (!SceneContainerFlag.isEnabled) {
startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
}
} else if (isKeyguardOccludedLegacy) {
startTransitionTo(KeyguardState.OCCLUDED)
} else if (isIdleOnCommunal && !communalSceneKtfRefactor()) {
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
- } else {
+ if (!SceneContainerFlag.isEnabled) {
startTransitionTo(KeyguardState.GLANCEABLE_HUB)
}
} else if (
@@ -171,9 +163,7 @@ constructor(
) {
// This case handles tapping the power button to transition through
// dream -> off -> hub.
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
- } else {
+ if (!SceneContainerFlag.isEnabled) {
transitionToGlanceableHub()
}
} else {
@@ -216,30 +206,21 @@ constructor(
!isWakeAndUnlock(biometricUnlockState.mode)
) {
if (canWakeDirectlyToGone) {
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is
- // needed
- } else {
+ if (!SceneContainerFlag.isEnabled) {
startTransitionTo(
KeyguardState.GONE,
ownerReason = "waking from dozing"
)
}
} else if (primaryBouncerShowing) {
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is
- // needed
- } else {
+ if (!SceneContainerFlag.isEnabled) {
startTransitionTo(
KeyguardState.PRIMARY_BOUNCER,
ownerReason = "waking from dozing"
)
}
} else if (isIdleOnCommunal && !communalSceneKtfRefactor()) {
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is
- // needed
- } else {
+ if (!SceneContainerFlag.isEnabled) {
startTransitionTo(
KeyguardState.GLANCEABLE_HUB,
ownerReason = "waking from dozing"
@@ -253,10 +234,7 @@ constructor(
) {
// This case handles tapping the power button to transition through
// dream -> off -> hub.
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Check if adaptation for scene framework is
- // needed
- } else {
+ if (!SceneContainerFlag.isEnabled) {
transitionToGlanceableHub()
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index c9db26dca9e2..0aa50e04087e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -231,7 +231,6 @@ constructor(
}
private fun listenForHubToGone() {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
if (SceneContainerFlag.isEnabled) return
if (communalSceneKtfRefactor()) {
scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 5dc020f41ad3..cd3df07eea55 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -276,7 +276,6 @@ constructor(
}
private fun listenForLockscreenToGone() {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
if (SceneContainerFlag.isEnabled) return
if (KeyguardWmStateRefactor.isEnabled) return
scope.launch("$TAG#listenForLockscreenToGone") {
@@ -292,7 +291,6 @@ constructor(
}
private fun listenForLockscreenToGoneDragging() {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
if (SceneContainerFlag.isEnabled) return
if (KeyguardWmStateRefactor.isEnabled) {
// When the refactor is enabled, we no longer use isKeyguardGoingAway.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 7b6949fdaa2c..0343786bb1fb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -76,7 +76,6 @@ constructor(
}
private fun listenForOccludedToPrimaryBouncer() {
- // TODO(b/336576536): Check if adaptation for scene framework is needed
if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.primaryBouncerShowing
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 0118f8e21f79..52323a51b011 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -35,7 +35,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
-import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.animation.Interpolators
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
index 2ebd9e8c5f2b..b2183007c48c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
@@ -71,7 +71,7 @@ constructor(
)
} else {
if (SceneContainerFlag.isEnabled) {
- // TODO(b/336576536): Some part of the transition implemented for flag off is
+ // TODO(b/360372242): Some part of the transition implemented for flag off is
// missing here. There are two things achieved with this:
// 1. Keyguard is hidden when the setup wizard is shown. This part is already
// implemented in scene container by disabling visibility instead of going
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
index d119ed4f6580..28a17ef4922a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
@@ -94,7 +94,7 @@ constructor(
val disposableHandle =
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch("$TAG#viewModel") {
+ launch {
viewModel.collect { buttonModel ->
updateButton(
view = button,
@@ -104,7 +104,7 @@ constructor(
}
}
- launch("$TAG#updateButtonAlpha") {
+ launch {
updateButtonAlpha(
view = button,
viewModel = viewModel,
@@ -112,7 +112,7 @@ constructor(
)
}
- launch("$TAG#configurationBasedDimensions") {
+ launch {
configurationBasedDimensions.collect { dimensions ->
button.updateLayoutParams<ViewGroup.LayoutParams> {
width = dimensions.buttonSizePx.width
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt
index fb6efd3310f6..3b36762f19da 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt
@@ -34,7 +34,7 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.TAG
import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor
import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
-import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.animation.Interpolators
import java.util.concurrent.Executor
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index 59cb6e5cef91..666c9f8e243b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -32,6 +32,7 @@ import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -72,7 +73,7 @@ constructor(
/** Whether the content of the scene UI should be shown. */
val isContentVisible: StateFlow<Boolean> = _isContentVisible.asStateFlow()
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
coroutineScope {
launch {
combine(
@@ -92,6 +93,8 @@ constructor(
.map { !it }
.collectLatest { _isContentVisible.value = it }
}
+
+ awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/Activatable.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/Activatable.kt
index ebb0ea62a10c..bd3d40b114e3 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/Activatable.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/Activatable.kt
@@ -57,7 +57,7 @@ interface Activatable {
* }
* ```
*/
- suspend fun activate()
+ suspend fun activate(): Nothing
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/SafeActivatable.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/SafeActivatable.kt
index f080a421d295..4dd76f8c78cb 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/SafeActivatable.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/SafeActivatable.kt
@@ -34,7 +34,7 @@ abstract class SafeActivatable : Activatable {
_isActive.set(value)
}
- final override suspend fun activate() {
+ final override suspend fun activate(): Nothing {
val allowed = _isActive.compareAndSet(false, true)
check(allowed) { "Cannot activate an already active activatable!" }
@@ -57,7 +57,7 @@ abstract class SafeActivatable : Activatable {
*
* Implementations could follow this pattern:
* ```kotlin
- * override suspend fun onActivated() {
+ * override suspend fun onActivated(): Nothing {
* coroutineScope {
* launch { ... }
* launch { ... }
@@ -68,5 +68,5 @@ abstract class SafeActivatable : Activatable {
*
* @see activate
*/
- protected abstract suspend fun onActivated()
+ protected abstract suspend fun onActivated(): Nothing
}
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt
index 77314813c34a..2edde4ad046f 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt
@@ -19,12 +19,15 @@ package com.android.systemui.lifecycle
import android.view.View
import androidx.compose.runtime.Composable
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.launch
/** Base class for all System UI view-models. */
abstract class SysUiViewModel : SafeActivatable() {
- override suspend fun onActivated() = Unit
+ override suspend fun onActivated(): Nothing {
+ awaitCancellation()
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
index 62759a4843d9..3c25e6205b05 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
@@ -54,7 +54,6 @@ import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Co
import com.android.systemui.media.controls.ui.viewmodel.MediaOutputSwitcherViewModel
import com.android.systemui.media.controls.ui.viewmodel.MediaPlayerViewModel
import com.android.systemui.media.controls.util.MediaDataUtils
-import com.android.systemui.media.controls.util.MediaFlags
import com.android.systemui.monet.ColorScheme
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
@@ -76,7 +75,6 @@ object MediaControlViewBinder {
falsingManager: FalsingManager,
@Background backgroundDispatcher: CoroutineDispatcher,
@Main mainDispatcher: CoroutineDispatcher,
- mediaFlags: MediaFlags,
) {
val mediaCard = viewHolder.player
mediaCard.repeatWhenAttached {
@@ -91,7 +89,6 @@ object MediaControlViewBinder {
falsingManager,
backgroundDispatcher,
mainDispatcher,
- mediaFlags
)
}
}
@@ -107,7 +104,6 @@ object MediaControlViewBinder {
falsingManager: FalsingManager,
backgroundDispatcher: CoroutineDispatcher,
mainDispatcher: CoroutineDispatcher,
- mediaFlags: MediaFlags,
) {
// Set up media control location and its listener.
viewModel.onLocationChanged(viewController.currentEndLocation)
@@ -164,18 +160,6 @@ object MediaControlViewBinder {
isSongUpdated
)
- // TODO: We don't need to refresh this state constantly, only if the
- // state actually changed to something which might impact the
- // measurement. State refresh interferes with the translation
- // animation, only run it if it's not running.
- if (!viewController.metadataAnimationHandler.isRunning) {
- // Don't refresh in scene framework, because it will calculate
- // with invalid layout sizes
- if (!mediaFlags.isSceneContainerEnabled()) {
- viewController.refreshState()
- }
- }
-
if (viewModel.playTurbulenceNoise) {
viewController.setUpTurbulenceNoise()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index c21301c62c8d..fb2bbde37a18 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -746,7 +746,6 @@ constructor(
falsingManager,
backgroundDispatcher,
mainDispatcher,
- mediaFlags
)
mediaContent.addView(viewHolder.player, position)
controllerById[commonViewModel.instanceId.toString()] = viewController
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
index 2ce7044897be..dd1fa76c65c9 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
@@ -36,8 +36,8 @@ import com.android.systemui.mediaprojection.appselector.view.RecentTasksAdapter.
import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener
import com.android.systemui.res.R
import com.android.systemui.util.recycler.HorizontalSpacerItemDecoration
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
-import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
import com.android.wm.shell.splitscreen.SplitScreen
import com.android.wm.shell.util.SplitBounds
import java.util.Optional
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
index 2c578130e920..0b9cd96670b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
@@ -20,103 +20,40 @@ import android.content.ClipData
import androidx.compose.foundation.draganddrop.dragAndDropSource
import androidx.compose.foundation.draganddrop.dragAndDropTarget
import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.lazy.grid.LazyGridItemInfo
+import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.compose.ui.draganddrop.DragAndDropEvent
import androidx.compose.ui.draganddrop.DragAndDropTarget
import androidx.compose.ui.draganddrop.DragAndDropTransferData
import androidx.compose.ui.draganddrop.mimeTypes
+import androidx.compose.ui.draganddrop.toAndroidDragEvent
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.unit.IntRect
+import androidx.compose.ui.unit.center
+import androidx.compose.ui.unit.toRect
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
-@Composable
-fun rememberDragAndDropState(listState: EditTileListState): DragAndDropState {
- val draggedCell: MutableState<SizedTile<EditTileViewModel>?> = remember { mutableStateOf(null) }
- return remember(listState) { DragAndDropState(draggedCell, listState) }
-}
-
-/**
- * Holds the [TileSpec] of the tile being moved and modify the [EditTileListState] based on drag and
- * drop events.
- */
-class DragAndDropState(
- val draggedCell: MutableState<SizedTile<EditTileViewModel>?>,
- private val listState: EditTileListState,
-) {
+/** Holds the [TileSpec] of the tile being moved and receives drag and drop events. */
+interface DragAndDropState {
+ val draggedCell: SizedTile<EditTileViewModel>?
val dragInProgress: Boolean
- get() = draggedCell.value != null
-
- /** Returns index of the dragged tile if it's present in the list. Returns -1 if not. */
- fun currentPosition(): Int {
- return draggedCell.value?.let { listState.indexOf(it.tile.tileSpec) } ?: -1
- }
-
- fun isMoving(tileSpec: TileSpec): Boolean {
- return draggedCell.value?.let { it.tile.tileSpec == tileSpec } ?: false
- }
- fun onStarted(cell: SizedTile<EditTileViewModel>) {
- draggedCell.value = cell
- }
+ fun isMoving(tileSpec: TileSpec): Boolean
- fun onMoved(targetSpec: TileSpec) {
- draggedCell.value?.let { listState.move(it, targetSpec) }
- }
+ fun onStarted(cell: SizedTile<EditTileViewModel>)
- fun movedOutOfBounds() {
- // Removing the tiles from the current tile grid if it moves out of bounds. This clears
- // the spacer and makes it apparent that dropping the tile at that point would remove it.
- draggedCell.value?.let { listState.remove(it.tile.tileSpec) }
- }
+ fun onMoved(target: Int, insertAfter: Boolean)
- fun onDrop() {
- draggedCell.value = null
- }
-}
-
-/**
- * Registers a tile as a [DragAndDropTarget] to receive drag events and update the
- * [DragAndDropState] with the tile's position, which can be used to insert a temporary placeholder.
- *
- * @param dragAndDropState The [DragAndDropState] using the tiles list
- * @param tileSpec The [TileSpec] of the tile
- * @param acceptDrops Whether the tile should accept a drop based on a given [TileSpec]
- * @param onDrop Action to be executed when a [TileSpec] is dropped on the tile
- */
-@Composable
-fun Modifier.dragAndDropTile(
- dragAndDropState: DragAndDropState,
- tileSpec: TileSpec,
- acceptDrops: (TileSpec) -> Boolean,
- onDrop: (TileSpec, Int) -> Unit,
-): Modifier {
- val target =
- remember(dragAndDropState) {
- object : DragAndDropTarget {
- override fun onDrop(event: DragAndDropEvent): Boolean {
- return dragAndDropState.draggedCell.value?.let {
- onDrop(it.tile.tileSpec, dragAndDropState.currentPosition())
- dragAndDropState.onDrop()
- true
- } ?: false
- }
+ fun movedOutOfBounds()
- override fun onEntered(event: DragAndDropEvent) {
- dragAndDropState.onMoved(tileSpec)
- }
- }
- }
- return dragAndDropTarget(
- shouldStartDragAndDrop = { event ->
- event.mimeTypes().contains(QsDragAndDrop.TILESPEC_MIME_TYPE) &&
- dragAndDropState.draggedCell.value?.let { acceptDrops(it.tile.tileSpec) } ?: false
- },
- target = target,
- )
+ fun onDrop()
}
/**
@@ -135,7 +72,7 @@ fun Modifier.dragAndDropRemoveZone(
remember(dragAndDropState) {
object : DragAndDropTarget {
override fun onDrop(event: DragAndDropEvent): Boolean {
- return dragAndDropState.draggedCell.value?.let {
+ return dragAndDropState.draggedCell?.let {
onDrop(it.tile.tileSpec)
dragAndDropState.onDrop()
true
@@ -156,19 +93,22 @@ fun Modifier.dragAndDropRemoveZone(
}
/**
- * Registers a tile list as a [DragAndDropTarget] to receive drop events. Use this on list
- * containers to catch drops outside of tiles.
+ * Registers a tile list as a [DragAndDropTarget] to receive drop events. Use this on the lazy tile
+ * grid to receive drag and drops events.
*
+ * @param gridState The [LazyGridState] of the tile list
+ * @param contentOffset The [Offset] of the tile list
* @param dragAndDropState The [DragAndDropState] using the tiles list
- * @param acceptDrops Whether the tile should accept a drop based on a given [TileSpec]
- * @param onDrop Action to be executed when a [TileSpec] is dropped on the tile
+ * @param onDrop Callback when a tile is dropped
*/
@Composable
fun Modifier.dragAndDropTileList(
+ gridState: LazyGridState,
+ contentOffset: Offset,
dragAndDropState: DragAndDropState,
- acceptDrops: (TileSpec) -> Boolean,
- onDrop: (TileSpec, Int) -> Unit,
+ onDrop: () -> Unit,
): Modifier {
+ val currentContentOffset by rememberUpdatedState(contentOffset)
val target =
remember(dragAndDropState) {
object : DragAndDropTarget {
@@ -176,9 +116,23 @@ fun Modifier.dragAndDropTileList(
dragAndDropState.onDrop()
}
+ override fun onMoved(event: DragAndDropEvent) {
+ // Drag offset relative to the list's top left corner
+ val relativeDragOffset = event.dragOffsetRelativeTo(currentContentOffset)
+ val targetItem =
+ gridState.layoutInfo.visibleItemsInfo.firstOrNull { item ->
+ // Check if the drag is on this item
+ IntRect(item.offset, item.size).toRect().contains(relativeDragOffset)
+ }
+
+ targetItem?.let {
+ dragAndDropState.onMoved(it.index, insertAfter(it, relativeDragOffset))
+ }
+ }
+
override fun onDrop(event: DragAndDropEvent): Boolean {
- return dragAndDropState.draggedCell.value?.let {
- onDrop(it.tile.tileSpec, dragAndDropState.currentPosition())
+ return dragAndDropState.draggedCell?.let {
+ onDrop()
dragAndDropState.onDrop()
true
} ?: false
@@ -188,12 +142,22 @@ fun Modifier.dragAndDropTileList(
return dragAndDropTarget(
target = target,
shouldStartDragAndDrop = { event ->
- event.mimeTypes().contains(QsDragAndDrop.TILESPEC_MIME_TYPE) &&
- dragAndDropState.draggedCell.value?.let { acceptDrops(it.tile.tileSpec) } ?: false
+ event.mimeTypes().contains(QsDragAndDrop.TILESPEC_MIME_TYPE)
},
)
}
+private fun DragAndDropEvent.dragOffsetRelativeTo(offset: Offset): Offset {
+ return toAndroidDragEvent().run { Offset(x, y) } - offset
+}
+
+private fun insertAfter(item: LazyGridItemInfo, offset: Offset): Boolean {
+ // We want to insert the tile after the target if we're aiming at the right side of a large tile
+ // TODO(ostonge): Verify this behavior in RTL
+ val itemCenter = item.offset + item.size.center
+ return item.span != 1 && offset.x > itemCenter.x
+}
+
fun Modifier.dragAndDropTileSource(
sizedTile: SizedTile<EditTileViewModel>,
onTap: (TileSpec) -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt
index 3bda7757f8e5..1674865bcce6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt
@@ -43,6 +43,7 @@ fun EditMode(
Modifier,
viewModel::addTile,
viewModel::removeTile,
+ viewModel::setTiles,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
index fa3008e3f292..4830ba7baa9b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
@@ -17,46 +17,106 @@
package com.android.systemui.qs.panels.ui.compose
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.runtime.toMutableStateList
import com.android.systemui.qs.panels.shared.model.SizedTile
+import com.android.systemui.qs.panels.ui.model.GridCell
+import com.android.systemui.qs.panels.ui.model.TileGridCell
+import com.android.systemui.qs.panels.ui.model.toGridCells
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
+/**
+ * Creates the edit tile list state that is remembered across compositions.
+ *
+ * Changes to the tiles or columns will recreate the state.
+ */
@Composable
fun rememberEditListState(
tiles: List<SizedTile<EditTileViewModel>>,
+ columns: Int,
): EditTileListState {
- return remember(tiles) { EditTileListState(tiles) }
+ return remember(tiles, columns) { EditTileListState(tiles, columns) }
}
/** Holds the temporary state of the tile list during a drag movement where we move tiles around. */
-class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>) {
- val tiles: SnapshotStateList<SizedTile<EditTileViewModel>> = tiles.toMutableStateList()
+class EditTileListState(
+ tiles: List<SizedTile<EditTileViewModel>>,
+ private val columns: Int,
+) : DragAndDropState {
+ private val _draggedCell = mutableStateOf<SizedTile<EditTileViewModel>?>(null)
+ override val draggedCell
+ get() = _draggedCell.value
+
+ override val dragInProgress: Boolean
+ get() = _draggedCell.value != null
+
+ private val _tiles: SnapshotStateList<GridCell> =
+ tiles.toGridCells(columns).toMutableStateList()
+ val tiles: List<GridCell>
+ get() = _tiles.toList()
+
+ fun tileSpecs(): List<TileSpec> {
+ return _tiles.filterIsInstance<TileGridCell>().map { it.tile.tileSpec }
+ }
+
+ fun indexOf(tileSpec: TileSpec): Int {
+ return _tiles.indexOfFirst { it is TileGridCell && it.tile.tileSpec == tileSpec }
+ }
+
+ override fun isMoving(tileSpec: TileSpec): Boolean {
+ return _draggedCell.value?.let { it.tile.tileSpec == tileSpec } ?: false
+ }
- fun move(sizedTile: SizedTile<EditTileViewModel>, target: TileSpec) {
- val fromIndex = indexOf(sizedTile.tile.tileSpec)
- val toIndex = indexOf(target)
+ override fun onStarted(cell: SizedTile<EditTileViewModel>) {
+ _draggedCell.value = cell
- if (toIndex == -1 || fromIndex == toIndex) {
+ // Add visible spacers to the grid to indicate where the user can move a tile
+ regenerateGrid(includeSpacers = true)
+ }
+
+ override fun onMoved(target: Int, insertAfter: Boolean) {
+ val draggedTile = _draggedCell.value ?: return
+
+ val fromIndex = indexOf(draggedTile.tile.tileSpec)
+ if (fromIndex == target) {
return
}
- if (fromIndex == -1) {
- // If tile isn't in the list, simply insert it
- tiles.add(toIndex, sizedTile)
+ val insertionIndex = if (insertAfter) target + 1 else target
+ if (fromIndex != -1) {
+ val cell = _tiles.removeAt(fromIndex)
+ regenerateGrid(includeSpacers = true)
+ _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell)
} else {
- // If tile is present in the list, move it
- tiles.apply { add(toIndex, removeAt(fromIndex)) }
+ // Add the tile with a temporary row which will get reassigned when regenerating spacers
+ _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0))
}
+
+ regenerateGrid(includeSpacers = true)
}
- fun remove(tileSpec: TileSpec) {
- tiles.removeIf { it.tile.tileSpec == tileSpec }
+ override fun movedOutOfBounds() {
+ val draggedTile = _draggedCell.value ?: return
+
+ _tiles.removeIf { cell ->
+ cell is TileGridCell && cell.tile.tileSpec == draggedTile.tile.tileSpec
+ }
}
- fun indexOf(tileSpec: TileSpec): Int {
- return tiles.indexOfFirst { it.tile.tileSpec == tileSpec }
+ override fun onDrop() {
+ _draggedCell.value = null
+
+ // Remove the spacers
+ regenerateGrid(includeSpacers = false)
+ }
+
+ private fun regenerateGrid(includeSpacers: Boolean) {
+ _tiles.filterIsInstance<TileGridCell>().toGridCells(columns, includeSpacers).let {
+ _tiles.clear()
+ _tiles.addAll(it)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
index e2f6bcf2e872..fd276c2dd220 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
@@ -39,6 +39,7 @@ interface GridLayout {
modifier: Modifier,
onAddTile: (TileSpec, Int) -> Unit,
onRemoveTile: (TileSpec) -> Unit,
+ onSetTiles: (List<TileSpec>) -> Unit,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
index bd925fee2800..d948dfd7d3b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
@@ -76,6 +76,7 @@ constructor(
modifier: Modifier,
onAddTile: (TileSpec, Int) -> Unit,
onRemoveTile: (TileSpec) -> Unit,
+ onSetTiles: (List<TileSpec>) -> Unit,
) {
val columns by gridSizeViewModel.columns.collectAsStateWithLifecycle()
val largeTiles by iconTilesViewModel.largeTiles.collectAsStateWithLifecycle()
@@ -91,12 +92,16 @@ constructor(
}
}
+ val (currentTiles, otherTiles) = sizedTiles.partition { it.tile.isCurrent }
+ val currentListState = rememberEditListState(currentTiles, columns)
DefaultEditTileGrid(
- sizedTiles = sizedTiles,
+ currentListState = currentListState,
+ otherTiles = otherTiles,
columns = columns,
modifier = modifier,
onAddTile = onAddTile,
onRemoveTile = onRemoveTile,
+ onSetTiles = onSetTiles,
onResize = iconTilesViewModel::resize,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
index 9c0701e974ec..c06d6d2dc957 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
@@ -52,8 +52,11 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyGridItemScope
import androidx.compose.foundation.lazy.grid.LazyGridScope
+import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -75,9 +78,13 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.onClick
@@ -89,6 +96,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.Expandable
+import com.android.compose.modifiers.background
import com.android.compose.modifiers.thenIf
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
@@ -96,8 +104,10 @@ import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.common.ui.compose.load
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.panels.shared.model.SizedTile
+import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.model.GridCell
+import com.android.systemui.qs.panels.ui.model.SpacerGridCell
import com.android.systemui.qs.panels.ui.model.TileGridCell
-import com.android.systemui.qs.panels.ui.model.toTileGridCells
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.toUiState
@@ -269,10 +279,12 @@ private fun Modifier.tileMarquee(): Modifier {
@Composable
fun TileLazyGrid(
modifier: Modifier = Modifier,
+ state: LazyGridState = rememberLazyGridState(),
columns: GridCells,
content: LazyGridScope.() -> Unit,
) {
LazyVerticalGrid(
+ state = state,
columns = columns,
verticalArrangement = spacedBy(dimensionResource(R.dimen.qs_tile_margin_vertical)),
horizontalArrangement = spacedBy(dimensionResource(R.dimen.qs_tile_margin_horizontal)),
@@ -283,23 +295,18 @@ fun TileLazyGrid(
@Composable
fun DefaultEditTileGrid(
- sizedTiles: List<SizedTile<EditTileViewModel>>,
+ currentListState: EditTileListState,
+ otherTiles: List<SizedTile<EditTileViewModel>>,
columns: Int,
modifier: Modifier,
onAddTile: (TileSpec, Int) -> Unit,
onRemoveTile: (TileSpec) -> Unit,
+ onSetTiles: (List<TileSpec>) -> Unit,
onResize: (TileSpec) -> Unit,
) {
- val (currentTiles, otherTiles) = sizedTiles.partition { it.tile.isCurrent }
- val currentListState = rememberEditListState(currentTiles)
- val dragAndDropState = rememberDragAndDropState(currentListState)
-
val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState {
onAddTile(it, CurrentTilesInteractor.POSITION_AT_END)
}
- val onDropAdd: (TileSpec, Int) -> Unit by rememberUpdatedState { tileSpec, position ->
- onAddTile(tileSpec, position)
- }
val tilePadding = dimensionResource(R.dimen.qs_tile_margin_vertical)
CompositionLocalProvider(LocalOverscrollConfiguration provides null) {
@@ -309,10 +316,10 @@ fun DefaultEditTileGrid(
modifier = modifier.fillMaxSize().verticalScroll(rememberScrollState())
) {
AnimatedContent(
- targetState = dragAndDropState.dragInProgress,
+ targetState = currentListState.dragInProgress,
modifier = Modifier.wrapContentSize()
) { dragIsInProgress ->
- EditGridHeader(Modifier.dragAndDropRemoveZone(dragAndDropState, onRemoveTile)) {
+ EditGridHeader(Modifier.dragAndDropRemoveZone(currentListState, onRemoveTile)) {
if (dragIsInProgress) {
RemoveTileTarget()
} else {
@@ -322,18 +329,17 @@ fun DefaultEditTileGrid(
}
CurrentTilesGrid(
- currentListState.tiles,
+ currentListState,
columns,
tilePadding,
onRemoveTile,
onResize,
- dragAndDropState,
- onDropAdd,
+ onSetTiles,
)
// Hide available tiles when dragging
AnimatedVisibility(
- visible = !dragAndDropState.dragInProgress,
+ visible = !currentListState.dragInProgress,
enter = fadeIn(),
exit = fadeOut()
) {
@@ -349,7 +355,7 @@ fun DefaultEditTileGrid(
columns,
tilePadding,
addTileToEnd,
- dragAndDropState,
+ currentListState,
)
}
}
@@ -359,7 +365,7 @@ fun DefaultEditTileGrid(
modifier =
Modifier.fillMaxWidth()
.weight(1f)
- .dragAndDropRemoveZone(dragAndDropState, onRemoveTile)
+ .dragAndDropRemoveZone(currentListState, onRemoveTile)
)
}
}
@@ -375,7 +381,7 @@ private fun EditGridHeader(
) {
Box(
contentAlignment = Alignment.Center,
- modifier = modifier.fillMaxWidth().height(TileDefaults.EditGridHeaderHeight)
+ modifier = modifier.fillMaxWidth().height(EditModeTileDefaults.EditGridHeaderHeight)
) {
content()
}
@@ -414,35 +420,42 @@ private fun CurrentTilesContainer(content: @Composable () -> Unit) {
@Composable
private fun CurrentTilesGrid(
- tiles: List<SizedTile<EditTileViewModel>>,
+ listState: EditTileListState,
columns: Int,
tilePadding: Dp,
onClick: (TileSpec) -> Unit,
onResize: (TileSpec) -> Unit,
- dragAndDropState: DragAndDropState,
- onDrop: (TileSpec, Int) -> Unit
+ onSetTiles: (List<TileSpec>) -> Unit,
) {
- // Current tiles
+ val currentListState by rememberUpdatedState(listState)
+
CurrentTilesContainer {
- val cells = tiles.toTileGridCells(columns)
val tileHeight = tileHeight()
- val totalRows = cells.lastOrNull()?.row ?: 0
+ val totalRows = listState.tiles.lastOrNull()?.row ?: 0
val totalHeight = gridHeight(totalRows + 1, tileHeight, tilePadding)
+ val gridState = rememberLazyGridState()
+ var gridContentOffset by remember { mutableStateOf(Offset(0f, 0f)) }
+
TileLazyGrid(
+ state = gridState,
modifier =
Modifier.height(totalHeight)
- .dragAndDropTileList(dragAndDropState, { true }, onDrop),
+ .dragAndDropTileList(gridState, gridContentOffset, listState) {
+ onSetTiles(currentListState.tileSpecs())
+ }
+ .onGloballyPositioned { coordinates ->
+ gridContentOffset = coordinates.positionInRoot()
+ }
+ .testTag(CURRENT_TILES_GRID_TEST_TAG),
columns = GridCells.Fixed(columns)
) {
editTiles(
- cells,
+ listState.tiles,
ClickAction.REMOVE,
onClick,
- dragAndDropState,
+ listState,
onResize = onResize,
indicatePosition = true,
- acceptDrops = { true },
- onDrop = onDrop,
)
}
}
@@ -464,7 +477,7 @@ private fun AvailableTileGrid(
// Available tiles
TileLazyGrid(
- modifier = Modifier.height(availableGridHeight),
+ modifier = Modifier.height(availableGridHeight).testTag(AVAILABLE_TILES_GRID_TEST_TAG),
columns = GridCells.Fixed(columns)
) {
editTiles(
@@ -472,7 +485,6 @@ private fun AvailableTileGrid(
ClickAction.ADD,
onClick,
dragAndDropState = dragAndDropState,
- acceptDrops = { false },
showLabels = true,
)
editTiles(
@@ -480,7 +492,6 @@ private fun AvailableTileGrid(
ClickAction.ADD,
onClick,
dragAndDropState = dragAndDropState,
- acceptDrops = { false },
showLabels = true,
)
}
@@ -495,64 +506,109 @@ fun gridHeight(rows: Int, tileHeight: Dp, padding: Dp): Dp {
return ((tileHeight + padding) * rows) - padding
}
+private fun GridCell.key(index: Int, dragAndDropState: DragAndDropState): Any {
+ return if (this is TileGridCell && !dragAndDropState.isMoving(tile.tileSpec)) {
+ key
+ } else {
+ index
+ }
+}
+
fun LazyGridScope.editTiles(
- cells: List<TileGridCell>,
+ cells: List<GridCell>,
clickAction: ClickAction,
onClick: (TileSpec) -> Unit,
dragAndDropState: DragAndDropState,
- acceptDrops: (TileSpec) -> Boolean,
onResize: (TileSpec) -> Unit = {},
- onDrop: (TileSpec, Int) -> Unit = { _, _ -> },
showLabels: Boolean = false,
indicatePosition: Boolean = false,
) {
items(
count = cells.size,
- key = { cells[it].key },
+ key = { cells[it].key(it, dragAndDropState) },
span = { cells[it].span },
contentType = { TileType }
) { index ->
- val cell = cells[index]
- val tileHeight = tileHeight(cell.isIcon && showLabels)
-
- if (!dragAndDropState.isMoving(cell.tile.tileSpec)) {
- val onClickActionName =
- when (clickAction) {
- ClickAction.ADD ->
- stringResource(id = R.string.accessibility_qs_edit_tile_add_action)
- ClickAction.REMOVE ->
- stringResource(id = R.string.accessibility_qs_edit_remove_tile_action)
- }
- val stateDescription =
- if (indicatePosition) {
- stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
+ when (val cell = cells[index]) {
+ is TileGridCell ->
+ if (dragAndDropState.isMoving(cell.tile.tileSpec)) {
+ // If the tile is being moved, replace it with a visible spacer
+ SpacerGridCell(
+ Modifier.background(
+ color = MaterialTheme.colorScheme.secondary,
+ alpha = { EditModeTileDefaults.PLACEHOLDER_ALPHA },
+ shape = TileDefaults.TileShape
+ )
+ .animateItem()
+ )
} else {
- ""
+ TileGridCell(
+ cell = cell,
+ index = index,
+ dragAndDropState = dragAndDropState,
+ clickAction = clickAction,
+ onClick = onClick,
+ onResize = onResize,
+ showLabels = showLabels,
+ indicatePosition = indicatePosition
+ )
}
- EditTile(
- tileViewModel = cell.tile,
- iconOnly = cell.isIcon,
- showLabels = showLabels,
- modifier =
- Modifier.height(tileHeight)
- .animateItem()
- .semantics {
- onClick(onClickActionName) { false }
- this.stateDescription = stateDescription
- }
- .dragAndDropTile(dragAndDropState, cell.tile.tileSpec, acceptDrops, onDrop)
- .dragAndDropTileSource(
- cell,
- onClick,
- onResize,
- dragAndDropState,
- )
- )
+ is SpacerGridCell -> SpacerGridCell()
}
}
}
@Composable
+private fun LazyGridItemScope.TileGridCell(
+ cell: TileGridCell,
+ index: Int,
+ dragAndDropState: DragAndDropState,
+ clickAction: ClickAction,
+ onClick: (TileSpec) -> Unit,
+ onResize: (TileSpec) -> Unit = {},
+ showLabels: Boolean = false,
+ indicatePosition: Boolean = false,
+) {
+ val tileHeight = tileHeight(cell.isIcon && showLabels)
+ val onClickActionName =
+ when (clickAction) {
+ ClickAction.ADD -> stringResource(id = R.string.accessibility_qs_edit_tile_add_action)
+ ClickAction.REMOVE ->
+ stringResource(id = R.string.accessibility_qs_edit_remove_tile_action)
+ }
+ val stateDescription =
+ if (indicatePosition) {
+ stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
+ } else {
+ ""
+ }
+ EditTile(
+ tileViewModel = cell.tile,
+ iconOnly = cell.isIcon,
+ showLabels = showLabels,
+ modifier =
+ Modifier.height(tileHeight)
+ .animateItem()
+ .semantics {
+ onClick(onClickActionName) { false }
+ this.stateDescription = stateDescription
+ }
+ .dragAndDropTileSource(
+ SizedTileImpl(cell.tile, cell.width),
+ onClick,
+ onResize,
+ dragAndDropState,
+ )
+ )
+}
+
+@Composable
+private fun SpacerGridCell(modifier: Modifier = Modifier) {
+ // By default, spacers are invisible and exist purely to catch drag movements
+ Box(modifier.height(tileHeight()).fillMaxWidth().tilePadding())
+}
+
+@Composable
fun EditTile(
tileViewModel: EditTileViewModel,
iconOnly: Boolean,
@@ -641,7 +697,7 @@ private fun TileIcon(
}
Image(
painter = painter,
- contentDescription = null,
+ contentDescription = icon.contentDescription?.load(),
colorFilter = ColorFilter.tint(color = color),
modifier = iconModifier
)
@@ -678,10 +734,14 @@ private data class TileColors(
val icon: Color,
)
+private object EditModeTileDefaults {
+ const val PLACEHOLDER_ALPHA = .3f
+ val EditGridHeaderHeight = 60.dp
+}
+
private object TileDefaults {
val TileShape = CircleShape
val IconTileWithLabelHeight = 140.dp
- val EditGridHeaderHeight = 60.dp
@Composable
fun activeTileColors(): TileColors =
@@ -722,3 +782,6 @@ private object TileDefaults {
}
}
}
+
+private const val CURRENT_TILES_GRID_TEST_TAG = "CurrentTilesGrid"
+private const val AVAILABLE_TILES_GRID_TEST_TAG = "AvailableTilesGrid"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
index c241fd87d9d5..8ca8de762772 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
@@ -22,6 +22,12 @@ import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.shared.model.splitInRowsSequence
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
+/** Represents an item from a grid associated with a row and a span */
+interface GridCell {
+ val row: Int
+ val span: GridItemSpan
+}
+
/**
* Represents a [EditTileViewModel] from a grid associated with a tile format and the row it's
* positioned at
@@ -29,10 +35,12 @@ import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
@Immutable
data class TileGridCell(
override val tile: EditTileViewModel,
- val row: Int,
- val key: String = "${tile.tileSpec.spec}-$row",
+ override val row: Int,
override val width: Int,
-) : SizedTile<EditTileViewModel> {
+ override val span: GridItemSpan = GridItemSpan(width)
+) : GridCell, SizedTile<EditTileViewModel> {
+ val key: String = "${tile.tileSpec.spec}-$row"
+
constructor(
sizedTile: SizedTile<EditTileViewModel>,
row: Int
@@ -41,12 +49,30 @@ data class TileGridCell(
row = row,
width = sizedTile.width,
)
-
- val span = GridItemSpan(width)
}
-fun List<SizedTile<EditTileViewModel>>.toTileGridCells(columns: Int): List<TileGridCell> {
+/** Represents an empty space used to fill incomplete rows. Will always display as a 1x1 tile */
+@Immutable
+data class SpacerGridCell(
+ override val row: Int,
+ override val span: GridItemSpan = GridItemSpan(1)
+) : GridCell
+
+fun List<SizedTile<EditTileViewModel>>.toGridCells(
+ columns: Int,
+ includeSpacers: Boolean = false
+): List<GridCell> {
return splitInRowsSequence(this, columns)
- .flatMapIndexed { index, sizedTiles -> sizedTiles.map { TileGridCell(it, index) } }
+ .flatMapIndexed { rowIndex, sizedTiles ->
+ val row: List<GridCell> = sizedTiles.map { TileGridCell(it, rowIndex) }
+
+ if (includeSpacers) {
+ // Fill the incomplete rows with spacers
+ val numSpacers = columns - sizedTiles.sumOf { it.width }
+ row.toMutableList().apply { repeat(numSpacers) { add(SpacerGridCell(rowIndex)) } }
+ } else {
+ row
+ }
+ }
.toList()
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
index ef2c8bfe0e4c..42715be6f6c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
@@ -179,6 +179,10 @@ constructor(
currentTilesInteractor.removeTiles(listOf(tileSpec))
}
+ fun setTiles(tileSpecs: List<TileSpec>) {
+ currentTilesInteractor.setTiles(tileSpecs)
+ }
+
/** Immediately resets the current tiles to the default list. */
fun resetCurrentTilesToDefault() {
throw NotImplementedError("This is not supported yet")
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
index 2a33a16fa43a..5f10b385e23b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
@@ -20,6 +20,7 @@ import android.app.Flags
import android.content.Intent
import android.os.Handler
import android.os.Looper
+import android.service.quicksettings.Tile
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import androidx.lifecycle.repeatOnLifecycle
@@ -94,7 +95,13 @@ constructor(
override fun getTileLabel(): CharSequence = tileState.label
- override fun newTileState() = QSTile.State()
+ override fun newTileState(): QSTile.State {
+ return QSTile.State().apply {
+ label = mContext.getString(R.string.quick_settings_modes_label)
+ icon = ResourceIcon.get(R.drawable.qs_dnd_icon_off)
+ state = Tile.STATE_INACTIVE
+ }
+ }
override fun handleClick(expandable: Expandable?) = runBlocking {
userActionInteractor.handleClick(expandable)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index b2873c5662e7..5ea9e6ae0a70 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -346,7 +346,6 @@ public class InternetDialogController implements AccessPointController.AccessPoi
mCallback = null;
}
- @VisibleForTesting
boolean isAirplaneModeEnabled() {
return mGlobalSettings.getInt(Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
index f0183360bea9..71f8639c1e22 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
@@ -30,7 +30,6 @@ import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyDisplayInfo;
-import android.telephony.TelephonyManager;
import android.text.Html;
import android.text.Layout;
import android.text.TextUtils;
@@ -50,9 +49,14 @@ import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.MainThread;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.lifecycle.MutableLiveData;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -110,7 +114,6 @@ public class InternetDialogDelegate implements
protected boolean mCanConfigWifi;
private final InternetDialogManager mInternetDialogManager;
- private TelephonyManager mTelephonyManager;
@Nullable
private AlertDialog mAlertDialog;
private final UiEventLogger mUiEventLogger;
@@ -169,6 +172,13 @@ public class InternetDialogDelegate implements
@Nullable
private Job mClickJob;
+ // These are to reduce the UI janky frame duration. b/323286540
+ private LifecycleRegistry mLifecycleRegistry;
+ @VisibleForTesting
+ LifecycleOwner mLifecycleOwner;
+ @VisibleForTesting
+ MutableLiveData<InternetContent> mDataInternetContent = new MutableLiveData<>();
+
@AssistedFactory
public interface Factory {
InternetDialogDelegate create(
@@ -205,7 +215,6 @@ public class InternetDialogDelegate implements
mInternetDialogManager = internetDialogManager;
mInternetDialogController = internetDialogController;
mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId();
- mTelephonyManager = mInternetDialogController.getTelephonyManager();
mCanConfigMobileData = canConfigMobileData;
mCanConfigWifi = canConfigWifi;
mCanChangeWifiState = WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context);
@@ -227,6 +236,14 @@ public class InternetDialogDelegate implements
mDialog.dismiss();
}
mDialog = dialog;
+ mLifecycleOwner = new LifecycleOwner() {
+ @NonNull
+ @Override
+ public Lifecycle getLifecycle() {
+ return mLifecycleRegistry;
+ }
+ };
+ mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
return dialog;
}
@@ -249,7 +266,9 @@ public class InternetDialogDelegate implements
mWifiNetworkHeight = context.getResources()
.getDimensionPixelSize(R.dimen.internet_dialog_wifi_network_height);
-
+ mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
+ mDataInternetContent.observe(
+ mLifecycleOwner, (internetContent) -> updateDialogUI(internetContent));
mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
mDivider = mDialogView.requireViewById(R.id.divider);
@@ -294,6 +313,8 @@ public class InternetDialogDelegate implements
if (DEBUG) {
Log.d(TAG, "onStart");
}
+
+ mLifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED);
mInternetDialogController.onStart(this, mCanConfigWifi);
if (!mCanConfigWifi) {
hideWifiViews();
@@ -315,6 +336,7 @@ public class InternetDialogDelegate implements
if (DEBUG) {
Log.d(TAG, "onStop");
}
+ mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
mMobileNetworkLayout.setOnClickListener(null);
mConnectedWifListLayout.setOnClickListener(null);
if (mSecondaryMobileNetworkLayout != null) {
@@ -348,31 +370,50 @@ public class InternetDialogDelegate implements
* otherwise {@code false}.
*/
void updateDialog(boolean shouldUpdateMobileNetwork) {
+ mBackgroundExecutor.execute(() -> {
+ mDataInternetContent.postValue(getInternetContent(shouldUpdateMobileNetwork));
+ });
+ }
+
+ private void updateDialogUI(InternetContent internetContent) {
if (DEBUG) {
- Log.d(TAG, "updateDialog");
+ Log.d(TAG, "updateDialog ");
}
- mInternetDialogTitle.setText(getDialogTitleText());
- mInternetDialogSubTitle.setText(getSubtitleText());
+
+ mInternetDialogTitle.setText(internetContent.mInternetDialogTitleString);
+ mInternetDialogSubTitle.setText(internetContent.mInternetDialogSubTitle);
mAirplaneModeButton.setVisibility(
- mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
+ internetContent.mIsAirplaneModeEnabled ? View.VISIBLE : View.GONE);
- updateEthernet();
- if (shouldUpdateMobileNetwork) {
- setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular(),
- mInternetDialogController.isCarrierNetworkActive());
- }
+ updateEthernet(internetContent);
+ setMobileDataLayout(internetContent);
if (!mCanConfigWifi) {
return;
}
-
- final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
- final boolean isWifiEnabled = mInternetDialogController.isWifiEnabled();
- final boolean isWifiScanEnabled = mInternetDialogController.isWifiScanEnabled();
- updateWifiToggle(isWifiEnabled, isDeviceLocked);
- updateConnectedWifi(isWifiEnabled, isDeviceLocked);
- updateWifiListAndSeeAll(isWifiEnabled, isDeviceLocked);
- updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked);
+ updateWifiToggle(internetContent);
+ updateConnectedWifi(internetContent);
+ updateWifiListAndSeeAll(internetContent);
+ updateWifiScanNotify(internetContent);
+ }
+
+ private InternetContent getInternetContent(boolean shouldUpdateMobileNetwork) {
+ InternetContent internetContent = new InternetContent();
+ internetContent.mShouldUpdateMobileNetwork = shouldUpdateMobileNetwork;
+ internetContent.mInternetDialogTitleString = getDialogTitleText();
+ internetContent.mInternetDialogSubTitle = getSubtitleText();
+ internetContent.mActiveNetworkIsCellular =
+ mInternetDialogController.activeNetworkIsCellular();
+ internetContent.mIsCarrierNetworkActive =
+ mInternetDialogController.isCarrierNetworkActive();
+ internetContent.mIsAirplaneModeEnabled = mInternetDialogController.isAirplaneModeEnabled();
+ internetContent.mHasEthernet = mInternetDialogController.hasEthernet();
+ internetContent.mIsWifiEnabled = mInternetDialogController.isWifiEnabled();
+ internetContent.mHasActiveSubIdOnDds = mInternetDialogController.hasActiveSubIdOnDds();
+ internetContent.mIsMobileDataEnabled = mInternetDialogController.isMobileDataEnabled();
+ internetContent.mIsDeviceLocked = mInternetDialogController.isDeviceLocked();
+ internetContent.mIsWifiScanEnabled = mInternetDialogController.isWifiScanEnabled();
+ return internetContent;
}
private void setOnClickListener(SystemUIDialog dialog) {
@@ -436,39 +477,39 @@ public class InternetDialogDelegate implements
}
@MainThread
- private void updateEthernet() {
+ private void updateEthernet(InternetContent internetContent) {
mEthernetLayout.setVisibility(
- mInternetDialogController.hasEthernet() ? View.VISIBLE : View.GONE);
+ internetContent.mHasEthernet ? View.VISIBLE : View.GONE);
}
- private void setMobileDataLayout(boolean activeNetworkIsCellular,
- boolean isCarrierNetworkActive) {
-
- if (mDialog != null) {
- setMobileDataLayout(mDialog, activeNetworkIsCellular, isCarrierNetworkActive);
+ private void setMobileDataLayout(InternetContent internetContent) {
+ if (!internetContent.mShouldUpdateMobileNetwork && mDialog == null) {
+ return;
}
+ setMobileDataLayout(mDialog, internetContent);
}
- private void setMobileDataLayout(SystemUIDialog dialog, boolean activeNetworkIsCellular,
- boolean isCarrierNetworkActive) {
- boolean isNetworkConnected = activeNetworkIsCellular || isCarrierNetworkActive;
+ private void setMobileDataLayout(SystemUIDialog dialog, InternetContent internetContent) {
+ boolean isNetworkConnected =
+ internetContent.mActiveNetworkIsCellular
+ || internetContent.mIsCarrierNetworkActive;
// 1. Mobile network should be gone if airplane mode ON or the list of active
// subscriptionId is null.
// 2. Carrier network should be gone if airplane mode ON and Wi-Fi is OFF.
if (DEBUG) {
- Log.d(TAG, "setMobileDataLayout, isCarrierNetworkActive = " + isCarrierNetworkActive);
+ Log.d(TAG, "setMobileDataLayout, isCarrierNetworkActive = "
+ + internetContent.mIsCarrierNetworkActive);
}
- boolean isWifiEnabled = mInternetDialogController.isWifiEnabled();
- if (!mInternetDialogController.hasActiveSubIdOnDds()
- && (!isWifiEnabled || !isCarrierNetworkActive)) {
+ if (!internetContent.mHasActiveSubIdOnDds && (!internetContent.mIsWifiEnabled
+ || !internetContent.mIsCarrierNetworkActive)) {
mMobileNetworkLayout.setVisibility(View.GONE);
if (mSecondaryMobileNetworkLayout != null) {
mSecondaryMobileNetworkLayout.setVisibility(View.GONE);
}
} else {
mMobileNetworkLayout.setVisibility(View.VISIBLE);
- mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled());
+ mMobileDataToggle.setChecked(internetContent.mIsMobileDataEnabled);
mMobileTitleText.setText(getMobileNetworkTitle(mDefaultDataSubId));
String summary = getMobileNetworkSummary(mDefaultDataSubId);
if (!TextUtils.isEmpty(summary)) {
@@ -508,7 +549,7 @@ public class InternetDialogDelegate implements
if (stub != null) {
stub.inflate();
}
- mSecondaryMobileNetworkLayout = dialog.findViewById(
+ mSecondaryMobileNetworkLayout = mDialogView.findViewById(
R.id.secondary_mobile_network_layout);
mSecondaryMobileNetworkLayout.setOnClickListener(
this::onClickConnectedSecondarySub);
@@ -567,7 +608,7 @@ public class InternetDialogDelegate implements
}
// Set airplane mode to the summary for carrier network
- if (mInternetDialogController.isAirplaneModeEnabled()) {
+ if (internetContent.mIsAirplaneModeEnabled) {
mAirplaneModeSummaryText.setVisibility(View.VISIBLE);
mAirplaneModeSummaryText.setText(
dialog.getContext().getText(R.string.airplane_mode));
@@ -579,17 +620,18 @@ public class InternetDialogDelegate implements
}
@MainThread
- private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
- if (mWiFiToggle.isChecked() != isWifiEnabled) {
- mWiFiToggle.setChecked(isWifiEnabled);
+ private void updateWifiToggle(InternetContent internetContent) {
+ if (mWiFiToggle.isChecked() != internetContent.mIsWifiEnabled) {
+ mWiFiToggle.setChecked(internetContent.mIsWifiEnabled);
}
- if (isDeviceLocked) {
+ if (internetContent.mIsDeviceLocked) {
mWifiToggleTitleText.setTextAppearance((mConnectedWifiEntry != null)
? R.style.TextAppearance_InternetDialog_Active
: R.style.TextAppearance_InternetDialog);
}
mTurnWifiOnLayout.setBackground(
- (isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null);
+ (internetContent.mIsDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn
+ : null);
if (!mCanChangeWifiState && mWiFiToggle.isEnabled()) {
mWiFiToggle.setEnabled(false);
@@ -601,8 +643,9 @@ public class InternetDialogDelegate implements
}
@MainThread
- private void updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked) {
- if (mDialog == null || !isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) {
+ private void updateConnectedWifi(InternetContent internetContent) {
+ if (mDialog == null || !internetContent.mIsWifiEnabled || mConnectedWifiEntry == null
+ || internetContent.mIsDeviceLocked) {
mConnectedWifListLayout.setVisibility(View.GONE);
mShareWifiButton.setVisibility(View.GONE);
return;
@@ -627,8 +670,8 @@ public class InternetDialogDelegate implements
}
@MainThread
- private void updateWifiListAndSeeAll(boolean isWifiEnabled, boolean isDeviceLocked) {
- if (!isWifiEnabled || isDeviceLocked) {
+ private void updateWifiListAndSeeAll(InternetContent internetContent) {
+ if (!internetContent.mIsWifiEnabled || internetContent.mIsDeviceLocked) {
mWifiRecyclerView.setVisibility(View.GONE);
mSeeAllLayout.setVisibility(View.GONE);
return;
@@ -670,9 +713,10 @@ public class InternetDialogDelegate implements
}
@MainThread
- private void updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled,
- boolean isDeviceLocked) {
- if (mDialog == null || isWifiEnabled || !isWifiScanEnabled || isDeviceLocked) {
+ private void updateWifiScanNotify(InternetContent internetContent) {
+ if (mDialog == null || internetContent.mIsWifiEnabled
+ || !internetContent.mIsWifiScanEnabled
+ || internetContent.mIsDeviceLocked) {
mWifiScanNotifyLayout.setVisibility(View.GONE);
return;
}
@@ -805,62 +849,62 @@ public class InternetDialogDelegate implements
@Override
public void onRefreshCarrierInfo() {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
public void onSimStateChanged() {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
@WorkerThread
public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
@WorkerThread
public void onLost(Network network) {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
public void onSubscriptionsChanged(int defaultDataSubId) {
mDefaultDataSubId = defaultDataSubId;
- mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
public void onUserMobileDataStateChanged(boolean enabled) {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
public void onServiceStateChanged(ServiceState serviceState) {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
@WorkerThread
public void onDataConnectionStateChanged(int state, int networkType) {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
public void onCarrierNetworkChange(boolean active) {
- mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
+
+ updateDialog(true /* shouldUpdateMobileNetwork */);
}
@Override
@@ -912,4 +956,20 @@ public class InternetDialogDelegate implements
return mId;
}
}
+
+ @VisibleForTesting
+ static class InternetContent {
+ CharSequence mInternetDialogTitleString = "";
+ CharSequence mInternetDialogSubTitle = "";
+ boolean mIsAirplaneModeEnabled = false;
+ boolean mHasEthernet = false;
+ boolean mShouldUpdateMobileNetwork = false;
+ boolean mActiveNetworkIsCellular = false;
+ boolean mIsCarrierNetworkActive = false;
+ boolean mIsWifiEnabled = false;
+ boolean mHasActiveSubIdOnDds = false;
+ boolean mIsMobileDataEnabled = false;
+ boolean mIsDeviceLocked = false;
+ boolean mIsWifiScanEnabled = false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
index 103b4a5ff7ef..61a06dbff18f 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
@@ -20,6 +20,7 @@ import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.lifecycle.Activatable
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.Flow
/**
@@ -35,7 +36,9 @@ interface Scene : Activatable {
/** Uniquely-identifying key for this scene. The key must be unique within its container. */
val key: SceneKey
- override suspend fun activate() = Unit
+ override suspend fun activate(): Nothing {
+ awaitCancellation()
+ }
/**
* The mapping between [UserAction] and destination [UserActionResult]s.
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModel.kt
index c2fd65b6d6cb..b5de1b6209bb 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModel.kt
@@ -41,7 +41,7 @@ abstract class SceneActionsViewModel : SysUiViewModel() {
*/
val actions: StateFlow<Map<UserAction, UserActionResult>> = _actions.asStateFlow()
- final override suspend fun onActivated() {
+ final override suspend fun onActivated(): Nothing {
try {
hydrateActions { state -> _actions.value = state }
awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 2d02f5a5b79d..0b4fb32eaf5b 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -57,7 +57,7 @@ constructor(
/** Whether the container is visible. */
val isVisible: StateFlow<Boolean> = sceneInteractor.isVisible
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
try {
// Sends a MotionEventHandler to the owner of the view-model so they can report
// MotionEvents into the view-model.
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
index 566bc166ed40..00c023540da3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
@@ -24,6 +24,7 @@ import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -44,10 +45,11 @@ constructor(private val sceneInteractor: SceneInteractor, shadeInteractor: Shade
/** Dictates the alignment of the overlay shade panel on the screen. */
val panelAlignment = shadeInteractor.shadeAlignment
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
sceneInteractor.resolveSceneFamily(SceneFamilies.Home).collectLatest { sceneKey ->
_backgroundScene.value = sceneKey
}
+ awaitCancellation()
}
/** Notifies that the user has clicked the semi-transparent background scrim. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
index 03fdfa9aaa6c..f0e9d41c0fe7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -41,6 +41,7 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import java.util.Date
import java.util.Locale
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -104,7 +105,7 @@ constructor(
private val _longerDateText: MutableStateFlow<String> = MutableStateFlow("")
val longerDateText: StateFlow<String> = _longerDateText.asStateFlow()
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
coroutineScope {
launch {
broadcastDispatcher
@@ -137,6 +138,8 @@ constructor(
launch {
shadeInteractor.isQsEnabled.map { !it }.collectLatest { _isDisabled.value = it }
}
+
+ awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt
index a4d34163ba68..fe3bcb5c326c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt
@@ -35,6 +35,7 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import java.util.concurrent.atomic.AtomicBoolean
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -73,10 +74,12 @@ constructor(
private val footerActionsControllerInitialized = AtomicBoolean(false)
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
deviceEntryInteractor.isDeviceEntered.collectLatest { isDeviceEntered ->
_isEmptySpaceClickable.value = !isDeviceEntered
}
+
+ awaitCancellation()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 14e14f4bd47f..1481b734ff61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -20,7 +20,6 @@ import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
-import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.domain.interactor.NaturalScrollingSettingObserver
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
@@ -45,7 +44,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.SplitShadeStateController
-import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.animation.Interpolators
import dagger.Lazy
import java.io.PrintWriter
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index bfb624a9287b..a20517981f77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -59,7 +59,7 @@ constructor(
ActivatableFlowDumper by ActivatableFlowDumperImpl(dumpManager, "NotificationScrollViewModel"),
SysUiViewModel() {
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
activateFlowDumper()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
index 53fab621173a..2fbb23e30003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.lifecycle.SysUiViewModel
@@ -25,6 +26,8 @@ import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNoti
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding
+import com.android.systemui.util.kotlin.ActivatableFlowDumper
+import com.android.systemui.util.kotlin.ActivatableFlowDumperImpl
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.Flow
@@ -40,7 +43,13 @@ constructor(
shadeInteractor: ShadeInteractor,
private val headsUpNotificationInteractor: HeadsUpNotificationInteractor,
featureFlags: FeatureFlagsClassic,
-) : SysUiViewModel() {
+ dumpManager: DumpManager,
+) :
+ SysUiViewModel(),
+ ActivatableFlowDumper by ActivatableFlowDumperImpl(
+ dumpManager = dumpManager,
+ tag = "NotificationsPlaceholderViewModel",
+ ) {
/** DEBUG: whether the placeholder should be made slightly visible for positional debugging. */
val isVisualDebuggingEnabled: Boolean = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES)
@@ -48,6 +57,10 @@ constructor(
/** DEBUG: whether the debug logging should be output. */
val isDebugLoggingEnabled: Boolean = SceneContainerFlag.isEnabled
+ override suspend fun onActivated(): Nothing {
+ activateFlowDumper()
+ }
+
/** Notifies that the bounds of the notification scrim have changed. */
fun onScrimBoundsChanged(bounds: ShadeScrimBounds?) {
interactor.setShadeScrimBounds(bounds)
@@ -68,37 +81,35 @@ constructor(
headsUpNotificationInteractor.isHeadsUpOrAnimatingAway
/** Corner rounding of the stack */
- // TODO(b/359244921): add .dumpWhileCollecting("shadeScrimRounding")
- val shadeScrimRounding: Flow<ShadeScrimRounding> = interactor.shadeScrimRounding
+ val shadeScrimRounding: Flow<ShadeScrimRounding> =
+ interactor.shadeScrimRounding.dumpWhileCollecting("shadeScrimRounding")
/**
* The amount [0-1] that the shade or quick settings has been opened. At 0, the shade is closed;
* at 1, either the shade or quick settings is open.
*/
- // TODO(b/359244921): add .dumpValue("expandFraction")
- val expandFraction: Flow<Float> = shadeInteractor.anyExpansion
+ val expandFraction: Flow<Float> = shadeInteractor.anyExpansion.dumpValue("expandFraction")
/**
* The amount [0-1] that quick settings has been opened. At 0, the shade may be open or closed;
* at 1, the quick settings are open.
*/
- // TODO(b/359244921): add .dumpValue("shadeToQsFraction")
- val shadeToQsFraction: Flow<Float> = shadeInteractor.qsExpansion
+ val shadeToQsFraction: Flow<Float> = shadeInteractor.qsExpansion.dumpValue("shadeToQsFraction")
/**
* The amount in px that the notification stack should scroll due to internal expansion. This
* should only happen when a notification expansion hits the bottom of the screen, so it is
* necessary to scroll up to keep expanding the notification.
*/
- // TODO(b/359244921): add .dumpWhileCollecting("syntheticScroll")
- val syntheticScroll: Flow<Float> = interactor.syntheticScroll
+ val syntheticScroll: Flow<Float> =
+ interactor.syntheticScroll.dumpWhileCollecting("syntheticScroll")
/**
* Whether the current touch gesture is overscroll. If true, it means the NSSL has already
* consumed part of the gesture.
*/
- // TODO(b/359244921): add .dumpWhileCollecting("isCurrentGestureOverScroll")
- val isCurrentGestureOverscroll: Flow<Boolean> = interactor.isCurrentGestureOverscroll
+ val isCurrentGestureOverscroll: Flow<Boolean> =
+ interactor.isCurrentGestureOverscroll.dumpWhileCollecting("isCurrentGestureOverScroll")
/** Sets whether the notification stack is scrolled to the top. */
fun setScrolledToTop(scrolledToTop: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
index 1a4708170a05..460423378dff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
@@ -333,10 +333,6 @@ constructor(
}
if (intent.isActivity) {
assistManagerLazy.get().hideAssist()
- // This activity could have started while the device is dreaming, in which case
- // the dream would occlude the activity. In order to show the newly started
- // activity, we wake from the dream.
- keyguardUpdateMonitor.awakenFromDream()
}
intentSentUiThreadCallback?.let { postOnUiThread(runnable = it) }
}
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 dda02db3f2ef..e7d5cd19a360 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -32,8 +32,6 @@ import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-import androidx.annotation.NonNull;
-
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.Dependency;
import com.android.systemui.Flags;
@@ -49,6 +47,7 @@ import java.util.Objects;
public class PhoneStatusBarView extends FrameLayout {
private static final String TAG = "PhoneStatusBarView";
+ private final StatusBarContentInsetsProvider mContentInsetsProvider;
private final StatusBarWindowController mStatusBarWindowController;
private int mRotationOrientation = -1;
@@ -61,10 +60,6 @@ public class PhoneStatusBarView extends FrameLayout {
private int mStatusBarHeight;
@Nullable
private Gefingerpoken mTouchEventHandler;
- @Nullable
- private HasCornerCutoutFetcher mHasCornerCutoutFetcher;
- @Nullable
- private InsetsFetcher mInsetsFetcher;
private int mDensity;
private float mFontScale;
@@ -75,6 +70,7 @@ public class PhoneStatusBarView extends FrameLayout {
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mContentInsetsProvider = Dependency.get(StatusBarContentInsetsProvider.class);
mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
}
@@ -82,14 +78,6 @@ public class PhoneStatusBarView extends FrameLayout {
mTouchEventHandler = handler;
}
- void setHasCornerCutoutFetcher(@NonNull HasCornerCutoutFetcher cornerCutoutFetcher) {
- mHasCornerCutoutFetcher = cornerCutoutFetcher;
- }
-
- void setInsetsFetcher(@NonNull InsetsFetcher insetsFetcher) {
- mInsetsFetcher = insetsFetcher;
- }
-
void init(StatusBarUserChipViewModel viewModel) {
StatusBarUserSwitcherContainer container = findViewById(R.id.user_switcher_container);
StatusBarUserChipViewBinder.bind(container, viewModel);
@@ -282,14 +270,7 @@ public class PhoneStatusBarView extends FrameLayout {
return;
}
- boolean hasCornerCutout;
- if (mHasCornerCutoutFetcher != null) {
- hasCornerCutout = mHasCornerCutoutFetcher.fetchHasCornerCutout();
- } else {
- Log.e(TAG, "mHasCornerCutoutFetcher unexpectedly null");
- hasCornerCutout = true;
- }
-
+ boolean hasCornerCutout = mContentInsetsProvider.currentRotationHasCornerCutout();
if (mDisplayCutout == null || mDisplayCutout.isEmpty() || hasCornerCutout) {
mCutoutSpace.setVisibility(View.GONE);
return;
@@ -307,12 +288,8 @@ public class PhoneStatusBarView extends FrameLayout {
}
private void updateSafeInsets() {
- if (mInsetsFetcher == null) {
- Log.e(TAG, "mInsetsFetcher unexpectedly null");
- return;
- }
-
- Insets insets = mInsetsFetcher.fetchInsets();
+ Insets insets = mContentInsetsProvider
+ .getStatusBarContentInsetsForCurrentRotation();
setPadding(
insets.left,
insets.top,
@@ -326,12 +303,4 @@ public class PhoneStatusBarView extends FrameLayout {
}
mStatusBarWindowController.refreshStatusBarHeight();
}
-
- interface HasCornerCutoutFetcher {
- boolean fetchHasCornerCutout();
- }
-
- interface InsetsFetcher {
- Insets fetchInsets();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 456265b27004..468a3c3a49a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -73,7 +73,6 @@ private constructor(
private val configurationController: ConfigurationController,
private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory,
private val darkIconDispatcher: DarkIconDispatcher,
- private val statusBarContentInsetsProvider: StatusBarContentInsetsProvider,
) : ViewController<PhoneStatusBarView>(view) {
private lateinit var battery: BatteryMeterView
@@ -156,14 +155,7 @@ private constructor(
}
init {
- // These should likely be done in `onInit`, not `init`.
mView.setTouchEventHandler(PhoneStatusBarViewTouchHandler())
- mView.setHasCornerCutoutFetcher {
- statusBarContentInsetsProvider.currentRotationHasCornerCutout()
- }
- mView.setInsetsFetcher {
- statusBarContentInsetsProvider.getStatusBarContentInsetsForCurrentRotation()
- }
mView.init(userChipViewModel)
}
@@ -318,7 +310,6 @@ private constructor(
private val configurationController: ConfigurationController,
private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory,
private val darkIconDispatcher: DarkIconDispatcher,
- private val statusBarContentInsetsProvider: StatusBarContentInsetsProvider,
) {
fun create(view: PhoneStatusBarView): PhoneStatusBarViewController {
val statusBarMoveFromCenterAnimationController =
@@ -344,7 +335,6 @@ private constructor(
configurationController,
statusOverlayHoverListenerFactory,
darkIconDispatcher,
- statusBarContentInsetsProvider,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
index 66ac17eee545..b9cba9903466 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
@@ -31,7 +31,7 @@ import androidx.annotation.Nullable;
import com.android.settingslib.Utils;
import com.android.systemui.res.R;
-import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.shared.animation.Interpolators;
/**
* View to show a toast-like popup on the notification shade and quick settings.
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/FlowDumper.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/FlowDumper.kt
index ade6c3df2e0f..ef9f8ff9de0d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/FlowDumper.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/FlowDumper.kt
@@ -170,7 +170,7 @@ abstract class FlowDumperImpl(
* [Activatable.activate()][com.android.systemui.lifecycle.Activatable.activate].
*/
interface ActivatableFlowDumper : FlowDumper {
- suspend fun activateFlowDumper()
+ suspend fun activateFlowDumper(): Nothing
}
/**
@@ -190,7 +190,7 @@ class ActivatableFlowDumperImpl(
private val registration =
object : SafeActivatable() {
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
try {
dumpManager.registerCriticalDumpable(
dumpManagerName,
@@ -205,7 +205,7 @@ class ActivatableFlowDumperImpl(
private val dumpManagerName = "[$idString] $tag"
- override suspend fun activateFlowDumper() {
+ override suspend fun activateFlowDumper(): Nothing {
registration.activate()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 2e29bbd33f92..b1c6455a6e57 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -21,6 +21,7 @@ import static android.app.WallpaperManager.FLAG_SYSTEM;
import static android.app.WallpaperManager.SetWallpaperFlags;
import static com.android.systemui.Flags.fixImageWallpaperCrashSurfaceAlreadyReleased;
+import static com.android.window.flags.Flags.multiCrop;
import static com.android.window.flags.Flags.offloadColorExtraction;
import android.annotation.Nullable;
@@ -190,7 +191,10 @@ public class ImageWallpaper extends WallpaperService {
}
mWallpaperManager = getDisplayContext().getSystemService(WallpaperManager.class);
mSurfaceHolder = surfaceHolder;
- Rect dimensions = mWallpaperManager.peekBitmapDimensions(getSourceFlag(), true);
+ Rect dimensions = !multiCrop()
+ ? mWallpaperManager.peekBitmapDimensions(getSourceFlag(), true)
+ : mWallpaperManager.peekBitmapDimensionsAsUser(getSourceFlag(), true,
+ mUserTracker.getUserId());
int width = Math.max(MIN_SURFACE_WIDTH, dimensions.width());
int height = Math.max(MIN_SURFACE_HEIGHT, dimensions.height());
mSurfaceHolder.setFixedSize(width, height);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index 5ff3915c76f9..113a8c05ee66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -45,6 +45,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.util.settings.SecureSettings;
@@ -90,6 +91,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
private SecureSettings mSecureSettings;
@Mock
private Lazy<ViewCapture> mLazyViewCapture;
+ @Mock
+ private NavigationModeController mNavigationModeController;
@Before
public void setUp() throws Exception {
@@ -163,7 +166,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
mController.mFloatingMenu = new MenuViewLayerController(mContextWrapper, mWindowManager,
- mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings);
+ mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings,
+ mNavigationModeController);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserUnlocked();
@@ -190,7 +194,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
mController.mFloatingMenu = new MenuViewLayerController(mContextWrapper, mWindowManager,
- mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings);
+ mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings,
+ mNavigationModeController);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserSwitching(fakeUserId);
@@ -204,7 +209,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
mController.mFloatingMenu = new MenuViewLayerController(mContextWrapper, mWindowManager,
- mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings);
+ mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings,
+ mNavigationModeController);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserUnlocked();
mKeyguardCallback.onKeyguardVisibilityChanged(true);
@@ -340,7 +346,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
new AccessibilityFloatingMenuController(mContextWrapper, windowManager,
viewCaptureAwareWindowManager, displayManager, mAccessibilityManager,
mTargetsObserver, mModeObserver, mKeyguardUpdateMonitor, mSecureSettings,
- displayTracker);
+ displayTracker, mNavigationModeController);
controller.init();
return controller;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
index 19b27003ebd1..d7acaaf796f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
@@ -34,7 +34,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.utils.TestUtils;
import com.android.systemui.util.settings.SecureSettings;
import com.android.wm.shell.common.bubbles.DismissView;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import org.junit.Before;
import org.junit.Rule;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
index c5509ac44046..157cccc3d62f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
@@ -44,6 +44,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.utils.TestUtils;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.res.R;
import com.android.systemui.util.settings.SecureSettings;
@@ -94,7 +95,8 @@ public class MenuItemAccessibilityDelegateTest extends SysuiTestCase {
mMenuViewLayer = spy(new MenuViewLayer(
mContext, stubWindowManager, mAccessibilityManager,
stubMenuViewModel, stubMenuViewAppearance, mMenuView,
- mock(IAccessibilityFloatingMenu.class), mSecureSettings));
+ mock(IAccessibilityFloatingMenu.class), mSecureSettings,
+ mock(NavigationModeController.class)));
doNothing().when(mMenuViewLayer).gotoEditScreen();
doReturn(mDraggableBounds).when(mMenuView).getMenuDraggableBounds();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
index 07ce7b9352c1..fcdeff9ab683 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
@@ -21,6 +21,7 @@ import static android.view.WindowInsets.Type.systemBars;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -41,6 +42,7 @@ import androidx.test.filters.SmallTest;
import com.android.app.viewcapture.ViewCapture;
import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.util.settings.SecureSettings;
import kotlin.Lazy;
@@ -90,7 +92,8 @@ public class MenuViewLayerControllerTest extends SysuiTestCase {
when(mWindowMetrics.getBounds()).thenReturn(new Rect(0, 0, 1080, 2340));
when(mWindowMetrics.getWindowInsets()).thenReturn(stubDisplayInsets());
mMenuViewLayerController = new MenuViewLayerController(mContext, mWindowManager,
- viewCaptureAwareWm, mAccessibilityManager, mSecureSettings);
+ viewCaptureAwareWm, mAccessibilityManager, mSecureSettings,
+ mock(NavigationModeController.class));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index 12140b58936b..c451c32c4587 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -81,9 +81,10 @@ import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestableContext;
import com.android.systemui.accessibility.utils.TestUtils;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.res.R;
import com.android.systemui.util.settings.SecureSettings;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
import org.junit.After;
import org.junit.Before;
@@ -169,7 +170,7 @@ public class MenuViewLayerTest extends SysuiTestCase {
mMenuViewLayer = spy(new MenuViewLayer(mSpyContext, mStubWindowManager,
mStubAccessibilityManager, mMenuViewModel, menuViewAppearance, mMenuView,
- mFloatingMenu, mSecureSettings));
+ mFloatingMenu, mSecureSettings, mock(NavigationModeController.class)));
mMenuAnimationController = mMenuView.getMenuAnimationController();
doNothing().when(mSpyContext).startActivity(any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index e4f0910f99fd..f1782e8b0569 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -31,11 +31,11 @@ import android.service.controls.ControlsProviderService
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.applications.ServiceListing
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.ActivityTaskManagerProxy
import com.android.systemui.util.concurrency.FakeExecutor
@@ -45,6 +45,8 @@ import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executor
import org.junit.After
import org.junit.Assert.assertEquals
@@ -56,39 +58,33 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatcher
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
@SmallTest
@RunWith(AndroidJUnit4::class)
class ControlsListingControllerImplTest : SysuiTestCase() {
companion object {
- private const val FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE.toLong() or
+ private const val FLAGS =
+ PackageManager.MATCH_DIRECT_BOOT_AWARE.toLong() or
PackageManager.MATCH_DIRECT_BOOT_UNAWARE.toLong()
}
- @Mock
- private lateinit var mockSL: ServiceListing
- @Mock
- private lateinit var mockCallback: ControlsListingController.ControlsListingCallback
- @Mock
- private lateinit var mockCallbackOther: ControlsListingController.ControlsListingCallback
- @Mock(stubOnly = true)
- private lateinit var userTracker: UserTracker
- @Mock(stubOnly = true)
- private lateinit var dumpManager: DumpManager
- @Mock
- private lateinit var packageManager: PackageManager
- @Mock
- private lateinit var featureFlags: FeatureFlags
- @Mock
- private lateinit var activityTaskManagerProxy: ActivityTaskManagerProxy
+ @Mock private lateinit var mockSL: ServiceListing
+ @Mock private lateinit var mockCallback: ControlsListingController.ControlsListingCallback
+ @Mock private lateinit var mockCallbackOther: ControlsListingController.ControlsListingCallback
+ @Mock(stubOnly = true) private lateinit var userTracker: UserTracker
+ @Mock(stubOnly = true) private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var featureFlags: FeatureFlags
+ @Mock private lateinit var activityTaskManagerProxy: ActivityTaskManagerProxy
private var componentName = ComponentName("pkg", "class1")
private var activityName = ComponentName("pkg", "activity")
@@ -98,7 +94,7 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
private lateinit var controller: ControlsListingControllerImpl
private var serviceListingCallbackCaptor =
- ArgumentCaptor.forClass(ServiceListing.Callback::class.java)
+ ArgumentCaptor.forClass(ServiceListing.Callback::class.java)
private val user = mContext.userId
private val otherUser = user + 1
@@ -112,23 +108,24 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
`when`(userTracker.userContext).thenReturn(context)
// Return disabled by default
`when`(packageManager.getComponentEnabledSetting(any()))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED)
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED)
`when`(activityTaskManagerProxy.supportsMultiWindow(any())).thenReturn(true)
mContext.setMockPackageManager(packageManager)
- mContext.orCreateTestableResources
- .addOverride(
- R.array.config_controlsPreferredPackages,
- arrayOf(componentName.packageName)
- )
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_controlsPreferredPackages,
+ arrayOf(componentName.packageName)
+ )
- val wrapper = object : ContextWrapper(mContext) {
- override fun createContextAsUser(user: UserHandle, flags: Int): Context {
- return baseContext
+ val wrapper =
+ object : ContextWrapper(mContext) {
+ override fun createContextAsUser(user: UserHandle, flags: Int): Context {
+ return baseContext
+ }
}
- }
- controller = ControlsListingControllerImpl(
+ controller =
+ ControlsListingControllerImpl(
wrapper,
executor,
{ mockSL },
@@ -136,7 +133,7 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
activityTaskManagerProxy,
dumpManager,
featureFlags
- )
+ )
verify(mockSL).addCallback(capture(serviceListingCallbackCaptor))
}
@@ -165,13 +162,13 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
callback?.onServicesReloaded(listOf(ServiceInfo(componentName)))
}
ControlsListingControllerImpl(
- mContext,
- exec,
- { mockServiceListing },
- userTracker,
- activityTaskManagerProxy,
- dumpManager,
- featureFlags
+ mContext,
+ exec,
+ { mockServiceListing },
+ userTracker,
+ activityTaskManagerProxy,
+ dumpManager,
+ featureFlags
)
}
@@ -201,8 +198,7 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Suppress("unchecked_cast")
val captor: ArgumentCaptor<List<ControlsServiceInfo>> =
- ArgumentCaptor.forClass(List::class.java)
- as ArgumentCaptor<List<ControlsServiceInfo>>
+ ArgumentCaptor.forClass(List::class.java) as ArgumentCaptor<List<ControlsServiceInfo>>
executor.runAllReady()
reset(mockCallback)
@@ -242,8 +238,7 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Suppress("unchecked_cast")
val captor: ArgumentCaptor<List<ControlsServiceInfo>> =
- ArgumentCaptor.forClass(List::class.java)
- as ArgumentCaptor<List<ControlsServiceInfo>>
+ ArgumentCaptor.forClass(List::class.java) as ArgumentCaptor<List<ControlsServiceInfo>>
executor.runAllReady()
reset(mockCallback)
@@ -285,10 +280,7 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Test
fun testNoActivity_nullPanel() {
- val serviceInfo = ServiceInfo(
- componentName,
- activityName
- )
+ val serviceInfo = ServiceInfo(componentName, activityName)
val list = listOf(serviceInfo)
serviceListingCallbackCaptor.value.onServicesReloaded(list)
@@ -300,10 +292,7 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Test
fun testActivityWithoutPermission_nullPanel() {
- val serviceInfo = ServiceInfo(
- componentName,
- activityName
- )
+ val serviceInfo = ServiceInfo(componentName, activityName)
setUpQueryResult(listOf(ActivityInfo(activityName)))
@@ -317,14 +306,11 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Test
fun testActivityPermissionNotExported_nullPanel() {
- val serviceInfo = ServiceInfo(
- componentName,
- activityName
- )
+ val serviceInfo = ServiceInfo(componentName, activityName)
- setUpQueryResult(listOf(
- ActivityInfo(activityName, permission = Manifest.permission.BIND_CONTROLS)
- ))
+ setUpQueryResult(
+ listOf(ActivityInfo(activityName, permission = Manifest.permission.BIND_CONTROLS))
+ )
val list = listOf(serviceInfo)
serviceListingCallbackCaptor.value.onServicesReloaded(list)
@@ -336,18 +322,17 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Test
fun testActivityDisabled_nullPanel() {
- val serviceInfo = ServiceInfo(
- componentName,
- activityName
- )
+ val serviceInfo = ServiceInfo(componentName, activityName)
- setUpQueryResult(listOf(
+ setUpQueryResult(
+ listOf(
ActivityInfo(
- activityName,
- exported = true,
- permission = Manifest.permission.BIND_CONTROLS
+ activityName,
+ exported = true,
+ permission = Manifest.permission.BIND_CONTROLS
)
- ))
+ )
+ )
val list = listOf(serviceInfo)
serviceListingCallbackCaptor.value.onServicesReloaded(list)
@@ -359,21 +344,20 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Test
fun testActivityEnabled_correctPanel() {
- val serviceInfo = ServiceInfo(
- componentName,
- activityName
- )
+ val serviceInfo = ServiceInfo(componentName, activityName)
`when`(packageManager.getComponentEnabledSetting(eq(activityName)))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
- setUpQueryResult(listOf(
+ setUpQueryResult(
+ listOf(
ActivityInfo(
- activityName,
- exported = true,
- permission = Manifest.permission.BIND_CONTROLS
+ activityName,
+ exported = true,
+ permission = Manifest.permission.BIND_CONTROLS
)
- ))
+ )
+ )
val list = listOf(serviceInfo)
serviceListingCallbackCaptor.value.onServicesReloaded(list)
@@ -385,22 +369,21 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Test
fun testActivityDefaultEnabled_correctPanel() {
- val serviceInfo = ServiceInfo(
- componentName,
- activityName
- )
+ val serviceInfo = ServiceInfo(componentName, activityName)
`when`(packageManager.getComponentEnabledSetting(eq(activityName)))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
- setUpQueryResult(listOf(
+ setUpQueryResult(
+ listOf(
ActivityInfo(
- activityName,
- enabled = true,
- exported = true,
- permission = Manifest.permission.BIND_CONTROLS
+ activityName,
+ enabled = true,
+ exported = true,
+ permission = Manifest.permission.BIND_CONTROLS
)
- ))
+ )
+ )
val list = listOf(serviceInfo)
serviceListingCallbackCaptor.value.onServicesReloaded(list)
@@ -412,22 +395,21 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Test
fun testActivityDefaultDisabled_nullPanel() {
- val serviceInfo = ServiceInfo(
- componentName,
- activityName
- )
+ val serviceInfo = ServiceInfo(componentName, activityName)
`when`(packageManager.getComponentEnabledSetting(eq(activityName)))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
- setUpQueryResult(listOf(
+ setUpQueryResult(
+ listOf(
ActivityInfo(
- activityName,
- enabled = false,
- exported = true,
- permission = Manifest.permission.BIND_CONTROLS
+ activityName,
+ enabled = false,
+ exported = true,
+ permission = Manifest.permission.BIND_CONTROLS
)
- ))
+ )
+ )
val list = listOf(serviceInfo)
serviceListingCallbackCaptor.value.onServicesReloaded(list)
@@ -439,22 +421,21 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Test
fun testActivityDifferentPackage_nullPanel() {
- val serviceInfo = ServiceInfo(
- componentName,
- ComponentName("other_package", "cls")
- )
+ val serviceInfo = ServiceInfo(componentName, ComponentName("other_package", "cls"))
`when`(packageManager.getComponentEnabledSetting(eq(activityName)))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
- setUpQueryResult(listOf(
+ setUpQueryResult(
+ listOf(
ActivityInfo(
- activityName,
- enabled = true,
- exported = true,
- permission = Manifest.permission.BIND_CONTROLS
+ activityName,
+ enabled = true,
+ exported = true,
+ permission = Manifest.permission.BIND_CONTROLS
)
- ))
+ )
+ )
val list = listOf(serviceInfo)
serviceListingCallbackCaptor.value.onServicesReloaded(list)
@@ -466,24 +447,25 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Test
fun testPackageNotPreferred_correctPanel() {
- mContext.orCreateTestableResources
- .addOverride(R.array.config_controlsPreferredPackages, arrayOf<String>())
-
- val serviceInfo = ServiceInfo(
- componentName,
- activityName
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_controlsPreferredPackages,
+ arrayOf<String>()
)
+ val serviceInfo = ServiceInfo(componentName, activityName)
+
`when`(packageManager.getComponentEnabledSetting(eq(activityName)))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
- setUpQueryResult(listOf(
+ setUpQueryResult(
+ listOf(
ActivityInfo(
- activityName,
- exported = true,
- permission = Manifest.permission.BIND_CONTROLS
+ activityName,
+ exported = true,
+ permission = Manifest.permission.BIND_CONTROLS
)
- ))
+ )
+ )
val list = listOf(serviceInfo)
serviceListingCallbackCaptor.value.onServicesReloaded(list)
@@ -512,16 +494,19 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
`when`(userTracker.userHandle).thenReturn(UserHandle.of(user))
controller.forceReload()
- verify(packageManager).queryIntentServicesAsUser(
+ verify(packageManager)
+ .queryIntentServicesAsUser(
argThat(IntentMatcherAction(ControlsProviderService.SERVICE_CONTROLS)),
- argThat(FlagsMatcher(
+ argThat(
+ FlagsMatcher(
PackageManager.GET_META_DATA.toLong() or
- PackageManager.GET_SERVICES.toLong() or
- PackageManager.MATCH_DIRECT_BOOT_AWARE.toLong() or
- PackageManager.MATCH_DIRECT_BOOT_UNAWARE.toLong()
- )),
+ PackageManager.GET_SERVICES.toLong() or
+ PackageManager.MATCH_DIRECT_BOOT_AWARE.toLong() or
+ PackageManager.MATCH_DIRECT_BOOT_UNAWARE.toLong()
+ )
+ ),
eq(UserHandle.of(user))
- )
+ )
}
@Test
@@ -529,16 +514,21 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
val resolveInfo = ResolveInfo()
resolveInfo.serviceInfo = ServiceInfo(componentName)
- `when`(packageManager.queryIntentServicesAsUser(
- argThat(IntentMatcherAction(ControlsProviderService.SERVICE_CONTROLS)),
- argThat(FlagsMatcher(
- PackageManager.GET_META_DATA.toLong() or
+ `when`(
+ packageManager.queryIntentServicesAsUser(
+ argThat(IntentMatcherAction(ControlsProviderService.SERVICE_CONTROLS)),
+ argThat(
+ FlagsMatcher(
+ PackageManager.GET_META_DATA.toLong() or
PackageManager.GET_SERVICES.toLong() or
PackageManager.MATCH_DIRECT_BOOT_AWARE.toLong() or
PackageManager.MATCH_DIRECT_BOOT_UNAWARE.toLong()
- )),
- any<UserHandle>()
- )).thenReturn(listOf(resolveInfo))
+ )
+ ),
+ any<UserHandle>()
+ )
+ )
+ .thenReturn(listOf(resolveInfo))
controller.forceReload()
@@ -554,17 +544,19 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
@Suppress("unchecked_cast")
val captor: ArgumentCaptor<List<ControlsServiceInfo>> =
- ArgumentCaptor.forClass(List::class.java)
- as ArgumentCaptor<List<ControlsServiceInfo>>
+ ArgumentCaptor.forClass(List::class.java) as ArgumentCaptor<List<ControlsServiceInfo>>
val resolveInfo = ResolveInfo()
resolveInfo.serviceInfo = ServiceInfo(componentName)
- `when`(packageManager.queryIntentServicesAsUser(
- any(),
- any<PackageManager.ResolveInfoFlags>(),
- any<UserHandle>()
- )).thenReturn(listOf(resolveInfo))
+ `when`(
+ packageManager.queryIntentServicesAsUser(
+ any(),
+ any<PackageManager.ResolveInfoFlags>(),
+ any<UserHandle>()
+ )
+ )
+ .thenReturn(listOf(resolveInfo))
reset(mockCallback)
controller.forceReload()
@@ -581,22 +573,21 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
fun testNoPanelIfMultiWindowNotSupported() {
`when`(activityTaskManagerProxy.supportsMultiWindow(any())).thenReturn(false)
- val serviceInfo = ServiceInfo(
- componentName,
- activityName
- )
+ val serviceInfo = ServiceInfo(componentName, activityName)
`when`(packageManager.getComponentEnabledSetting(eq(activityName)))
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
- setUpQueryResult(listOf(
- ActivityInfo(
- activityName,
- enabled = true,
- exported = true,
- permission = Manifest.permission.BIND_CONTROLS
+ setUpQueryResult(
+ listOf(
+ ActivityInfo(
+ activityName,
+ enabled = true,
+ exported = true,
+ permission = Manifest.permission.BIND_CONTROLS
+ )
)
- ))
+ )
val list = listOf(serviceInfo)
serviceListingCallbackCaptor.value.onServicesReloaded(list)
@@ -606,20 +597,77 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
assertNull(controller.getCurrentServices()[0].panelActivity)
}
+ @Test
+ fun dumpAndAddRemoveCallback_willNotThrowConcurrentModificationException() {
+ val repeat = 100
+ controller.addCallback(mockCallback) // 1 extra callback increases the duration of iteration
+
+ // the goal of these two barriers is to make the modify and iterate run concurrently
+ val startSignal = CountDownLatch(2)
+ val doneSignal = CountDownLatch(2)
+ val modifyRunnable = Runnable {
+ for (i in 1..repeat) {
+ controller.addCallback(mockCallbackOther)
+ executor.runAllReady()
+ controller.removeCallback(mockCallbackOther)
+ executor.runAllReady()
+ }
+ }
+ val printWriter = mock<PrintWriter>()
+ val arr = arrayOf<String>()
+ val iterateRunnable = Runnable {
+ for (i in 1..repeat) {
+ controller.dump(printWriter, arr)
+ }
+ }
+
+ val workerThread = Thread(Worker(startSignal, doneSignal, modifyRunnable))
+ workerThread.start()
+ val workerThreadOther = Thread(Worker(startSignal, doneSignal, iterateRunnable))
+ workerThreadOther.start()
+ doneSignal.await()
+ workerThread.interrupt()
+ workerThreadOther.interrupt()
+ }
+
+ class Worker : Runnable {
+ private val startSignal: CountDownLatch
+ private val doneSignal: CountDownLatch
+ private val runnable: Runnable
+
+ constructor(start: CountDownLatch, done: CountDownLatch, run: Runnable) {
+ startSignal = start
+ doneSignal = done
+ runnable = run
+ }
+
+ override fun run() {
+ try {
+ startSignal.countDown()
+ startSignal.await()
+ runnable.run()
+ doneSignal.countDown()
+ } catch (ex: InterruptedException) {
+ return
+ }
+ }
+ }
+
private fun ServiceInfo(
- componentName: ComponentName,
- panelActivityComponentName: ComponentName? = null
+ componentName: ComponentName,
+ panelActivityComponentName: ComponentName? = null
): ServiceInfo {
return ServiceInfo().apply {
packageName = componentName.packageName
name = componentName.className
panelActivityComponentName?.let {
- metaData = Bundle().apply {
- putString(
+ metaData =
+ Bundle().apply {
+ putString(
ControlsProviderService.META_DATA_PANEL_ACTIVITY,
it.flattenToShortString()
- )
- }
+ )
+ }
}
}
}
@@ -642,34 +690,29 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
private fun setUpQueryResult(infos: List<ActivityInfo>) {
`when`(
packageManager.queryIntentActivitiesAsUser(
- argThat(IntentMatcherComponent(activityName)),
- argThat(FlagsMatcher(FLAGS)),
- eq(UserHandle.of(user))
+ argThat(IntentMatcherComponent(activityName)),
+ argThat(FlagsMatcher(FLAGS)),
+ eq(UserHandle.of(user))
)
- ).thenReturn(infos.map {
- ResolveInfo().apply { activityInfo = it }
- })
+ )
+ .thenReturn(infos.map { ResolveInfo().apply { activityInfo = it } })
}
- private class IntentMatcherComponent(
- private val componentName: ComponentName
- ) : ArgumentMatcher<Intent> {
+ private class IntentMatcherComponent(private val componentName: ComponentName) :
+ ArgumentMatcher<Intent> {
override fun matches(argument: Intent?): Boolean {
return argument?.component == componentName
}
}
- private class IntentMatcherAction(
- private val action: String
- ) : ArgumentMatcher<Intent> {
+ private class IntentMatcherAction(private val action: String) : ArgumentMatcher<Intent> {
override fun matches(argument: Intent?): Boolean {
return argument?.action == action
}
}
- private class FlagsMatcher(
- private val flags: Long
- ) : ArgumentMatcher<PackageManager.ResolveInfoFlags> {
+ private class FlagsMatcher(private val flags: Long) :
+ ArgumentMatcher<PackageManager.ResolveInfoFlags> {
override fun matches(argument: PackageManager.ResolveInfoFlags?): Boolean {
return flags == argument?.value
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
index 7583399c784a..1d96c4d67c77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
@@ -68,20 +68,23 @@ class TutorialSchedulerRepositoryTest : SysuiTestCase() {
@Test
fun connectKeyboard() =
testScope.runTest {
- val now = Instant.now().toEpochMilli()
- underTest.updateConnectTime(KEYBOARD, now)
+ val now = Instant.now()
+ underTest.updateFirstConnectionTime(KEYBOARD, now)
assertThat(underTest.wasEverConnected(KEYBOARD)).isTrue()
- assertThat(underTest.connectTime(KEYBOARD)).isEqualTo(now)
+ assertThat(underTest.firstConnectionTime(KEYBOARD)!!.epochSecond)
+ .isEqualTo(now.epochSecond)
assertThat(underTest.wasEverConnected(TOUCHPAD)).isFalse()
}
@Test
fun launchKeyboard() =
testScope.runTest {
- underTest.updateLaunch(KEYBOARD)
+ val now = Instant.now()
+ underTest.updateLaunchTime(KEYBOARD, now)
assertThat(underTest.isLaunched(KEYBOARD)).isTrue()
+ assertThat(underTest.launchTime(KEYBOARD)!!.epochSecond).isEqualTo(now.epochSecond)
assertThat(underTest.isLaunched(TOUCHPAD)).isFalse()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
new file mode 100644
index 000000000000..0c716137f434
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2024 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.inputdevice.tutorial.ui.viewmodel
+
+import androidx.lifecycle.Lifecycle.Event
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.LifecycleRegistry
+import androidx.lifecycle.SavedStateHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.inputdevice.tutorial.domain.interactor.KeyboardTouchpadConnectionInteractor
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.ACTION_KEY
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.BACK_GESTURE
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.HOME_GESTURE
+import com.android.systemui.keyboard.data.repository.keyboardRepository
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.model.sysUiState
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
+import com.android.systemui.testKosmos
+import com.android.systemui.touchpad.data.repository.TouchpadRepository
+import com.android.systemui.touchpad.tutorial.touchpadGesturesInteractor
+import com.android.systemui.util.coroutines.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val sysUiState = kosmos.sysUiState
+ private val touchpadRepo = PrettyFakeTouchpadRepository()
+ private val keyboardRepo = kosmos.keyboardRepository
+ private var startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+ private val viewModel by lazy { createViewModel(startingPeripheral) }
+
+ // createUnsafe so its methods don't have to be called on Main thread
+ private val lifecycle = LifecycleRegistry.createUnsafe(mock(LifecycleOwner::class.java))
+
+ @get:Rule val mainDispatcherRule = MainDispatcherRule(kosmos.testDispatcher)
+
+ private fun createViewModel(
+ startingPeripheral: String = INTENT_TUTORIAL_TYPE_TOUCHPAD,
+ hasTouchpadTutorialScreens: Boolean = true,
+ ): KeyboardTouchpadTutorialViewModel {
+ val viewModel =
+ KeyboardTouchpadTutorialViewModel(
+ Optional.of(kosmos.touchpadGesturesInteractor),
+ KeyboardTouchpadConnectionInteractor(keyboardRepo, touchpadRepo),
+ hasTouchpadTutorialScreens,
+ SavedStateHandle(mapOf(INTENT_TUTORIAL_TYPE_KEY to startingPeripheral))
+ )
+ lifecycle.addObserver(viewModel)
+ return viewModel
+ }
+
+ @Test
+ fun screensOrder_whenTouchpadAndKeyboardConnected() =
+ testScope.runTest {
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+ peripheralsState(keyboardConnected = true, touchpadConnected = true)
+
+ goToNextScreen()
+ goToNextScreen()
+ // reached the last screen
+
+ assertThat(screens).containsExactly(BACK_GESTURE, HOME_GESTURE, ACTION_KEY).inOrder()
+ assertThat(closeActivity).isFalse()
+ }
+
+ @Test
+ fun screensOrder_whenKeyboardDisconnectsDuringTutorial() =
+ testScope.runTest {
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+ peripheralsState(keyboardConnected = true, touchpadConnected = true)
+
+ // back gesture screen
+ goToNextScreen()
+ // home gesture screen
+ peripheralsState(keyboardConnected = false, touchpadConnected = true)
+ goToNextScreen()
+ // no action key screen because keyboard disconnected
+
+ assertThat(screens).containsExactly(BACK_GESTURE, HOME_GESTURE).inOrder()
+ assertThat(closeActivity).isTrue()
+ }
+
+ @Test
+ fun screensOrderUntilFinish_whenTouchpadAndKeyboardConnected() =
+ testScope.runTest {
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+
+ peripheralsState(keyboardConnected = true, touchpadConnected = true)
+
+ goToNextScreen()
+ goToNextScreen()
+ // we're at the last screen so "next screen" should be actually closing activity
+ goToNextScreen()
+
+ assertThat(screens).containsExactly(BACK_GESTURE, HOME_GESTURE, ACTION_KEY).inOrder()
+ assertThat(closeActivity).isTrue()
+ }
+
+ @Test
+ fun screensOrder_whenGoingBackToPreviousScreens() =
+ testScope.runTest {
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+ peripheralsState(keyboardConnected = true, touchpadConnected = true)
+
+ // back gesture
+ goToNextScreen()
+ // home gesture
+ goToNextScreen()
+ // action key
+
+ goBack()
+ // home gesture
+ goBack()
+ // back gesture
+ goBack()
+ // finish activity
+
+ assertThat(screens)
+ .containsExactly(BACK_GESTURE, HOME_GESTURE, ACTION_KEY, HOME_GESTURE, BACK_GESTURE)
+ .inOrder()
+ assertThat(closeActivity).isTrue()
+ }
+
+ @Test
+ fun screensOrder_whenGoingBackAndOnlyKeyboardConnected() =
+ testScope.runTest {
+ startingPeripheral = INTENT_TUTORIAL_TYPE_KEYBOARD
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+ peripheralsState(keyboardConnected = true, touchpadConnected = false)
+
+ // action key screen
+ goBack()
+ // activity finished
+
+ assertThat(screens).containsExactly(ACTION_KEY).inOrder()
+ assertThat(closeActivity).isTrue()
+ }
+
+ @Test
+ fun screensOrder_whenTouchpadConnected() =
+ testScope.runTest {
+ startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+
+ peripheralsState(keyboardConnected = false, touchpadConnected = true)
+
+ goToNextScreen()
+ goToNextScreen()
+ goToNextScreen()
+
+ assertThat(screens).containsExactly(BACK_GESTURE, HOME_GESTURE).inOrder()
+ assertThat(closeActivity).isTrue()
+ }
+
+ @Test
+ fun screensOrder_whenKeyboardConnected() =
+ testScope.runTest {
+ startingPeripheral = INTENT_TUTORIAL_TYPE_KEYBOARD
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+
+ peripheralsState(keyboardConnected = true)
+
+ goToNextScreen()
+ goToNextScreen()
+
+ assertThat(screens).containsExactly(ACTION_KEY).inOrder()
+ assertThat(closeActivity).isTrue()
+ }
+
+ @Test
+ fun touchpadGesturesDisabled_onlyDuringTouchpadTutorial() =
+ testScope.runTest {
+ startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+ collectValues(viewModel.screen) // just to initialize viewModel
+ peripheralsState(keyboardConnected = true, touchpadConnected = true)
+
+ assertGesturesDisabled()
+ goToNextScreen()
+ goToNextScreen()
+ // end of touchpad tutorial, keyboard tutorial starts
+ assertGesturesNotDisabled()
+ }
+
+ @Test
+ fun activityFinishes_ifTouchpadModuleIsNotPresent() =
+ testScope.runTest {
+ val viewModel =
+ createViewModel(
+ startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD,
+ hasTouchpadTutorialScreens = false
+ )
+ val screens by collectValues(viewModel.screen)
+ val closeActivity by collectLastValue(viewModel.closeActivity)
+ peripheralsState(touchpadConnected = true)
+
+ assertThat(screens).isEmpty()
+ assertThat(closeActivity).isTrue()
+ }
+
+ @Test
+ fun touchpadGesturesDisabled_whenTutorialGoesToForeground() =
+ testScope.runTest {
+ startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+ collectValues(viewModel.screen) // just to initialize viewModel
+ peripheralsState(touchpadConnected = true)
+
+ lifecycle.handleLifecycleEvent(Event.ON_START)
+
+ assertGesturesDisabled()
+ }
+
+ @Test
+ fun touchpadGesturesNotDisabled_whenTutorialGoesToBackground() =
+ testScope.runTest {
+ startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+ collectValues(viewModel.screen)
+ peripheralsState(touchpadConnected = true)
+
+ lifecycle.handleLifecycleEvent(Event.ON_START)
+ lifecycle.handleLifecycleEvent(Event.ON_STOP)
+
+ assertGesturesNotDisabled()
+ }
+
+ @Test
+ fun keyboardShortcutsDisabled_onlyDuringKeyboardTutorial() =
+ testScope.runTest {
+ // TODO(b/358587037)
+ }
+
+ private fun TestScope.goToNextScreen() {
+ viewModel.onDoneButtonClicked()
+ runCurrent()
+ }
+
+ private fun TestScope.goBack() {
+ viewModel.onBack()
+ runCurrent()
+ }
+
+ private fun TestScope.peripheralsState(
+ keyboardConnected: Boolean = false,
+ touchpadConnected: Boolean = false
+ ) {
+ keyboardRepo.setIsAnyKeyboardConnected(keyboardConnected)
+ touchpadRepo.setIsAnyTouchpadConnected(touchpadConnected)
+ runCurrent()
+ }
+
+ private fun TestScope.assertGesturesNotDisabled() = assertFlagEnabled(enabled = false)
+
+ private fun TestScope.assertGesturesDisabled() = assertFlagEnabled(enabled = true)
+
+ private fun TestScope.assertFlagEnabled(enabled: Boolean) {
+ // sysui state is changed on background scope so let's make sure it's executed
+ runCurrent()
+ assertThat(sysUiState.isFlagEnabled(SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED))
+ .isEqualTo(enabled)
+ }
+
+ // replace below when we have better fake
+ internal class PrettyFakeTouchpadRepository : TouchpadRepository {
+
+ private val _isAnyTouchpadConnected = MutableStateFlow(false)
+ override val isAnyTouchpadConnected: Flow<Boolean> = _isAnyTouchpadConnected
+
+ fun setIsAnyTouchpadConnected(connected: Boolean) {
+ _isAnyTouchpadConnected.value = connected
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
index 721162099169..f531a3fdd8f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
@@ -15,8 +15,8 @@ import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
-import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50
import com.android.wm.shell.recents.RecentTasks
+import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50
import com.android.wm.shell.util.GroupedRecentTaskInfo
import com.android.wm.shell.util.SplitBounds
import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java
index ff8c4481adea..643debfbc810 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java
@@ -6,20 +6,20 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.testing.TestableLooper;
+import android.testing.UiThreadTest;
import android.view.View;
+import android.view.Window;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.TextView;
@@ -44,20 +44,18 @@ import kotlinx.coroutines.CoroutineScope;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import java.util.List;
-@Ignore("b/257089187")
@SmallTest
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@UiThreadTest
public class InternetDialogDelegateTest extends SysuiTestCase {
private static final String MOBILE_NETWORK_TITLE = "Mobile Title";
@@ -87,6 +85,8 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
private SystemUIDialog.Factory mSystemUIDialogFactory;
@Mock
private SystemUIDialog mSystemUIDialog;
+ @Mock
+ private Window mWindow;
private FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock());
private InternetDialogDelegate mInternetDialogDelegate;
@@ -121,13 +121,16 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
when(mInternetDialogController.getMobileNetworkSummary(anyInt()))
.thenReturn(MOBILE_NETWORK_SUMMARY);
when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
-
+ when(mInternetDialogController.getActiveAutoSwitchNonDdsSubId()).thenReturn(
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
mMockitoSession = ExtendedMockito.mockitoSession()
.spyStatic(WifiEnterpriseRestrictionUtils.class)
.startMocking();
when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
when(mSystemUIDialogFactory.create(any(SystemUIDialog.Delegate.class)))
.thenReturn(mSystemUIDialog);
+ when(mSystemUIDialog.getContext()).thenReturn(mContext);
+ when(mSystemUIDialog.getWindow()).thenReturn(mWindow);
createInternetDialog();
}
@@ -146,6 +149,8 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
mBgExecutor,
mKeyguard,
mSystemUIDialogFactory);
+ mInternetDialogDelegate.createDialog();
+ mInternetDialogDelegate.onCreate(mSystemUIDialog, null);
mInternetDialogDelegate.mAdapter = mInternetAdapter;
mInternetDialogDelegate.mConnectedWifiEntry = mInternetWifiEntry;
mInternetDialogDelegate.mWifiEntriesCount = mWifiEntries.size();
@@ -163,10 +168,12 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
mSeeAll = mDialogView.requireViewById(R.id.see_all_layout);
mWifiScanNotify = mDialogView.requireViewById(R.id.wifi_scan_notify_layout);
mAirplaneModeSummaryText = mDialogView.requireViewById(R.id.airplane_mode_summary);
+ mInternetDialogDelegate.onStart(mSystemUIDialog);
}
@After
public void tearDown() {
+ mInternetDialogDelegate.onStop(mSystemUIDialog);
mInternetDialogDelegate.dismissDialog();
mMockitoSession.finishMocking();
}
@@ -191,59 +198,77 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
@Test
public void updateDialog_withApmOn_internetDialogSubTitleGone() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
+ });
}
@Test
public void updateDialog_withApmOff_internetDialogSubTitleVisible() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
+ });
}
@Test
public void updateDialog_apmOffAndHasEthernet_showEthernet() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
when(mInternetDialogController.hasEthernet()).thenReturn(true);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
+ });
}
@Test
public void updateDialog_apmOffAndNoEthernet_hideEthernet() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
when(mInternetDialogController.hasEthernet()).thenReturn(false);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
public void updateDialog_apmOnAndHasEthernet_showEthernet() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
when(mInternetDialogController.hasEthernet()).thenReturn(true);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
+ });
}
@Test
public void updateDialog_apmOnAndNoEthernet_hideEthernet() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
when(mInternetDialogController.hasEthernet()).thenReturn(false);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
@@ -252,41 +277,56 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(false);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
when(mInternetDialogController.hasActiveSubIdOnDds()).thenReturn(false);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
- public void updateDialog_apmOnWithCarrierNetworkAndWifiStatus_mobileDataLayout() {
- // Carrier network should be gone if airplane mode ON and Wi-Fi is off.
+ public void updateDialog_apmOnWithCarrierNetworkAndWifiStatus_mobileDataLayoutVisible() {
+ // Carrier network should be visible if airplane mode ON and Wi-Fi is ON.
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
- when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
-
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
+ });
+ }
- // Carrier network should be visible if airplane mode ON and Wi-Fi is ON.
+ @Test
+ public void updateDialog_apmOnWithCarrierNetworkAndWifiStatus_mobileDataLayoutGone() {
+ // Carrier network should be gone if airplane mode ON and Wi-Fi is off.
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
- when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
-
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
public void updateDialog_apmOnAndNoCarrierNetwork_mobileDataLayoutGone() {
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(false);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
@@ -295,11 +335,14 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
mInternetDialogDelegate.mConnectedWifiEntry = null;
doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
+ });
}
@Test
@@ -308,30 +351,39 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
mInternetDialogDelegate.mConnectedWifiEntry = null;
doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
public void updateDialog_apmOffAndHasCarrierNetwork_notShowApmSummary() {
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
public void updateDialog_apmOnAndNoCarrierNetwork_notShowApmSummary() {
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(false);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
@@ -340,10 +392,13 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
when(mInternetDialogController.isMobileDataEnabled()).thenReturn(true);
mMobileToggleSwitch.setChecked(false);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mMobileToggleSwitch.isChecked()).isTrue();
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mMobileToggleSwitch.isChecked()).isTrue();
+ });
}
@Test
@@ -352,26 +407,32 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
when(mInternetDialogController.isMobileDataEnabled()).thenReturn(false);
mMobileToggleSwitch.setChecked(false);
-
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mMobileToggleSwitch.isChecked()).isFalse();
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mMobileToggleSwitch.isChecked()).isFalse();
+ });
}
@Test
public void updateDialog_wifiOnAndHasInternetWifi_showConnectedWifi() {
- mInternetDialogDelegate.dismissDialog();
+ when(mInternetDialogController.getActiveAutoSwitchNonDdsSubId()).thenReturn(1);
doReturn(true).when(mInternetDialogController).hasActiveSubIdOnDds();
- createInternetDialog();
// The preconditions WiFi ON and Internet WiFi are already in setUp()
doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
- LinearLayout secondaryLayout = mDialogView.requireViewById(
- R.id.secondary_mobile_network_layout);
- assertThat(secondaryLayout.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
+ LinearLayout secondaryLayout = mDialogView.requireViewById(
+ R.id.secondary_mobile_network_layout);
+ assertThat(secondaryLayout.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
@@ -379,10 +440,13 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
// The precondition WiFi ON is already in setUp()
mInternetDialogDelegate.mConnectedWifiEntry = null;
doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
@@ -390,14 +454,17 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
// The precondition WiFi ON is already in setUp()
mInternetDialogDelegate.mConnectedWifiEntry = null;
mInternetDialogDelegate.mWifiEntriesCount = 0;
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
- // Show a blank block to fix the dialog height even if there is no WiFi list
- assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
- verify(mInternetAdapter).setMaxEntriesCount(3);
- assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+ // Show a blank block to fix the dialog height even if there is no WiFi list
+ assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+ verify(mInternetAdapter).setMaxEntriesCount(3);
+ assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
+ });
}
@Test
@@ -405,28 +472,34 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
// The precondition WiFi ON is already in setUp()
mInternetDialogDelegate.mConnectedWifiEntry = null;
mInternetDialogDelegate.mWifiEntriesCount = 1;
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
- // Show a blank block to fix the dialog height even if there is no WiFi list
- assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
- verify(mInternetAdapter).setMaxEntriesCount(3);
- assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+ // Show a blank block to fix the dialog height even if there is no WiFi list
+ assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+ verify(mInternetAdapter).setMaxEntriesCount(3);
+ assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
+ });
}
@Test
public void updateDialog_wifiOnAndHasConnectedWifi_showAllWifiAndSeeAllArea() {
// The preconditions WiFi ON and WiFi entries are already in setUp()
mInternetDialogDelegate.mWifiEntriesCount = 0;
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
- // Show a blank block to fix the dialog height even if there is no WiFi list
- assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
- verify(mInternetAdapter).setMaxEntriesCount(2);
- assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
+ // Show a blank block to fix the dialog height even if there is no WiFi list
+ assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+ verify(mInternetAdapter).setMaxEntriesCount(2);
+ assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
+ });
}
@Test
@@ -435,13 +508,16 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
mInternetDialogDelegate.mConnectedWifiEntry = null;
mInternetDialogDelegate.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT;
mInternetDialogDelegate.mHasMoreWifiEntries = true;
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
- assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
- verify(mInternetAdapter).setMaxEntriesCount(3);
- assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+ verify(mInternetAdapter).setMaxEntriesCount(3);
+ assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
+ });
}
@Test
@@ -449,13 +525,16 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
// The preconditions WiFi ON and WiFi entries are already in setUp()
mInternetDialogDelegate.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT - 1;
mInternetDialogDelegate.mHasMoreWifiEntries = true;
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
- verify(mInternetAdapter).setMaxEntriesCount(2);
- assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+ verify(mInternetAdapter).setMaxEntriesCount(2);
+ assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
+ });
}
@Test
@@ -463,32 +542,38 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
// The preconditions WiFi entries are already in setUp()
when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
mInternetDialogDelegate.mConnectedWifiEntry = null;
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- // Show WiFi Toggle without background
- assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mWifiToggle.getBackground()).isNull();
- // Hide Wi-Fi networks and See all
- assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
- assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
- assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ // Show WiFi Toggle without background
+ assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mWifiToggle.getBackground()).isNull();
+ // Hide Wi-Fi networks and See all
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
public void updateDialog_deviceLockedAndHasConnectedWifi_showWifiToggleWithBackground() {
// The preconditions WiFi ON and WiFi entries are already in setUp()
when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- // Show WiFi Toggle with highlight background
- assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mWifiToggle.getBackground()).isNotNull();
- // Hide Wi-Fi networks and See all
- assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
- assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
- assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ // Show WiFi Toggle with highlight background
+ assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mWifiToggle.getBackground()).isNotNull();
+ // Hide Wi-Fi networks and See all
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
@@ -496,13 +581,16 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
mInternetDialogDelegate.dismissDialog();
when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(false);
createInternetDialog();
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- // Disable Wi-Fi switch and show restriction message in summary.
- assertThat(mWifiToggleSwitch.isEnabled()).isFalse();
- assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mWifiToggleSummary.getText().length()).isNotEqualTo(0);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ // Disable Wi-Fi switch and show restriction message in summary.
+ assertThat(mWifiToggleSwitch.isEnabled()).isFalse();
+ assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mWifiToggleSummary.getText().length()).isNotEqualTo(0);
+ });
}
@Test
@@ -510,50 +598,38 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
mInternetDialogDelegate.dismissDialog();
when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
createInternetDialog();
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- // Enable Wi-Fi switch and hide restriction message in summary.
- assertThat(mWifiToggleSwitch.isEnabled()).isTrue();
- assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ // Enable Wi-Fi switch and hide restriction message in summary.
+ assertThat(mWifiToggleSwitch.isEnabled()).isTrue();
+ assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.GONE);
+ });
}
@Test
public void updateDialog_showSecondaryDataSub() {
- mInternetDialogDelegate.dismissDialog();
+ when(mInternetDialogController.getActiveAutoSwitchNonDdsSubId()).thenReturn(1);
doReturn(1).when(mInternetDialogController).getActiveAutoSwitchNonDdsSubId();
doReturn(true).when(mInternetDialogController).hasActiveSubIdOnDds();
doReturn(false).when(mInternetDialogController).isAirplaneModeEnabled();
- createInternetDialog();
-
clearInvocations(mInternetDialogController);
mInternetDialogDelegate.updateDialog(true);
+ mBgExecutor.runAllReady();
- LinearLayout primaryLayout = mDialogView.requireViewById(
- R.id.mobile_network_layout);
- LinearLayout secondaryLayout = mDialogView.requireViewById(
- R.id.secondary_mobile_network_layout);
-
- verify(mInternetDialogController).getMobileNetworkSummary(1);
- assertThat(primaryLayout.getBackground()).isNotEqualTo(secondaryLayout.getBackground());
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ LinearLayout primaryLayout = mDialogView.requireViewById(
+ R.id.mobile_network_layout);
+ LinearLayout secondaryLayout = mDialogView.requireViewById(
+ R.id.secondary_mobile_network_layout);
- // Tap the primary sub info
- primaryLayout.performClick();
- ArgumentCaptor<AlertDialog> dialogArgumentCaptor =
- ArgumentCaptor.forClass(AlertDialog.class);
- verify(mDialogTransitionAnimator).showFromDialog(dialogArgumentCaptor.capture(),
- eq(mSystemUIDialog), eq(null), eq(false));
- AlertDialog dialog = dialogArgumentCaptor.getValue();
- dialog.show();
- dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
- TestableLooper.get(this).processAllMessages();
- verify(mInternetDialogController).setAutoDataSwitchMobileDataPolicy(1, false);
-
- // Tap the secondary sub info
- secondaryLayout.performClick();
- verify(mInternetDialogController).launchMobileNetworkSettings(any(View.class));
-
- dialog.dismiss();
+ verify(mInternetDialogController).getMobileNetworkSummary(1);
+ assertThat(primaryLayout.getBackground()).isNotEqualTo(
+ secondaryLayout.getBackground());
+ });
}
@Test
@@ -561,6 +637,12 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
// The preconditions WiFi ON and WiFi entries are already in setUp()
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
+
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+ });
assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
}
@@ -569,8 +651,13 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() {
when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
when(mInternetDialogController.isWifiScanEnabled()).thenReturn(false);
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
+
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+ });
assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
}
@@ -580,8 +667,13 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
+
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+ });
assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
}
@@ -591,33 +683,43 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
when(mInternetDialogController.isDeviceLocked()).thenReturn(false);
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.VISIBLE);
- TextView wifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text);
- assertThat(wifiScanNotifyText.getText().length()).isNotEqualTo(0);
- assertThat(wifiScanNotifyText.getMovementMethod()).isNotNull();
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.VISIBLE);
+ TextView wifiScanNotifyText = mDialogView.requireViewById(
+ R.id.wifi_scan_notify_text);
+ assertThat(wifiScanNotifyText.getText().length()).isNotEqualTo(0);
+ assertThat(wifiScanNotifyText.getMovementMethod()).isNotNull();
+ });
}
@Test
public void updateDialog_wifiIsDisabled_uncheckWifiSwitch() {
when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
mWifiToggleSwitch.setChecked(true);
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mWifiToggleSwitch.isChecked()).isFalse();
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mWifiToggleSwitch.isChecked()).isFalse();
+ });
}
@Test
- public void updateDialog_wifiIsEnabled_checkWifiSwitch() {
+ public void updateDialog_wifiIsEnabled_checkWifiSwitch() throws Exception {
when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
mWifiToggleSwitch.setChecked(false);
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mWifiToggleSwitch.isChecked()).isTrue();
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mWifiToggleSwitch.isChecked()).isTrue();
+ });
}
@Test
@@ -699,21 +801,28 @@ public class InternetDialogDelegateTest extends SysuiTestCase {
public void updateDialog_shareWifiIntentNull_hideButton() {
when(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
.thenReturn(null);
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mInternetDialogDelegate.mShareWifiButton.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mInternetDialogDelegate.mShareWifiButton.getVisibility()).isEqualTo(
+ View.GONE);
+ });
}
@Test
public void updateDialog_shareWifiShareable_showButton() {
when(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
.thenReturn(new Intent());
-
mInternetDialogDelegate.updateDialog(false);
+ mBgExecutor.runAllReady();
- assertThat(mInternetDialogDelegate.mShareWifiButton.getVisibility())
- .isEqualTo(View.VISIBLE);
+ mInternetDialogDelegate.mDataInternetContent.observe(
+ mInternetDialogDelegate.mLifecycleOwner, i -> {
+ assertThat(mInternetDialogDelegate.mShareWifiButton.getVisibility())
+ .isEqualTo(View.VISIBLE);
+ });
}
private void setNetworkVisible(boolean ethernetVisible, boolean mobileDataVisible,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
index 660e8da72bf1..39e4fc9831b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
@@ -30,7 +30,7 @@ import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 63192f35ff40..95db95cd288b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -674,6 +674,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
}
@Test
+ @EnableFlags(NotificationContentAlphaOptimization.FLAG_NAME)
public void testForceResetSwipeStateDoesNothingIfTranslationIsZeroAndAlphaIsOne() {
doReturn(FAKE_ROW_WIDTH).when(mNotificationRow).getMeasuredWidth();
doReturn(0f).when(mNotificationRow).getTranslationX();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 70ac31d99559..30e7247b325e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -391,7 +391,6 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
configurationController,
mStatusOverlayHoverListenerFactory,
fakeDarkIconDispatcher,
- mock(StatusBarContentInsetsProvider::class.java),
)
.create(view)
.also { it.init() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
index 648ddf847ea0..575b05123d38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
@@ -56,14 +56,21 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
private val systemIconsContainer: View
get() = view.requireViewById(R.id.system_icons)
+ private val contentInsetsProvider = mock<StatusBarContentInsetsProvider>()
private val windowController = mock<StatusBarWindowController>()
@Before
fun setUp() {
+ mDependency.injectTestDependency(
+ StatusBarContentInsetsProvider::class.java,
+ contentInsetsProvider
+ )
mDependency.injectTestDependency(StatusBarWindowController::class.java, windowController)
context.ensureTestableResources()
view = spy(createStatusBarView())
whenever(view.rootWindowInsets).thenReturn(emptyWindowInsets())
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(Insets.NONE)
}
@Test
@@ -234,7 +241,8 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
@Test
fun onAttachedToWindow_updatesLeftTopRightPaddingsBasedOnInsets() {
val insets = Insets.of(/* left= */ 10, /* top= */ 20, /* right= */ 30, /* bottom= */ 40)
- view.setInsetsFetcher { insets }
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(insets)
view.onAttachedToWindow()
@@ -245,23 +253,10 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
}
@Test
- fun onAttachedToWindow_noInsetsFetcher_noCrash() {
- // Don't call `PhoneStatusBarView.setInsetsFetcher`
-
- // WHEN the view is attached
- view.onAttachedToWindow()
-
- // THEN there's no crash, and the padding stays as it was
- assertThat(view.paddingLeft).isEqualTo(0)
- assertThat(view.paddingTop).isEqualTo(0)
- assertThat(view.paddingRight).isEqualTo(0)
- assertThat(view.paddingBottom).isEqualTo(0)
- }
-
- @Test
fun onConfigurationChanged_updatesLeftTopRightPaddingsBasedOnInsets() {
val insets = Insets.of(/* left= */ 40, /* top= */ 30, /* right= */ 20, /* bottom= */ 10)
- view.setInsetsFetcher { insets }
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(insets)
view.onConfigurationChanged(Configuration())
@@ -272,31 +267,17 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
}
@Test
- fun onConfigurationChanged_noInsetsFetcher_noCrash() {
- // Don't call `PhoneStatusBarView.setInsetsFetcher`
-
- // WHEN the view is attached
- view.onConfigurationChanged(Configuration())
-
- // THEN there's no crash, and the padding stays as it was
- assertThat(view.paddingLeft).isEqualTo(0)
- assertThat(view.paddingTop).isEqualTo(0)
- assertThat(view.paddingRight).isEqualTo(0)
- assertThat(view.paddingBottom).isEqualTo(0)
- }
-
- @Test
fun onConfigurationChanged_noRelevantChange_doesNotUpdateInsets() {
val previousInsets =
Insets.of(/* left= */ 40, /* top= */ 30, /* right= */ 20, /* bottom= */ 10)
- view.setInsetsFetcher { previousInsets }
-
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(previousInsets)
context.orCreateTestableResources.overrideConfiguration(Configuration())
view.onAttachedToWindow()
val newInsets = Insets.NONE
- view.setInsetsFetcher { newInsets }
-
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(newInsets)
view.onConfigurationChanged(Configuration())
assertThat(view.paddingLeft).isEqualTo(previousInsets.left)
@@ -309,14 +290,16 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
fun onConfigurationChanged_densityChanged_updatesInsets() {
val previousInsets =
Insets.of(/* left= */ 40, /* top= */ 30, /* right= */ 20, /* bottom= */ 10)
- view.setInsetsFetcher { previousInsets }
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(previousInsets)
val configuration = Configuration()
configuration.densityDpi = 123
context.orCreateTestableResources.overrideConfiguration(configuration)
view.onAttachedToWindow()
val newInsets = Insets.NONE
- view.setInsetsFetcher { newInsets }
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(newInsets)
configuration.densityDpi = 456
view.onConfigurationChanged(configuration)
@@ -330,14 +313,16 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
fun onConfigurationChanged_fontScaleChanged_updatesInsets() {
val previousInsets =
Insets.of(/* left= */ 40, /* top= */ 30, /* right= */ 20, /* bottom= */ 10)
- view.setInsetsFetcher { previousInsets }
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(previousInsets)
val configuration = Configuration()
configuration.fontScale = 1f
context.orCreateTestableResources.overrideConfiguration(configuration)
view.onAttachedToWindow()
val newInsets = Insets.NONE
- view.setInsetsFetcher { newInsets }
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(newInsets)
configuration.fontScale = 2f
view.onConfigurationChanged(configuration)
@@ -363,7 +348,8 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
@Test
fun onApplyWindowInsets_updatesLeftTopRightPaddingsBasedOnInsets() {
val insets = Insets.of(/* left= */ 90, /* top= */ 10, /* right= */ 45, /* bottom= */ 50)
- view.setInsetsFetcher { insets }
+ whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(insets)
view.onApplyWindowInsets(WindowInsets(Rect()))
@@ -404,7 +390,7 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
/* typeVisibilityMap = */ booleanArrayOf(),
/* isRound = */ false,
/* forceConsumingTypes = */ 0,
- /* forceConsumingOpaqueCaptionBar = */ false,
+ /* forceConsumingCaptionBar = */ false,
/* suppressScrimTypes = */ 0,
/* displayCutout = */ DisplayCutout.NO_CUTOUT,
/* roundedCorners = */ RoundedCorners.NO_ROUNDED_CORNERS,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index 6fb70de3569d..60a15915fb77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -223,8 +223,11 @@ public class ImageWallpaperTest extends SysuiTestCase {
}
private void setBitmapDimensions(int bitmapWidth, int bitmapHeight) {
+ // TODO(b/281648899) remove the when(mWallpaperManager.peekBitmapDimensions(...))
when(mWallpaperManager.peekBitmapDimensions(anyInt(), anyBoolean()))
.thenReturn(new Rect(0, 0, bitmapWidth, bitmapHeight));
+ when(mWallpaperManager.peekBitmapDimensionsAsUser(anyInt(), anyBoolean(), anyInt()))
+ .thenReturn(new Rect(0, 0, bitmapWidth, bitmapHeight));
when(mWallpaperBitmap.getWidth()).thenReturn(bitmapWidth);
when(mWallpaperBitmap.getHeight()).thenReturn(bitmapHeight);
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/FakeContextualEducationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/FakeContextualEducationRepository.kt
index aa1968afba7d..cdfb297c27b9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/FakeContextualEducationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/FakeContextualEducationRepository.kt
@@ -25,13 +25,13 @@ import kotlinx.coroutines.flow.asStateFlow
class FakeContextualEducationRepository : ContextualEducationRepository {
private val userGestureMap = mutableMapOf<Int, GestureEduModel>()
- private val _gestureEduModels = MutableStateFlow(GestureEduModel())
+ private val _gestureEduModels = MutableStateFlow(GestureEduModel(userId = 0))
private val gestureEduModelsFlow = _gestureEduModels.asStateFlow()
private var currentUser: Int = 0
override fun setUser(userId: Int) {
if (!userGestureMap.contains(userId)) {
- userGestureMap[userId] = GestureEduModel()
+ userGestureMap[userId] = GestureEduModel(userId = userId)
}
// save data of current user to the map
userGestureMap[currentUser] = _gestureEduModels.value
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeActivatable.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeActivatable.kt
index e8b2dd232c1c..bcc73935de61 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeActivatable.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeActivatable.kt
@@ -25,7 +25,7 @@ class FakeActivatable(
var activationCount = 0
var cancellationCount = 0
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
activationCount++
onActivation()
try {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeSysUiViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeSysUiViewModel.kt
index 9a56f2419669..c0bb9a6fbe14 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeSysUiViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/lifecycle/FakeSysUiViewModel.kt
@@ -25,7 +25,7 @@ class FakeSysUiViewModel(
var activationCount = 0
var cancellationCount = 0
- override suspend fun onActivated() {
+ override suspend fun onActivated(): Nothing {
activationCount++
onActivation()
try {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index 0b309b59b0dc..4dd3ae762db7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -62,7 +62,9 @@ import com.android.systemui.statusbar.notification.people.PeopleNotificationIden
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.CoordinateOnClickListener
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener
-import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag
import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger
@@ -80,8 +82,6 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.wmshell.BubblesManager
-import com.google.common.util.concurrent.MoreExecutors
-import com.google.common.util.concurrent.SettableFuture
import java.util.Optional
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@@ -309,7 +309,7 @@ class ExpandableNotificationRowBuilder(
entry.ranking = rb.build()
}
- return generateRow(entry, FLAG_CONTENT_VIEW_ALL)
+ return generateRow(entry, INFLATION_FLAGS)
}
private fun generateRow(
@@ -374,7 +374,8 @@ class ExpandableNotificationRowBuilder(
private const val PKG = "com.android.systemui"
private const val UID = 1000
private val USER_HANDLE = UserHandle.of(ActivityManager.getCurrentUser())
-
+ private val INFLATION_FLAGS =
+ FLAG_CONTENT_VIEW_CONTRACTED or FLAG_CONTENT_VIEW_EXPANDED or FLAG_CONTENT_VIEW_HEADS_UP
private const val IS_CONVERSATION_FLAG = "test.isConversation"
private val Notification.isConversationStyleNotification
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelKosmos.kt
index 1542bb349a97..3247525f1a36 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.systemui.dump.dumpManager
import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
@@ -29,5 +30,6 @@ val Kosmos.notificationsPlaceholderViewModel by Fixture {
shadeInteractor = shadeInteractor,
headsUpNotificationInteractor = headsUpNotificationInteractor,
featureFlags = featureFlagsClassic,
+ dumpManager = dumpManager,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialKosmos.kt
new file mode 100644
index 000000000000..f502df0b4075
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialKosmos.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.touchpad.tutorial
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.model.sysUiState
+import com.android.systemui.settings.displayTracker
+import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
+
+var Kosmos.touchpadGesturesInteractor: TouchpadGesturesInteractor by
+ Kosmos.Fixture {
+ TouchpadGesturesInteractor(sysUiState, displayTracker, testScope.backgroundScope)
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt
new file mode 100644
index 000000000000..577620347991
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 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.util.coroutines
+
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.setMain
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+
+/**
+ * Overrides main dispatcher to passed testDispatcher. You probably want to use it when using
+ * viewModelScope which has hardcoded main dispatcher.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+class MainDispatcherRule(val testDispatcher: TestDispatcher) : TestWatcher() {
+ override fun starting(description: Description) {
+ Dispatchers.setMain(testDispatcher)
+ }
+
+ override fun finished(description: Description) {
+ Dispatchers.resetMain()
+ }
+}
diff --git a/ravenwood/tools/ravenizer-fake/Android.bp b/ravenwood/tools/ravenizer-fake/Android.bp
new file mode 100644
index 000000000000..7e2c407f2116
--- /dev/null
+++ b/ravenwood/tools/ravenizer-fake/Android.bp
@@ -0,0 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+sh_binary_host {
+ name: "ravenizer",
+ src: "ravenizer",
+ visibility: ["//visibility:public"],
+}
diff --git a/ravenwood/tools/ravenizer-fake/ravenizer b/ravenwood/tools/ravenizer-fake/ravenizer
new file mode 100755
index 000000000000..84b3c8ee365e
--- /dev/null
+++ b/ravenwood/tools/ravenizer-fake/ravenizer
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright (C) 2024 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.
+
+# "Fake" ravenizer, which just copies the file.
+# We need it to add ravenizer support to Soong on AOSP,
+# when the actual ravenizer is not in AOSP yet.
+
+invalid_arg() {
+ echo "Ravenizer(fake): invalid args" 1>&2
+ exit 1
+}
+
+(( $# >= 4 )) || invalid_arg
+[[ "$1" == "--in-jar" ]] || invalid_arg
+[[ "$3" == "--out-jar" ]] || invalid_arg
+
+echo "Ravenizer(fake): copiyng $2 to $4"
+
+cp "$2" "$4"
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 91b549c9a04b..68d92218c01b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15312,12 +15312,17 @@ public class ActivityManagerService extends IActivityManager.Stub
final int cookie = traceBroadcastIntentBegin(intent, resultTo, ordered, sticky,
callingUid, realCallingUid, userId);
try {
+ final BroadcastSentEventRecord broadcastSentEventRecord =
+ new BroadcastSentEventRecord();
final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId,
intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
appOp, BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky,
callingPid, callingUid, realCallingUid, realCallingPid, userId,
- backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver);
+ backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver,
+ broadcastSentEventRecord);
+ broadcastSentEventRecord.setResult(res);
+ broadcastSentEventRecord.logToStatsd();
return res;
} finally {
traceBroadcastIntentEnd(cookie);
@@ -15365,7 +15370,8 @@ public class ActivityManagerService extends IActivityManager.Stub
int callingUid, int realCallingUid, int realCallingPid, int userId,
BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList,
- @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
+ @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
+ @NonNull BroadcastSentEventRecord broadcastSentEventRecord) {
// Ensure all internal loopers are registered for idle checks
BroadcastLoopers.addMyLooper();
@@ -15398,6 +15404,17 @@ public class ActivityManagerService extends IActivityManager.Stub
}
intent = new Intent(intent);
+ broadcastSentEventRecord.setIntent(intent);
+ broadcastSentEventRecord.setOriginalIntentFlags(intent.getFlags());
+ broadcastSentEventRecord.setSenderUid(callingUid);
+ broadcastSentEventRecord.setRealSenderUid(realCallingUid);
+ broadcastSentEventRecord.setSticky(sticky);
+ broadcastSentEventRecord.setOrdered(ordered);
+ broadcastSentEventRecord.setResultRequested(resultTo != null);
+ final int callerAppProcessState = getRealProcessStateLocked(callerApp, realCallingPid);
+ broadcastSentEventRecord.setSenderProcState(callerAppProcessState);
+ broadcastSentEventRecord.setSenderUidState(getRealUidStateLocked(callerApp,
+ realCallingPid));
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
// Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
@@ -15891,7 +15908,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- final int callerAppProcessState = getRealProcessStateLocked(callerApp, realCallingPid);
// Add to the sticky list if requested.
if (sticky) {
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
@@ -16131,6 +16147,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ordered, sticky, false, userId,
backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
callerAppProcessState);
+ broadcastSentEventRecord.setBroadcastRecord(r);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
queue.enqueueBroadcastLocked(r);
@@ -16187,6 +16204,22 @@ public class ActivityManagerService extends IActivityManager.Stub
return PROCESS_STATE_NONEXISTENT;
}
+ @GuardedBy("this")
+ private int getRealUidStateLocked(ProcessRecord app, int pid) {
+ if (app == null) {
+ synchronized (mPidsSelfLocked) {
+ app = mPidsSelfLocked.get(pid);
+ }
+ }
+ if (app != null && app.getThread() != null && !app.isKilled()) {
+ final UidRecord uidRecord = app.getUidRecord();
+ if (uidRecord != null) {
+ return uidRecord.getCurProcState();
+ }
+ }
+ return PROCESS_STATE_NONEXISTENT;
+ }
+
@VisibleForTesting
ArrayList<StickyBroadcast> getStickyBroadcastsForTest(String action, int userId) {
synchronized (mStickyBroadcasts) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index edb04c5c00bc..f908c67d7ec9 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -53,6 +53,7 @@ import android.os.Bundle;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.IntArray;
import android.util.PrintWriterPrinter;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -940,6 +941,46 @@ final class BroadcastRecord extends Binder {
return type;
}
+ int[] calculateTypesForLogging() {
+ final IntArray types = new IntArray();
+ if (isForeground()) {
+ types.add(BROADCAST_TYPE_FOREGROUND);
+ } else {
+ types.add(BROADCAST_TYPE_BACKGROUND);
+ }
+ if (alarm) {
+ types.add(BROADCAST_TYPE_ALARM);
+ }
+ if (interactive) {
+ types.add(BROADCAST_TYPE_INTERACTIVE);
+ }
+ if (ordered) {
+ types.add(BROADCAST_TYPE_ORDERED);
+ }
+ if (prioritized) {
+ types.add(BROADCAST_TYPE_PRIORITIZED);
+ }
+ if (resultTo != null) {
+ types.add(BROADCAST_TYPE_RESULT_TO);
+ }
+ if (deferUntilActive) {
+ types.add(BROADCAST_TYPE_DEFERRABLE_UNTIL_ACTIVE);
+ }
+ if (pushMessage) {
+ types.add(BROADCAST_TYPE_PUSH_MESSAGE);
+ }
+ if (pushMessageOverQuota) {
+ types.add(BROADCAST_TYPE_PUSH_MESSAGE_OVER_QUOTA);
+ }
+ if (sticky) {
+ types.add(BROADCAST_TYPE_STICKY);
+ }
+ if (initialSticky) {
+ types.add(BROADCAST_TYPE_INITIAL_STICKY);
+ }
+ return types.toArray();
+ }
+
public BroadcastRecord maybeStripForHistory() {
if (!intent.canStripForHistory()) {
return this;
diff --git a/services/core/java/com/android/server/am/BroadcastSentEventRecord.java b/services/core/java/com/android/server/am/BroadcastSentEventRecord.java
new file mode 100644
index 000000000000..f2ac6d52b0c0
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastSentEventRecord.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 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.am;
+
+import static android.app.AppProtoEnums.BROADCAST_TYPE_ORDERED;
+import static android.app.AppProtoEnums.BROADCAST_TYPE_RESULT_TO;
+import static android.app.AppProtoEnums.BROADCAST_TYPE_STICKY;
+
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_SENT;
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_SENT__RESULT__FAILED_STICKY_CANT_HAVE_PERMISSION;
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_SENT__RESULT__FAILED_USER_STOPPED;
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_SENT__RESULT__SUCCESS;
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_SENT__RESULT__UNKNOWN;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.content.Intent;
+import android.util.IntArray;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+final class BroadcastSentEventRecord {
+ @NonNull private Intent mIntent;
+ private int mOriginalIntentFlags;
+ private int mSenderUid;
+ private int mRealSenderUid;
+ private boolean mSticky;
+ private boolean mOrdered;
+ private boolean mResultRequested;
+ private int mSenderProcState;
+ private int mSenderUidState;
+ @Nullable private BroadcastRecord mBroadcastRecord;
+ private int mResult;
+
+ public void setIntent(@NonNull Intent intent) {
+ mIntent = intent;
+ }
+
+ public void setSenderUid(int uid) {
+ mSenderUid = uid;
+ }
+
+ public void setRealSenderUid(int uid) {
+ mRealSenderUid = uid;
+ }
+
+ public void setOriginalIntentFlags(int flags) {
+ mOriginalIntentFlags = flags;
+ }
+
+ public void setSticky(boolean sticky) {
+ mSticky = sticky;
+ }
+
+ public void setOrdered(boolean ordered) {
+ mOrdered = ordered;
+ }
+
+ public void setResultRequested(boolean resultRequested) {
+ mResultRequested = resultRequested;
+ }
+
+ public void setSenderProcState(int procState) {
+ mSenderProcState = procState;
+ }
+
+ public void setSenderUidState(int procState) {
+ mSenderUidState = procState;
+ }
+
+ public void setBroadcastRecord(@NonNull BroadcastRecord record) {
+ mBroadcastRecord = record;
+ }
+
+ public void setResult(int result) {
+ mResult = result;
+ }
+
+ public void logToStatsd() {
+ if (Flags.logBroadcastSentEvent()) {
+ int loggingResult = switch (mResult) {
+ case ActivityManager.BROADCAST_SUCCESS ->
+ BROADCAST_SENT__RESULT__SUCCESS;
+ case ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION ->
+ BROADCAST_SENT__RESULT__FAILED_STICKY_CANT_HAVE_PERMISSION;
+ case ActivityManager.BROADCAST_FAILED_USER_STOPPED ->
+ BROADCAST_SENT__RESULT__FAILED_USER_STOPPED;
+ default -> BROADCAST_SENT__RESULT__UNKNOWN;
+ };
+ int[] types = calculateTypesForLogging();
+ FrameworkStatsLog.write(BROADCAST_SENT, mIntent.getAction(), mIntent.getFlags(),
+ mOriginalIntentFlags, mSenderUid, mRealSenderUid, mIntent.getPackage() != null,
+ mIntent.getComponent() != null,
+ mBroadcastRecord != null ? mBroadcastRecord.receivers.size() : 0,
+ loggingResult,
+ mBroadcastRecord != null ? mBroadcastRecord.getDeliveryGroupPolicy() : 0,
+ ActivityManager.processStateAmToProto(mSenderProcState),
+ ActivityManager.processStateAmToProto(mSenderUidState), types);
+ }
+ }
+
+ private int[] calculateTypesForLogging() {
+ if (mBroadcastRecord != null) {
+ return mBroadcastRecord.calculateTypesForLogging();
+ } else {
+ final IntArray types = new IntArray();
+ if (mSticky) {
+ types.add(BROADCAST_TYPE_STICKY);
+ }
+ if (mOrdered) {
+ types.add(BROADCAST_TYPE_ORDERED);
+ }
+ if (mResultRequested) {
+ types.add(BROADCAST_TYPE_RESULT_TO);
+ }
+ return types.toArray();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 5315167b46eb..3334393a1618 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -184,3 +184,14 @@ flag {
description: "Defer submitting binder calls to paused processes."
bug: "327038797"
}
+
+flag {
+ name: "log_broadcast_sent_event"
+ namespace: "backstage_power"
+ description: "Log the broadcast send event to Statsd"
+ bug: "355261986"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index bd27f475dfe1..ab7971355041 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -492,6 +492,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Used to scale the brightness in doze mode
private float mDozeScaleFactor;
+ // Used to keep track of the display state from the latest request to override the doze screen
+ // state.
+ @GuardedBy("mLock")
+ private int mPendingOverrideDozeScreenStateLocked;
+
/**
* Creates the display power controller.
*/
@@ -803,15 +808,28 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
@Override
public void overrideDozeScreenState(int displayState, @Display.StateReason int reason) {
Slog.i(TAG, "New offload doze override: " + Display.stateToString(displayState));
- mHandler.postAtTime(() -> {
- if (mDisplayOffloadSession == null
- || !(DisplayOffloadSession.isSupportedOffloadState(displayState)
- || displayState == Display.STATE_UNKNOWN)) {
- return;
+ if (mDisplayOffloadSession != null
+ && (DisplayOffloadSession.isSupportedOffloadState(displayState)
+ || displayState == Display.STATE_UNKNOWN)) {
+ if (mFlags.isOffloadDozeOverrideHoldsWakelockEnabled()) {
+ mWakelockController.acquireWakelock(
+ WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE);
}
- mDisplayStateController.overrideDozeScreenState(displayState, reason);
- updatePowerState();
- }, mClock.uptimeMillis());
+ synchronized (mLock) {
+ mPendingOverrideDozeScreenStateLocked = displayState;
+ }
+ mHandler.postAtTime(() -> {
+ synchronized (mLock) {
+ mDisplayStateController
+ .overrideDozeScreenState(mPendingOverrideDozeScreenStateLocked, reason);
+ }
+ updatePowerState();
+ if (mFlags.isOffloadDozeOverrideHoldsWakelockEnabled()) {
+ mWakelockController.releaseWakelock(
+ WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE);
+ }
+ }, mClock.uptimeMillis());
+ }
}
@Override
@@ -1338,30 +1356,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
initialize(readyToUpdateDisplayState() ? state : Display.STATE_UNKNOWN);
}
- if (mFlags.isOffloadDozeOverrideHoldsWakelockEnabled()) {
- // Sometimes, a display-state change can come without an associated PowerRequest,
- // as with DisplayOffload. For those cases, we have to make sure to also mark the
- // display as "not ready" so that we can inform power-manager when the state-change is
- // complete.
- if (mPowerState.getScreenState() != state) {
- final boolean wasReady;
- synchronized (mLock) {
- wasReady = mDisplayReadyLocked;
- mDisplayReadyLocked = false;
- mustNotify = true;
- }
-
- if (wasReady) {
- // If we went from ready to not-ready from the state-change (instead of a
- // PowerRequest) there's a good chance that nothing is keeping PowerManager
- // from suspending. Grab the unfinished business suspend blocker to keep the
- // device awake until the display-state change goes into effect.
- mWakelockController.acquireWakelock(
- WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
- }
- }
- }
-
// Animate the screen state change unless already animating.
// The transition may be deferred, so after this point we will use the
// actual state instead of the desired one.
diff --git a/services/core/java/com/android/server/display/WakelockController.java b/services/core/java/com/android/server/display/WakelockController.java
index 7bc797125b0e..5b0229cbb393 100644
--- a/services/core/java/com/android/server/display/WakelockController.java
+++ b/services/core/java/com/android/server/display/WakelockController.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.hardware.display.DisplayManagerInternal;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.utils.DebugUtils;
@@ -37,7 +38,8 @@ public final class WakelockController {
public static final int WAKE_LOCK_PROXIMITY_NEGATIVE = 2;
public static final int WAKE_LOCK_PROXIMITY_DEBOUNCE = 3;
public static final int WAKE_LOCK_STATE_CHANGED = 4;
- public static final int WAKE_LOCK_UNFINISHED_BUSINESS = 5;
+ public static final int WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE = 5;
+ public static final int WAKE_LOCK_UNFINISHED_BUSINESS = 6;
@VisibleForTesting
static final int WAKE_LOCK_MAX = WAKE_LOCK_UNFINISHED_BUSINESS;
@@ -53,18 +55,23 @@ public final class WakelockController {
WAKE_LOCK_PROXIMITY_NEGATIVE,
WAKE_LOCK_PROXIMITY_DEBOUNCE,
WAKE_LOCK_STATE_CHANGED,
+ WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE,
WAKE_LOCK_UNFINISHED_BUSINESS
})
@Retention(RetentionPolicy.SOURCE)
public @interface WAKE_LOCK_TYPE {
}
+ private final Object mLock = new Object();
+
// Asynchronous callbacks into the power manager service.
// Only invoked from the handler thread while no locks are held.
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks;
// Identifiers for suspend blocker acquisition requests
private final String mSuspendBlockerIdUnfinishedBusiness;
+ @GuardedBy("mLock")
+ private final String mSuspendBlockerOverrideDozeScreenState;
private final String mSuspendBlockerIdOnStateChanged;
private final String mSuspendBlockerIdProxPositive;
private final String mSuspendBlockerIdProxNegative;
@@ -73,6 +80,10 @@ public final class WakelockController {
// True if we have unfinished business and are holding a suspend-blocker.
private boolean mUnfinishedBusiness;
+ // True if we have are holding a suspend-blocker to override the doze screen state.
+ @GuardedBy("mLock")
+ private boolean mIsOverrideDozeScreenStateAcquired;
+
// True if we have have debounced the proximity change impact and are holding a suspend-blocker.
private boolean mHasProximityDebounced;
@@ -108,6 +119,7 @@ public final class WakelockController {
mTag = TAG + "[" + mDisplayId + "]";
mDisplayPowerCallbacks = callbacks;
mSuspendBlockerIdUnfinishedBusiness = "[" + displayId + "]unfinished business";
+ mSuspendBlockerOverrideDozeScreenState = "[" + displayId + "]override doze screen state";
mSuspendBlockerIdOnStateChanged = "[" + displayId + "]on state changed";
mSuspendBlockerIdProxPositive = "[" + displayId + "]prox positive";
mSuspendBlockerIdProxNegative = "[" + displayId + "]prox negative";
@@ -154,6 +166,10 @@ public final class WakelockController {
return acquireProxDebounceSuspendBlocker();
case WAKE_LOCK_STATE_CHANGED:
return acquireStateChangedSuspendBlocker();
+ case WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE:
+ synchronized (mLock) {
+ return acquireOverrideDozeScreenStateSuspendBlockerLocked();
+ }
case WAKE_LOCK_UNFINISHED_BUSINESS:
return acquireUnfinishedBusinessSuspendBlocker();
default:
@@ -171,6 +187,10 @@ public final class WakelockController {
return releaseProxDebounceSuspendBlocker();
case WAKE_LOCK_STATE_CHANGED:
return releaseStateChangedSuspendBlocker();
+ case WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE:
+ synchronized (mLock) {
+ return releaseOverrideDozeScreenStateSuspendBlockerLocked();
+ }
case WAKE_LOCK_UNFINISHED_BUSINESS:
return releaseUnfinishedBusinessSuspendBlocker();
default:
@@ -220,6 +240,42 @@ public final class WakelockController {
}
/**
+ * Acquires the suspend blocker to override the doze screen state and notifies the
+ * PowerManagerService about the changes. Note that this utility is syncronized because a
+ * request to override the doze screen state can come from a non-power thread.
+ */
+ @GuardedBy("mLock")
+ private boolean acquireOverrideDozeScreenStateSuspendBlockerLocked() {
+ // Grab a wake lock if we have unfinished business.
+ if (!mIsOverrideDozeScreenStateAcquired) {
+ if (DEBUG) {
+ Slog.d(mTag, "Acquiring suspend blocker to override the doze screen state...");
+ }
+ mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerOverrideDozeScreenState);
+ mIsOverrideDozeScreenStateAcquired = true;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Releases the override doze screen state suspend blocker and notifies the PowerManagerService
+ * about the changes.
+ */
+ @GuardedBy("mLock")
+ private boolean releaseOverrideDozeScreenStateSuspendBlockerLocked() {
+ if (mIsOverrideDozeScreenStateAcquired) {
+ if (DEBUG) {
+ Slog.d(mTag, "Finished overriding doze screen state...");
+ }
+ mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerOverrideDozeScreenState);
+ mIsOverrideDozeScreenStateAcquired = false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Acquires the unfinished business wakelock and notifies the PowerManagerService about the
* changes.
*/
@@ -366,6 +422,7 @@ public final class WakelockController {
pw.println(" mOnStateChangePending=" + isOnStateChangedPending());
pw.println(" mOnProximityPositiveMessages=" + isProximityPositiveAcquired());
pw.println(" mOnProximityNegativeMessages=" + isProximityNegativeAcquired());
+ pw.println(" mIsOverrideDozeScreenStateAcquired=" + isOverrideDozeScreenStateAcquired());
}
@VisibleForTesting
@@ -394,6 +451,13 @@ public final class WakelockController {
}
@VisibleForTesting
+ String getSuspendBlockerOverrideDozeScreenState() {
+ synchronized (mLock) {
+ return mSuspendBlockerOverrideDozeScreenState;
+ }
+ }
+
+ @VisibleForTesting
boolean hasUnfinishedBusiness() {
return mUnfinishedBusiness;
}
@@ -417,4 +481,11 @@ public final class WakelockController {
boolean hasProximitySensorDebounced() {
return mHasProximityDebounced;
}
+
+ @VisibleForTesting
+ boolean isOverrideDozeScreenStateAcquired() {
+ synchronized (mLock) {
+ return mIsOverrideDozeScreenStateAcquired;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 000f3122f05a..ef61d02cd999 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -71,6 +71,8 @@ class InputSettingsObserver extends ContentObserver {
(reason) -> updateTouchpadTapToClickEnabled()),
Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_TAP_DRAGGING),
(reason) -> updateTouchpadTapDraggingEnabled()),
+ Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_VISUALIZER),
+ (reason) -> updateTouchpadHardwareStateNotificationsEnabled()),
Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE),
(reason) -> updateTouchpadRightClickZoneEnabled()),
Map.entry(Settings.System.getUriFor(Settings.System.SHOW_TOUCHES),
@@ -177,6 +179,10 @@ class InputSettingsObserver extends ContentObserver {
mNative.setTouchpadTapDraggingEnabled(InputSettings.useTouchpadTapDragging(mContext));
}
+ private void updateTouchpadHardwareStateNotificationsEnabled() {
+ mNative.setShouldNotifyTouchpadHardwareState(InputSettings.useTouchpadVisualizer(mContext));
+ }
+
private void updateTouchpadRightClickZoneEnabled() {
mNative.setTouchpadRightClickZoneEnabled(InputSettings.useTouchpadRightClickZone(mContext));
}
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index a9d40bb54f96..69a9f4d88da1 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -135,6 +135,8 @@ interface NativeInputManagerService {
void setTouchpadTapDraggingEnabled(boolean enabled);
+ void setShouldNotifyTouchpadHardwareState(boolean enabled);
+
void setTouchpadRightClickZoneEnabled(boolean enabled);
void setShowTouches(boolean enabled);
@@ -395,6 +397,9 @@ interface NativeInputManagerService {
public native void setTouchpadTapDraggingEnabled(boolean enabled);
@Override
+ public native void setShouldNotifyTouchpadHardwareState(boolean enabled);
+
+ @Override
public native void setTouchpadRightClickZoneEnabled(boolean enabled);
@Override
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 1070f2f8faf1..e1b8e9f559ed 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1364,14 +1364,14 @@ class MediaRouter2ServiceImpl {
if (manager == null || manager.mLastSessionCreationRequest == null) {
Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
+ "Ignoring unknown request.");
- userHandler.notifySessionCreationFailedToRouter(routerRecord, requestId);
+ routerRecord.notifySessionCreationFailed(requestId);
return;
}
if (!TextUtils.equals(manager.mLastSessionCreationRequest.mOldSession.getId(),
oldSession.getId())) {
Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
+ "Ignoring unmatched routing session.");
- userHandler.notifySessionCreationFailedToRouter(routerRecord, requestId);
+ routerRecord.notifySessionCreationFailed(requestId);
return;
}
if (!TextUtils.equals(manager.mLastSessionCreationRequest.mRoute.getId(),
@@ -1384,7 +1384,7 @@ class MediaRouter2ServiceImpl {
} else {
Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
+ "Ignoring unmatched route.");
- userHandler.notifySessionCreationFailedToRouter(routerRecord, requestId);
+ routerRecord.notifySessionCreationFailed(requestId);
return;
}
}
@@ -1396,7 +1396,7 @@ class MediaRouter2ServiceImpl {
&& !TextUtils.equals(route.getId(), defaultRouteId)) {
Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
+ route);
- userHandler.notifySessionCreationFailedToRouter(routerRecord, requestId);
+ routerRecord.notifySessionCreationFailed(requestId);
return;
}
}
@@ -1484,8 +1484,7 @@ class MediaRouter2ServiceImpl {
&& !TextUtils.equals(route.getId(), defaultRouteId)) {
userHandler.sendMessage(
obtainMessage(
- UserHandler::notifySessionCreationFailedToRouter,
- userHandler,
+ RouterRecord::notifySessionCreationFailed,
routerRecord,
toOriginalRequestId(DUMMY_REQUEST_ID)));
} else {
@@ -1762,12 +1761,7 @@ class MediaRouter2ServiceImpl {
if (routerRecord == null) {
Slog.w(TAG, "requestCreateSessionWithManagerLocked: Ignoring session creation for "
+ "unknown router.");
- try {
- managerRecord.mManager.notifyRequestFailed(requestId, REASON_UNKNOWN_ERROR);
- } catch (RemoteException ex) {
- Slog.w(TAG, "requestCreateSessionWithManagerLocked: Failed to notify failure. "
- + "Manager probably died.");
- }
+ managerRecord.notifyRequestFailed(requestId, REASON_UNKNOWN_ERROR);
return;
}
@@ -1780,10 +1774,8 @@ class MediaRouter2ServiceImpl {
"requestCreateSessionWithManagerLocked: Notifying failure for pending"
+ " session creation request - oldSession: %s, route: %s",
lastRequest.mOldSession, lastRequest.mRoute));
- managerRecord.mUserRecord.mHandler.notifyRequestFailedToManager(
- managerRecord.mManager,
- toOriginalRequestId(lastRequest.mManagerRequestId),
- REASON_UNKNOWN_ERROR);
+ managerRecord.notifyRequestFailed(
+ toOriginalRequestId(lastRequest.mManagerRequestId), REASON_UNKNOWN_ERROR);
}
managerRecord.mLastSessionCreationRequest = new SessionCreationRequest(routerRecord,
MediaRoute2ProviderService.REQUEST_ID_NONE, uniqueRequestId,
@@ -1793,15 +1785,12 @@ class MediaRouter2ServiceImpl {
// As a return, media router will request to create a session.
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(
- UserHandler::requestRouterCreateSessionOnHandler,
- routerRecord.mUserRecord.mHandler,
- uniqueRequestId,
+ RouterRecord::requestCreateSessionByManager,
routerRecord,
managerRecord,
+ uniqueRequestId,
oldSession,
- route,
- transferInitiatorUserHandle,
- transferInitiatorPackageName));
+ route));
}
@GuardedBy("mLock")
@@ -2256,6 +2245,71 @@ class MediaRouter2ServiceImpl {
}
/**
+ * Notifies the corresponding router of a request failure.
+ *
+ * @param requestId The id of the request that failed.
+ */
+ public void notifySessionCreationFailed(int requestId) {
+ try {
+ mRouter.notifySessionCreated(requestId, /* sessionInfo= */ null);
+ } catch (RemoteException ex) {
+ Slog.w(
+ TAG,
+ "Failed to notify router of the session creation failure."
+ + " Router probably died.",
+ ex);
+ }
+ }
+
+ /**
+ * Notifies the corresponding router of the release of the given {@link RoutingSessionInfo}.
+ */
+ public void notifySessionReleased(RoutingSessionInfo sessionInfo) {
+ try {
+ mRouter.notifySessionReleased(sessionInfo);
+ } catch (RemoteException ex) {
+ Slog.w(
+ TAG,
+ "Failed to notify router of the session release. Router probably died.",
+ ex);
+ }
+ }
+
+ /**
+ * Sends the corresponding router a {@link RoutingSessionInfo session} creation request,
+ * with the given {@link MediaRoute2Info} as the initial member.
+ *
+ * <p>Must be called on the thread of the corresponding {@link UserHandler}.
+ *
+ * @param managerRecord The record of the manager that made the request.
+ * @param uniqueRequestId The id of the request.
+ * @param oldSession The session from which the transfer originated.
+ * @param route The initial route member of the session to create.
+ */
+ public void requestCreateSessionByManager(
+ ManagerRecord managerRecord,
+ long uniqueRequestId,
+ RoutingSessionInfo oldSession,
+ MediaRoute2Info route) {
+ try {
+ if (route.isSystemRoute() && !hasSystemRoutingPermission()) {
+ // The router lacks permission to modify system routing, so we hide system
+ // route info from them.
+ route = mUserRecord.mHandler.mSystemProvider.getDefaultRoute();
+ }
+ mRouter.requestCreateSessionByManager(uniqueRequestId, oldSession, route);
+ } catch (RemoteException ex) {
+ Slog.w(
+ TAG,
+ "getSessionHintsForCreatingSessionOnHandler: "
+ + "Failed to request. Router probably died.",
+ ex);
+ managerRecord.notifyRequestFailed(
+ toOriginalRequestId(uniqueRequestId), REASON_UNKNOWN_ERROR);
+ }
+ }
+
+ /**
* Sends the corresponding router an update for the given session.
*
* <p>Note: These updates are not directly visible to the app.
@@ -2360,6 +2414,25 @@ class MediaRouter2ServiceImpl {
}
}
+ /**
+ * Notifies the corresponding manager of a request failure.
+ *
+ * <p>Must be called on the thread of the corresponding {@link UserHandler}.
+ *
+ * @param requestId The id of the request that failed.
+ * @param reason The reason of the failure. One of
+ */
+ public void notifyRequestFailed(int requestId, int reason) {
+ try {
+ mManager.notifyRequestFailed(requestId, reason);
+ } catch (RemoteException ex) {
+ Slog.w(
+ TAG,
+ "Failed to notify manager of the request failure. Manager probably died.",
+ ex);
+ }
+ }
+
private void updateScanningState(@ScanningState int scanningState) {
if (mScanningState == scanningState) {
return;
@@ -2738,30 +2811,6 @@ class MediaRouter2ServiceImpl {
return -1;
}
- private void requestRouterCreateSessionOnHandler(
- long uniqueRequestId,
- @NonNull RouterRecord routerRecord,
- @NonNull ManagerRecord managerRecord,
- @NonNull RoutingSessionInfo oldSession,
- @NonNull MediaRoute2Info route,
- @NonNull UserHandle transferInitiatorUserHandle,
- @NonNull String transferInitiatorPackageName) {
- try {
- if (route.isSystemRoute() && !routerRecord.hasSystemRoutingPermission()) {
- // The router lacks permission to modify system routing, so we hide system
- // route info from them.
- route = mSystemProvider.getDefaultRoute();
- }
- routerRecord.mRouter.requestCreateSessionByManager(
- uniqueRequestId, oldSession, route);
- } catch (RemoteException ex) {
- Slog.w(TAG, "getSessionHintsForCreatingSessionOnHandler: "
- + "Failed to request. Router probably died.", ex);
- notifyRequestFailedToManager(managerRecord.mManager,
- toOriginalRequestId(uniqueRequestId), REASON_UNKNOWN_ERROR);
- }
- }
-
private void requestCreateSessionWithRouter2OnHandler(
long uniqueRequestId,
long managerRequestId,
@@ -2774,8 +2823,7 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
Slog.w(TAG, "requestCreateSessionWithRouter2OnHandler: Ignoring session "
+ "creation request since no provider found for given route=" + route);
- notifySessionCreationFailedToRouter(routerRecord,
- toOriginalRequestId(uniqueRequestId));
+ routerRecord.notifySessionCreationFailed(toOriginalRequestId(uniqueRequestId));
return;
}
@@ -3054,7 +3102,7 @@ class MediaRouter2ServiceImpl {
+ sessionInfo);
return;
}
- notifySessionReleasedToRouter(routerRecord, sessionInfo);
+ routerRecord.notifySessionReleased(sessionInfo);
}
private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
@@ -3073,8 +3121,7 @@ class MediaRouter2ServiceImpl {
final int requesterId = toRequesterId(uniqueRequestId);
ManagerRecord manager = findManagerWithId(requesterId);
if (manager != null) {
- notifyRequestFailedToManager(
- manager.mManager, toOriginalRequestId(uniqueRequestId), reason);
+ manager.notifyRequestFailed(toOriginalRequestId(uniqueRequestId), reason);
}
// Currently, only manager records can get notified of failures.
@@ -3109,40 +3156,19 @@ class MediaRouter2ServiceImpl {
// Notify the requester about the failure.
// The call should be made by either MediaRouter2 or MediaRouter2Manager.
if (matchingRequest.mManagerRequestId == MediaRouter2Manager.REQUEST_ID_NONE) {
- notifySessionCreationFailedToRouter(
- matchingRequest.mRouterRecord, toOriginalRequestId(uniqueRequestId));
+ matchingRequest.mRouterRecord.notifySessionCreationFailed(
+ toOriginalRequestId(uniqueRequestId));
} else {
final int requesterId = toRequesterId(matchingRequest.mManagerRequestId);
ManagerRecord manager = findManagerWithId(requesterId);
if (manager != null) {
- notifyRequestFailedToManager(manager.mManager,
+ manager.notifyRequestFailed(
toOriginalRequestId(matchingRequest.mManagerRequestId), reason);
}
}
return true;
}
- private void notifySessionCreationFailedToRouter(@NonNull RouterRecord routerRecord,
- int requestId) {
- try {
- routerRecord.mRouter.notifySessionCreated(requestId,
- /* sessionInfo= */ null);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to notify router of the session creation failure."
- + " Router probably died.", ex);
- }
- }
-
- private void notifySessionReleasedToRouter(@NonNull RouterRecord routerRecord,
- @NonNull RoutingSessionInfo sessionInfo) {
- try {
- routerRecord.mRouter.notifySessionReleased(sessionInfo);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to notify router of the session release."
- + " Router probably died.", ex);
- }
- }
-
private List<IMediaRouter2Manager> getManagers() {
final List<IMediaRouter2Manager> managers = new ArrayList<>();
MediaRouter2ServiceImpl service = mServiceRef.get();
@@ -3379,16 +3405,6 @@ class MediaRouter2ServiceImpl {
// need to update routers other than the one making the update.
}
- private void notifyRequestFailedToManager(@NonNull IMediaRouter2Manager manager,
- int requestId, int reason) {
- try {
- manager.notifyRequestFailed(requestId, reason);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to notify manager of the request failure."
- + " Manager probably died.", ex);
- }
- }
-
private void updateDiscoveryPreferenceOnHandler() {
MediaRouter2ServiceImpl service = mServiceRef.get();
if (service == null) {
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 1cdab44a5b1b..008746c0423c 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -118,11 +118,32 @@ public class GroupHelper {
private final ArrayMap<FullyQualifiedGroupKey, ArrayMap<String, NotificationAttributes>>
mAggregatedNotifications = new ArrayMap<>();
- private static final List<NotificationSectioner> NOTIFICATION_SHADE_SECTIONS = List.of(
- new NotificationSectioner("AlertingSection", 0, (record) ->
- record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT),
- new NotificationSectioner("SilentSection", 1, (record) ->
- record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT));
+ private static List<NotificationSectioner> NOTIFICATION_SHADE_SECTIONS =
+ getNotificationShadeSections();
+
+ private static List<NotificationSectioner> getNotificationShadeSections() {
+ if (android.service.notification.Flags.notificationClassification()) {
+ return List.of(
+ new NotificationSectioner("PromotionsSection", 0, (record) ->
+ NotificationChannel.PROMOTIONS_ID.equals(record.getChannel().getId())),
+ new NotificationSectioner("SocialSection", 0, (record) ->
+ NotificationChannel.SOCIAL_MEDIA_ID.equals(record.getChannel().getId())),
+ new NotificationSectioner("NewsSection", 0, (record) ->
+ NotificationChannel.NEWS_ID.equals(record.getChannel().getId())),
+ new NotificationSectioner("RecsSection", 0, (record) ->
+ NotificationChannel.RECS_ID.equals(record.getChannel().getId())),
+ new NotificationSectioner("AlertingSection", 0, (record) ->
+ record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT),
+ new NotificationSectioner("SilentSection", 1, (record) ->
+ record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT));
+ } else {
+ return List.of(
+ new NotificationSectioner("AlertingSection", 0, (record) ->
+ record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT),
+ new NotificationSectioner("SilentSection", 1, (record) ->
+ record.getImportance() < NotificationManager.IMPORTANCE_DEFAULT));
+ }
+ }
public GroupHelper(Context context, PackageManager packageManager, int autoGroupAtCount,
int autoGroupSparseGroupsAtCount, Callback callback) {
@@ -131,6 +152,7 @@ public class GroupHelper {
mContext = context;
mPackageManager = packageManager;
mAutogroupSparseGroupsAtCount = autoGroupSparseGroupsAtCount;
+ NOTIFICATION_SHADE_SECTIONS = getNotificationShadeSections();
}
private String generatePackageKey(int userId, String pkg) {
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index aaa38a3a1331..6c78b3c85e18 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -887,7 +887,7 @@ final class DefaultPermissionGrantPolicy {
grantPermissionsToSystemPackage(pm,
getDefaultSystemHandlerActivityPackage(pm,
SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
- userId, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS);
+ userId, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS, NEARBY_DEVICES_PERMISSIONS);
}
// Print Spooler
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index 096231910e6e..8e375275d080 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
@@ -67,19 +67,19 @@ public final class ClientProfile {
/**
* The handle of the primary frontend resource
*/
- private long mPrimaryUsingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ private int mPrimaryUsingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
/**
* List of the frontend handles that are used by the current client.
*/
- private Set<Long> mUsingFrontendHandles = new HashSet<>();
+ private Set<Integer> mUsingFrontendHandles = new HashSet<>();
/**
* List of the client ids that share frontend with the current client.
*/
private Set<Integer> mShareFeClientIds = new HashSet<>();
- private Set<Long> mUsingDemuxHandles = new HashSet<>();
+ private Set<Integer> mUsingDemuxHandles = new HashSet<>();
/**
* Client id sharee that has shared frontend with the current client.
@@ -89,7 +89,7 @@ public final class ClientProfile {
/**
* List of the Lnb handles that are used by the current client.
*/
- private Set<Long> mUsingLnbHandles = new HashSet<>();
+ private Set<Integer> mUsingLnbHandles = new HashSet<>();
/**
* List of the Cas system ids that are used by the current client.
@@ -184,7 +184,7 @@ public final class ClientProfile {
*
* @param frontendHandle being used.
*/
- public void useFrontend(long frontendHandle) {
+ public void useFrontend(int frontendHandle) {
mUsingFrontendHandles.add(frontendHandle);
}
@@ -193,14 +193,14 @@ public final class ClientProfile {
*
* @param frontendHandle being used.
*/
- public void setPrimaryFrontend(long frontendHandle) {
+ public void setPrimaryFrontend(int frontendHandle) {
mPrimaryUsingFrontendHandle = frontendHandle;
}
/**
* Get the primary frontend used by the client
*/
- public long getPrimaryFrontend() {
+ public int getPrimaryFrontend() {
return mPrimaryUsingFrontendHandle;
}
@@ -222,7 +222,7 @@ public final class ClientProfile {
mShareFeClientIds.remove(clientId);
}
- public Set<Long> getInUseFrontendHandles() {
+ public Set<Integer> getInUseFrontendHandles() {
return mUsingFrontendHandles;
}
@@ -253,14 +253,14 @@ public final class ClientProfile {
*
* @param demuxHandle the demux being used.
*/
- public void useDemux(long demuxHandle) {
+ public void useDemux(int demuxHandle) {
mUsingDemuxHandles.add(demuxHandle);
}
/**
* Get the set of demux handles in use.
*/
- public Set<Long> getInUseDemuxHandles() {
+ public Set<Integer> getInUseDemuxHandles() {
return mUsingDemuxHandles;
}
@@ -269,7 +269,7 @@ public final class ClientProfile {
*
* @param demuxHandle the demux handl being released.
*/
- public void releaseDemux(long demuxHandle) {
+ public void releaseDemux(int demuxHandle) {
mUsingDemuxHandles.remove(demuxHandle);
}
@@ -278,11 +278,11 @@ public final class ClientProfile {
*
* @param lnbHandle being used.
*/
- public void useLnb(long lnbHandle) {
+ public void useLnb(int lnbHandle) {
mUsingLnbHandles.add(lnbHandle);
}
- public Set<Long> getInUseLnbHandles() {
+ public Set<Integer> getInUseLnbHandles() {
return mUsingLnbHandles;
}
@@ -291,7 +291,7 @@ public final class ClientProfile {
*
* @param lnbHandle being released.
*/
- public void releaseLnb(long lnbHandle) {
+ public void releaseLnb(int lnbHandle) {
mUsingLnbHandles.remove(lnbHandle);
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java
index 14bc216d03ef..df735659c0fe 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java
@@ -69,7 +69,7 @@ public final class DemuxResource extends TunerResourceBasic {
public static class Builder extends TunerResourceBasic.Builder {
private int mFilterTypes;
- Builder(long handle) {
+ Builder(int handle) {
super(handle);
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java
index 953d97499c41..7ef75e3120c5 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java
@@ -42,7 +42,7 @@ public final class FrontendResource extends TunerResourceBasic {
/**
* An array to save all the FE handles under the same exclisive group.
*/
- private Set<Long> mExclusiveGroupMemberHandles = new HashSet<>();
+ private Set<Integer> mExclusiveGroupMemberHandles = new HashSet<>();
private FrontendResource(Builder builder) {
super(builder);
@@ -58,7 +58,7 @@ public final class FrontendResource extends TunerResourceBasic {
return mExclusiveGroupId;
}
- public Set<Long> getExclusiveGroupMemberFeHandles() {
+ public Set<Integer> getExclusiveGroupMemberFeHandles() {
return mExclusiveGroupMemberHandles;
}
@@ -67,7 +67,7 @@ public final class FrontendResource extends TunerResourceBasic {
*
* @param handle the handle to be added.
*/
- public void addExclusiveGroupMemberFeHandle(long handle) {
+ public void addExclusiveGroupMemberFeHandle(int handle) {
mExclusiveGroupMemberHandles.add(handle);
}
@@ -76,7 +76,7 @@ public final class FrontendResource extends TunerResourceBasic {
*
* @param handles the handle collection to be added.
*/
- public void addExclusiveGroupMemberFeHandles(Collection<Long> handles) {
+ public void addExclusiveGroupMemberFeHandles(Collection<Integer> handles) {
mExclusiveGroupMemberHandles.addAll(handles);
}
@@ -85,7 +85,7 @@ public final class FrontendResource extends TunerResourceBasic {
*
* @param id the id to be removed.
*/
- public void removeExclusiveGroupMemberFeId(long handle) {
+ public void removeExclusiveGroupMemberFeId(int handle) {
mExclusiveGroupMemberHandles.remove(handle);
}
@@ -104,7 +104,7 @@ public final class FrontendResource extends TunerResourceBasic {
@Type private int mType;
private int mExclusiveGroupId;
- Builder(long handle) {
+ Builder(int handle) {
super(handle);
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/LnbResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/LnbResource.java
index ab283713b15a..41cacea5f09e 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/LnbResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/LnbResource.java
@@ -37,7 +37,8 @@ public final class LnbResource extends TunerResourceBasic {
* Builder class for {@link LnbResource}.
*/
public static class Builder extends TunerResourceBasic.Builder {
- Builder(long handle) {
+
+ Builder(int handle) {
super(handle);
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceBasic.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceBasic.java
index d2ff8fa7c2e8..07853fc69055 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceBasic.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceBasic.java
@@ -28,7 +28,7 @@ public class TunerResourceBasic {
* Handle of the current resource. Should not be changed and should be aligned with the driver
* level implementation.
*/
- final long mHandle;
+ final int mHandle;
/**
* If the current resource is in use.
@@ -44,7 +44,7 @@ public class TunerResourceBasic {
this.mHandle = builder.mHandle;
}
- public long getHandle() {
+ public int getHandle() {
return mHandle;
}
@@ -78,9 +78,9 @@ public class TunerResourceBasic {
* Builder class for {@link TunerResourceBasic}.
*/
public static class Builder {
- private final long mHandle;
+ private final int mHandle;
- Builder(long handle) {
+ Builder(int handle) {
this.mHandle = handle;
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 45a40edfaf41..0afb049d31c7 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -78,18 +78,12 @@ public class TunerResourceManagerService extends SystemService implements IBinde
private static final int INVALID_FE_COUNT = -1;
- private static final int RESOURCE_ID_SHIFT = 24;
- private static final int RESOURCE_TYPE_SHIFT = 56;
- private static final long RESOURCE_COUNT_MASK = 0xffffff;
- private static final long RESOURCE_ID_MASK = 0xffffffff;
- private static final long RESOURCE_TYPE_MASK = 0xff;
-
// Map of the registered client profiles
private Map<Integer, ClientProfile> mClientProfiles = new HashMap<>();
private int mNextUnusedClientId = 0;
// Map of the current available frontend resources
- private Map<Long, FrontendResource> mFrontendResources = new HashMap<>();
+ private Map<Integer, FrontendResource> mFrontendResources = new HashMap<>();
// SparseIntArray of the max usable number for each frontend resource type
private SparseIntArray mFrontendMaxUsableNums = new SparseIntArray();
// SparseIntArray of the currently used number for each frontend resource type
@@ -99,15 +93,15 @@ public class TunerResourceManagerService extends SystemService implements IBinde
// Backups for the frontend resource maps for enabling testing with custom resource maps
// such as TunerTest.testHasUnusedFrontend1()
- private Map<Long, FrontendResource> mFrontendResourcesBackup = new HashMap<>();
+ private Map<Integer, FrontendResource> mFrontendResourcesBackup = new HashMap<>();
private SparseIntArray mFrontendMaxUsableNumsBackup = new SparseIntArray();
private SparseIntArray mFrontendUsedNumsBackup = new SparseIntArray();
private SparseIntArray mFrontendExistingNumsBackup = new SparseIntArray();
// Map of the current available demux resources
- private Map<Long, DemuxResource> mDemuxResources = new HashMap<>();
+ private Map<Integer, DemuxResource> mDemuxResources = new HashMap<>();
// Map of the current available lnb resources
- private Map<Long, LnbResource> mLnbResources = new HashMap<>();
+ private Map<Integer, LnbResource> mLnbResources = new HashMap<>();
// Map of the current available Cas resources
private Map<Integer, CasResource> mCasResources = new HashMap<>();
// Map of the current available CiCam resources
@@ -278,7 +272,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public void setLnbInfoList(long[] lnbHandles) throws RemoteException {
+ public void setLnbInfoList(int[] lnbHandles) throws RemoteException {
enforceTrmAccessPermission("setLnbInfoList");
if (lnbHandles == null) {
throw new RemoteException("Lnb handle list can't be null");
@@ -289,8 +283,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public boolean requestFrontend(
- @NonNull TunerFrontendRequest request, @NonNull long[] frontendHandle) {
+ public boolean requestFrontend(@NonNull TunerFrontendRequest request,
+ @NonNull int[] frontendHandle) {
enforceTunerAccessPermission("requestFrontend");
enforceTrmAccessPermission("requestFrontend");
if (frontendHandle == null) {
@@ -375,8 +369,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public boolean requestDemux(@NonNull TunerDemuxRequest request, @NonNull long[] demuxHandle)
- throws RemoteException {
+ public boolean requestDemux(@NonNull TunerDemuxRequest request,
+ @NonNull int[] demuxHandle) throws RemoteException {
enforceTunerAccessPermission("requestDemux");
enforceTrmAccessPermission("requestDemux");
if (demuxHandle == null) {
@@ -393,7 +387,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
@Override
public boolean requestDescrambler(@NonNull TunerDescramblerRequest request,
- @NonNull long[] descramblerHandle) throws RemoteException {
+ @NonNull int[] descramblerHandle) throws RemoteException {
enforceDescramblerAccessPermission("requestDescrambler");
enforceTrmAccessPermission("requestDescrambler");
if (descramblerHandle == null) {
@@ -410,7 +404,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
@Override
public boolean requestCasSession(@NonNull CasSessionRequest request,
- @NonNull long[] casSessionHandle) throws RemoteException {
+ @NonNull int[] casSessionHandle) throws RemoteException {
enforceTrmAccessPermission("requestCasSession");
if (casSessionHandle == null) {
throw new RemoteException("casSessionHandle can't be null");
@@ -425,8 +419,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public boolean requestCiCam(@NonNull TunerCiCamRequest request, @NonNull long[] ciCamHandle)
- throws RemoteException {
+ public boolean requestCiCam(@NonNull TunerCiCamRequest request,
+ @NonNull int[] ciCamHandle) throws RemoteException {
enforceTrmAccessPermission("requestCiCam");
if (ciCamHandle == null) {
throw new RemoteException("ciCamHandle can't be null");
@@ -441,7 +435,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull long[] lnbHandle)
+ public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull int[] lnbHandle)
throws RemoteException {
enforceTunerAccessPermission("requestLnb");
enforceTrmAccessPermission("requestLnb");
@@ -458,7 +452,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public void releaseFrontend(long frontendHandle, int clientId) throws RemoteException {
+ public void releaseFrontend(int frontendHandle, int clientId) throws RemoteException {
enforceTunerAccessPermission("releaseFrontend");
enforceTrmAccessPermission("releaseFrontend");
if (!validateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND,
@@ -487,7 +481,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public void releaseDemux(long demuxHandle, int clientId) throws RemoteException {
+ public void releaseDemux(int demuxHandle, int clientId) throws RemoteException {
enforceTunerAccessPermission("releaseDemux");
enforceTrmAccessPermission("releaseDemux");
if (DEBUG) {
@@ -518,7 +512,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public void releaseDescrambler(long descramblerHandle, int clientId) {
+ public void releaseDescrambler(int descramblerHandle, int clientId) {
enforceTunerAccessPermission("releaseDescrambler");
enforceTrmAccessPermission("releaseDescrambler");
if (DEBUG) {
@@ -527,7 +521,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public void releaseCasSession(long casSessionHandle, int clientId) throws RemoteException {
+ public void releaseCasSession(int casSessionHandle, int clientId) throws RemoteException {
enforceTrmAccessPermission("releaseCasSession");
if (!validateResourceHandle(
TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, casSessionHandle)) {
@@ -551,7 +545,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public void releaseCiCam(long ciCamHandle, int clientId) throws RemoteException {
+ public void releaseCiCam(int ciCamHandle, int clientId) throws RemoteException {
enforceTrmAccessPermission("releaseCiCam");
if (!validateResourceHandle(
TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, ciCamHandle)) {
@@ -579,7 +573,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
- public void releaseLnb(long lnbHandle, int clientId) throws RemoteException {
+ public void releaseLnb(int lnbHandle, int clientId) throws RemoteException {
enforceTunerAccessPermission("releaseLnb");
enforceTrmAccessPermission("releaseLnb");
if (!validateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB, lnbHandle)) {
@@ -877,7 +871,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
// A set to record the frontends pending on updating. Ids will be removed
// from this set once its updating finished. Any frontend left in this set when all
// the updates are done will be removed from mFrontendResources.
- Set<Long> updatingFrontendHandles = new HashSet<>(getFrontendResources().keySet());
+ Set<Integer> updatingFrontendHandles = new HashSet<>(getFrontendResources().keySet());
// Update frontendResources map and other mappings accordingly
for (int i = 0; i < infos.length; i++) {
@@ -896,7 +890,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
}
- for (long removingHandle : updatingFrontendHandles) {
+ for (int removingHandle : updatingFrontendHandles) {
// update the exclusive group id member list
removeFrontendResource(removingHandle);
}
@@ -914,7 +908,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
// A set to record the demuxes pending on updating. Ids will be removed
// from this set once its updating finished. Any demux left in this set when all
// the updates are done will be removed from mDemuxResources.
- Set<Long> updatingDemuxHandles = new HashSet<>(getDemuxResources().keySet());
+ Set<Integer> updatingDemuxHandles = new HashSet<>(getDemuxResources().keySet());
// Update demuxResources map and other mappings accordingly
for (int i = 0; i < infos.length; i++) {
@@ -932,13 +926,13 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
}
- for (long removingHandle : updatingDemuxHandles) {
+ for (int removingHandle : updatingDemuxHandles) {
// update the exclusive group id member list
removeDemuxResource(removingHandle);
}
}
@VisibleForTesting
- protected void setLnbInfoListInternal(long[] lnbHandles) {
+ protected void setLnbInfoListInternal(int[] lnbHandles) {
if (DEBUG) {
for (int i = 0; i < lnbHandles.length; i++) {
Slog.d(TAG, "updateLnbInfo(lnbHanle=" + lnbHandles[i] + ")");
@@ -948,7 +942,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
// A set to record the Lnbs pending on updating. Handles will be removed
// from this set once its updating finished. Any lnb left in this set when all
// the updates are done will be removed from mLnbResources.
- Set<Long> updatingLnbHandles = new HashSet<>(getLnbResources().keySet());
+ Set<Integer> updatingLnbHandles = new HashSet<>(getLnbResources().keySet());
// Update lnbResources map and other mappings accordingly
for (int i = 0; i < lnbHandles.length; i++) {
@@ -964,7 +958,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
}
- for (long removingHandle : updatingLnbHandles) {
+ for (int removingHandle : updatingLnbHandles) {
removeLnbResource(removingHandle);
}
}
@@ -1009,7 +1003,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@VisibleForTesting
- protected boolean requestFrontendInternal(TunerFrontendRequest request, long[] frontendHandle) {
+ protected boolean requestFrontendInternal(TunerFrontendRequest request, int[] frontendHandle) {
if (DEBUG) {
Slog.d(TAG, "requestFrontend(request=" + request + ")");
}
@@ -1021,8 +1015,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
return false;
}
clientPriorityUpdateOnRequest(requestClient);
- long grantingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- long inUseLowestPriorityFrHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ int grantingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ int inUseLowestPriorityFrHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
// Priority max value is 1000
int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
boolean isRequestFromSameProcess = false;
@@ -1056,7 +1050,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
// we need to check the max used num if the target frontend type is not
// currently in primary use (and simply blocked due to exclusive group)
ClientProfile targetOwnerProfile = getClientProfile(fr.getOwnerClientId());
- long primaryFeId = targetOwnerProfile.getPrimaryFrontend();
+ int primaryFeId = targetOwnerProfile.getPrimaryFrontend();
FrontendResource primaryFe = getFrontendResource(primaryFeId);
if (fr.getType() != primaryFe.getType()
&& isFrontendMaxNumUseReached(fr.getType())) {
@@ -1108,7 +1102,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
getClientProfile(shareeFeClientId).stopSharingFrontend(selfClientId);
getClientProfile(selfClientId).releaseFrontend();
}
- for (long feId : getClientProfile(targetClientId).getInUseFrontendHandles()) {
+ for (int feId : getClientProfile(targetClientId).getInUseFrontendHandles()) {
getClientProfile(selfClientId).useFrontend(feId);
}
getClientProfile(selfClientId).setShareeFeClientId(targetClientId);
@@ -1123,14 +1117,14 @@ public class TunerResourceManagerService extends SystemService implements IBinde
currentOwnerProfile.stopSharingFrontend(newOwnerId);
newOwnerProfile.setShareeFeClientId(ClientProfile.INVALID_RESOURCE_ID);
currentOwnerProfile.setShareeFeClientId(newOwnerId);
- for (long inUseHandle : newOwnerProfile.getInUseFrontendHandles()) {
+ for (int inUseHandle : newOwnerProfile.getInUseFrontendHandles()) {
getFrontendResource(inUseHandle).setOwner(newOwnerId);
}
// change the primary frontend
newOwnerProfile.setPrimaryFrontend(currentOwnerProfile.getPrimaryFrontend());
currentOwnerProfile.setPrimaryFrontend(TunerResourceManager.INVALID_RESOURCE_HANDLE);
// double check there is no other resources tied to the previous owner
- for (long inUseHandle : currentOwnerProfile.getInUseFrontendHandles()) {
+ for (int inUseHandle : currentOwnerProfile.getInUseFrontendHandles()) {
int ownerId = getFrontendResource(inUseHandle).getOwnerClientId();
if (ownerId != newOwnerId) {
Slog.e(TAG, "something is wrong in transferFeOwner:" + inUseHandle
@@ -1162,8 +1156,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
ClientProfile currentOwnerProfile = getClientProfile(currentOwnerId);
ClientProfile newOwnerProfile = getClientProfile(newOwnerId);
- Set<Long> inUseLnbHandles = new HashSet<>();
- for (Long lnbHandle : currentOwnerProfile.getInUseLnbHandles()) {
+ Set<Integer> inUseLnbHandles = new HashSet<>();
+ for (Integer lnbHandle : currentOwnerProfile.getInUseLnbHandles()) {
// link lnb handle to the new profile
newOwnerProfile.useLnb(lnbHandle);
@@ -1175,7 +1169,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
// unlink lnb handles from the original owner
- for (Long lnbHandle : inUseLnbHandles) {
+ for (Integer lnbHandle : inUseLnbHandles) {
currentOwnerProfile.releaseLnb(lnbHandle);
}
@@ -1198,7 +1192,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@VisibleForTesting
- protected boolean requestLnbInternal(TunerLnbRequest request, long[] lnbHandle) {
+ protected boolean requestLnbInternal(TunerLnbRequest request, int[] lnbHandle) {
if (DEBUG) {
Slog.d(TAG, "requestLnb(request=" + request + ")");
}
@@ -1206,8 +1200,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
lnbHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
ClientProfile requestClient = getClientProfile(request.clientId);
clientPriorityUpdateOnRequest(requestClient);
- long grantingLnbHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- long inUseLowestPriorityLnbHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ int grantingLnbHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ int inUseLowestPriorityLnbHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
// Priority max value is 1000
int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
boolean isRequestFromSameProcess = false;
@@ -1254,8 +1248,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@VisibleForTesting
- protected boolean requestCasSessionInternal(
- CasSessionRequest request, long[] casSessionHandle) {
+ protected boolean requestCasSessionInternal(CasSessionRequest request, int[] casSessionHandle) {
if (DEBUG) {
Slog.d(TAG, "requestCasSession(request=" + request + ")");
}
@@ -1308,7 +1301,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@VisibleForTesting
- protected boolean requestCiCamInternal(TunerCiCamRequest request, long[] ciCamHandle) {
+ protected boolean requestCiCamInternal(TunerCiCamRequest request, int[] ciCamHandle) {
if (DEBUG) {
Slog.d(TAG, "requestCiCamInternal(TunerCiCamRequest=" + request + ")");
}
@@ -1331,7 +1324,6 @@ public class TunerResourceManagerService extends SystemService implements IBinde
ciCamHandle[0] = generateResourceHandle(
TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, ciCam.getCiCamId());
updateCiCamClientMappingOnNewGrant(request.ciCamId, request.clientId);
- Slog.e(TAG, "requestCiCamInternal(ciCamHandle=" + ciCamHandle[0] + ")");
return true;
}
for (int ownerId : ciCam.getOwnerClientIds()) {
@@ -1357,7 +1349,6 @@ public class TunerResourceManagerService extends SystemService implements IBinde
ciCamHandle[0] = generateResourceHandle(
TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, ciCam.getCiCamId());
updateCiCamClientMappingOnNewGrant(request.ciCamId, request.clientId);
- Slog.e(TAG, "requestCiCamInternal(ciCamHandle=" + ciCamHandle[0] + ")");
return true;
}
return false;
@@ -1441,7 +1432,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@VisibleForTesting
- protected boolean requestDemuxInternal(TunerDemuxRequest request, long[] demuxHandle) {
+ protected boolean requestDemuxInternal(TunerDemuxRequest request, int[] demuxHandle) {
if (DEBUG) {
Slog.d(TAG, "requestDemux(request=" + request + ")");
}
@@ -1464,8 +1455,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
clientPriorityUpdateOnRequest(requestClient);
- long grantingDemuxHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- long inUseLowestPriorityDrHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ int grantingDemuxHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ int inUseLowestPriorityDrHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
// Priority max value is 1000
int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
boolean isRequestFromSameProcess = false;
@@ -1559,7 +1550,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
@VisibleForTesting
protected boolean requestDescramblerInternal(
- TunerDescramblerRequest request, long[] descramblerHandle) {
+ TunerDescramblerRequest request, int[] descramblerHandle) {
if (DEBUG) {
Slog.d(TAG, "requestDescrambler(request=" + request + ")");
}
@@ -1878,20 +1869,20 @@ public class TunerResourceManagerService extends SystemService implements IBinde
return false;
}
- private void updateFrontendClientMappingOnNewGrant(long grantingHandle, int ownerClientId) {
+ private void updateFrontendClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
FrontendResource grantingFrontend = getFrontendResource(grantingHandle);
ClientProfile ownerProfile = getClientProfile(ownerClientId);
grantingFrontend.setOwner(ownerClientId);
increFrontendNum(mFrontendUsedNums, grantingFrontend.getType());
ownerProfile.useFrontend(grantingHandle);
- for (long exclusiveGroupMember : grantingFrontend.getExclusiveGroupMemberFeHandles()) {
+ for (int exclusiveGroupMember : grantingFrontend.getExclusiveGroupMemberFeHandles()) {
getFrontendResource(exclusiveGroupMember).setOwner(ownerClientId);
ownerProfile.useFrontend(exclusiveGroupMember);
}
ownerProfile.setPrimaryFrontend(grantingHandle);
}
- private void updateDemuxClientMappingOnNewGrant(long grantingHandle, int ownerClientId) {
+ private void updateDemuxClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
DemuxResource grantingDemux = getDemuxResource(grantingHandle);
if (grantingDemux != null) {
ClientProfile ownerProfile = getClientProfile(ownerClientId);
@@ -1906,7 +1897,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
ownerProfile.releaseDemux(releasingDemux.getHandle());
}
- private void updateLnbClientMappingOnNewGrant(long grantingHandle, int ownerClientId) {
+ private void updateLnbClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
LnbResource grantingLnb = getLnbResource(grantingHandle);
ClientProfile ownerProfile = getClientProfile(ownerClientId);
grantingLnb.setOwner(ownerClientId);
@@ -1990,23 +1981,23 @@ public class TunerResourceManagerService extends SystemService implements IBinde
@VisibleForTesting
@Nullable
- protected FrontendResource getFrontendResource(long frontendHandle) {
+ protected FrontendResource getFrontendResource(int frontendHandle) {
return mFrontendResources.get(frontendHandle);
}
@VisibleForTesting
- protected Map<Long, FrontendResource> getFrontendResources() {
+ protected Map<Integer, FrontendResource> getFrontendResources() {
return mFrontendResources;
}
@VisibleForTesting
@Nullable
- protected DemuxResource getDemuxResource(long demuxHandle) {
+ protected DemuxResource getDemuxResource(int demuxHandle) {
return mDemuxResources.get(demuxHandle);
}
@VisibleForTesting
- protected Map<Long, DemuxResource> getDemuxResources() {
+ protected Map<Integer, DemuxResource> getDemuxResources() {
return mDemuxResources;
}
@@ -2065,8 +2056,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
}
- private void replaceFeResourceMap(
- Map<Long, FrontendResource> srcMap, Map<Long, FrontendResource> dstMap) {
+ private void replaceFeResourceMap(Map<Integer, FrontendResource> srcMap, Map<Integer,
+ FrontendResource> dstMap) {
if (dstMap != null) {
dstMap.clear();
if (srcMap != null && srcMap.size() > 0) {
@@ -2119,7 +2110,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
if (fe.getExclusiveGroupId() == newFe.getExclusiveGroupId()) {
newFe.addExclusiveGroupMemberFeHandle(fe.getHandle());
newFe.addExclusiveGroupMemberFeHandles(fe.getExclusiveGroupMemberFeHandles());
- for (long excGroupmemberFeHandle : fe.getExclusiveGroupMemberFeHandles()) {
+ for (int excGroupmemberFeHandle : fe.getExclusiveGroupMemberFeHandles()) {
getFrontendResource(excGroupmemberFeHandle)
.addExclusiveGroupMemberFeHandle(newFe.getHandle());
}
@@ -2137,7 +2128,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
mDemuxResources.put(newDemux.getHandle(), newDemux);
}
- private void removeFrontendResource(long removingHandle) {
+ private void removeFrontendResource(int removingHandle) {
FrontendResource fe = getFrontendResource(removingHandle);
if (fe == null) {
return;
@@ -2149,7 +2140,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
clearFrontendAndClientMapping(ownerClient);
}
- for (long excGroupmemberFeHandle : fe.getExclusiveGroupMemberFeHandles()) {
+ for (int excGroupmemberFeHandle : fe.getExclusiveGroupMemberFeHandles()) {
getFrontendResource(excGroupmemberFeHandle)
.removeExclusiveGroupMemberFeId(fe.getHandle());
}
@@ -2157,7 +2148,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
mFrontendResources.remove(removingHandle);
}
- private void removeDemuxResource(long removingHandle) {
+ private void removeDemuxResource(int removingHandle) {
DemuxResource demux = getDemuxResource(removingHandle);
if (demux == null) {
return;
@@ -2170,12 +2161,12 @@ public class TunerResourceManagerService extends SystemService implements IBinde
@VisibleForTesting
@Nullable
- protected LnbResource getLnbResource(long lnbHandle) {
+ protected LnbResource getLnbResource(int lnbHandle) {
return mLnbResources.get(lnbHandle);
}
@VisibleForTesting
- protected Map<Long, LnbResource> getLnbResources() {
+ protected Map<Integer, LnbResource> getLnbResources() {
return mLnbResources;
}
@@ -2184,7 +2175,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
mLnbResources.put(newLnb.getHandle(), newLnb);
}
- private void removeLnbResource(long removingHandle) {
+ private void removeLnbResource(int removingHandle) {
LnbResource lnb = getLnbResource(removingHandle);
if (lnb == null) {
return;
@@ -2288,7 +2279,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
if (profile == null) {
return;
}
- for (Long feId : profile.getInUseFrontendHandles()) {
+ for (Integer feId : profile.getInUseFrontendHandles()) {
FrontendResource fe = getFrontendResource(feId);
int ownerClientId = fe.getOwnerClientId();
if (ownerClientId == profile.getId()) {
@@ -2299,9 +2290,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde
if (ownerClientProfile != null) {
ownerClientProfile.stopSharingFrontend(profile.getId());
}
+
}
- long primaryFeId = profile.getPrimaryFrontend();
+ int primaryFeId = profile.getPrimaryFrontend();
if (primaryFeId != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
FrontendResource primaryFe = getFrontendResource(primaryFeId);
if (primaryFe != null) {
@@ -2318,7 +2310,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
return;
}
// Clear Lnb
- for (Long lnbHandle : profile.getInUseLnbHandles()) {
+ for (Integer lnbHandle : profile.getInUseLnbHandles()) {
getLnbResource(lnbHandle).removeOwner();
}
// Clear Cas
@@ -2330,7 +2322,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
getCiCamResource(profile.getInUseCiCamId()).removeOwner(profile.getId());
}
// Clear Demux
- for (Long demuxHandle : profile.getInUseDemuxHandles()) {
+ for (Integer demuxHandle : profile.getInUseDemuxHandles()) {
getDemuxResource(demuxHandle).removeOwner();
}
// Clear Frontend
@@ -2343,31 +2335,24 @@ public class TunerResourceManagerService extends SystemService implements IBinde
return mClientProfiles.keySet().contains(clientId);
}
- /**
- * Generate resource handle for resourceType and resourceId
- * Resource Handle Allotment : 64 bits (long)
- * 8 bits - resourceType
- * 32 bits - resourceId
- * 24 bits - resourceRequestCount
- */
- private long generateResourceHandle(
+ private int generateResourceHandle(
@TunerResourceManager.TunerResourceType int resourceType, int resourceId) {
- return (resourceType & RESOURCE_TYPE_MASK) << RESOURCE_TYPE_SHIFT
- | (resourceId & RESOURCE_ID_MASK) << RESOURCE_ID_SHIFT
- | (mResourceRequestCount++ & RESOURCE_COUNT_MASK);
+ return (resourceType & 0x000000ff) << 24
+ | (resourceId << 16)
+ | (mResourceRequestCount++ & 0xffff);
}
@VisibleForTesting
- protected int getResourceIdFromHandle(long resourceHandle) {
+ protected int getResourceIdFromHandle(int resourceHandle) {
if (resourceHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
- return (int) resourceHandle;
+ return resourceHandle;
}
- return (int) ((resourceHandle >> RESOURCE_ID_SHIFT) & RESOURCE_ID_MASK);
+ return (resourceHandle & 0x00ff0000) >> 16;
}
- private boolean validateResourceHandle(int resourceType, long resourceHandle) {
+ private boolean validateResourceHandle(int resourceType, int resourceHandle) {
if (resourceHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE
- || ((resourceHandle >> RESOURCE_TYPE_SHIFT) & RESOURCE_TYPE_MASK) != resourceType) {
+ || ((resourceHandle & 0xff000000) >> 24) != resourceType) {
return false;
}
return true;
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index f2ad5b95fe5e..dd16d2433a64 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -487,25 +487,37 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
HalVibration performHapticFeedbackInternal(
int uid, int deviceId, String opPkg, int constant, String reason,
IBinder token, int flags, int privFlags) {
+
+ // Make sure we report the constant id in the requested haptic feedback reason.
+ reason = "performHapticFeedback(constant=" + constant + "): " + reason;
+
HapticFeedbackVibrationProvider hapticVibrationProvider = getHapticVibrationProvider();
if (hapticVibrationProvider == null) {
Slog.e(TAG, "performHapticFeedback; haptic vibration provider not ready.");
+ logAndRecordPerformHapticFeedbackAttempt(uid, deviceId, opPkg, reason,
+ Vibration.Status.IGNORED_ERROR_SCHEDULING);
return null;
}
+
if (hapticVibrationProvider.isRestrictedHapticFeedback(constant)
&& !hasPermission(android.Manifest.permission.VIBRATE_SYSTEM_CONSTANTS)) {
Slog.w(TAG, "performHapticFeedback; no permission for system constant " + constant);
+ logAndRecordPerformHapticFeedbackAttempt(uid, deviceId, opPkg, reason,
+ Vibration.Status.IGNORED_MISSING_PERMISSION);
return null;
}
+
VibrationEffect effect = hapticVibrationProvider.getVibrationForHapticFeedback(constant);
if (effect == null) {
Slog.w(TAG, "performHapticFeedback; vibration absent for constant " + constant);
+ logAndRecordPerformHapticFeedbackAttempt(uid, deviceId, opPkg, reason,
+ Vibration.Status.IGNORED_UNSUPPORTED);
return null;
}
+
CombinedVibration vib = CombinedVibration.createParallel(effect);
VibrationAttributes attrs = hapticVibrationProvider.getVibrationAttributesForHapticFeedback(
constant, flags, privFlags);
- reason = "performHapticFeedback(constant=" + constant + "): " + reason;
VibratorFrameworkStatsLogger.logPerformHapticsFeedbackIfKeyboard(uid, constant);
return vibrateWithoutPermissionCheck(uid, deviceId, opPkg, vib, attrs, reason, token);
}
@@ -563,22 +575,27 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
private HalVibration vibrateInternal(int uid, int deviceId, String opPkg,
@NonNull CombinedVibration effect, @NonNull VibrationAttributes attrs,
String reason, IBinder token) {
+ Vibration.CallerInfo callerInfo =
+ new Vibration.CallerInfo(attrs, uid, deviceId, opPkg, reason);
if (token == null) {
Slog.e(TAG, "token must not be null");
+ logAndRecordVibrationAttempt(effect, callerInfo, Vibration.Status.IGNORED_ERROR_TOKEN);
return null;
}
if (effect.hasVendorEffects()
&& !hasPermission(android.Manifest.permission.VIBRATE_VENDOR_EFFECTS)) {
- Slog.w(TAG, "vibrate; no permission for vendor effects");
+ Slog.e(TAG, "vibrate; no permission for vendor effects");
+ logAndRecordVibrationAttempt(effect, callerInfo,
+ Vibration.Status.IGNORED_MISSING_PERMISSION);
return null;
}
enforceUpdateAppOpsStatsPermission(uid);
if (!isEffectValid(effect)) {
+ logAndRecordVibrationAttempt(effect, callerInfo, Vibration.Status.IGNORED_UNSUPPORTED);
return null;
}
// Create Vibration.Stats as close to the received request as possible, for tracking.
- HalVibration vib = new HalVibration(token, effect,
- new Vibration.CallerInfo(attrs, uid, deviceId, opPkg, reason));
+ HalVibration vib = new HalVibration(token, effect, callerInfo);
fillVibrationFallbacks(vib, effect);
if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
@@ -973,6 +990,22 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
return new Vibration.EndInfo(Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
}
+ private void logAndRecordPerformHapticFeedbackAttempt(int uid, int deviceId, String opPkg,
+ String reason, Vibration.Status status) {
+ Vibration.CallerInfo callerInfo = new Vibration.CallerInfo(
+ VibrationAttributes.createForUsage(VibrationAttributes.USAGE_UNKNOWN),
+ uid, deviceId, opPkg, reason);
+ logAndRecordVibrationAttempt(/* effect= */ null, callerInfo, status);
+ }
+
+ private void logAndRecordVibrationAttempt(@Nullable CombinedVibration effect,
+ Vibration.CallerInfo callerInfo, Vibration.Status status) {
+ logAndRecordVibration(
+ new Vibration.DebugInfo(status, new VibrationStats(),
+ effect, /* originalEffect= */ null, VibrationScaler.SCALE_NONE,
+ VibrationScaler.ADAPTIVE_SCALE_NONE, callerInfo));
+ }
+
private void logAndRecordVibration(Vibration.DebugInfo info) {
info.logMetrics(mFrameworkStatsLogger);
logVibrationStatus(info.mCallerInfo.uid, info.mCallerInfo.attrs, info.mStatus);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3d5808210e00..5e030661c668 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4626,7 +4626,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return kept;
}
- /** Update default (global) configuration and notify listeners about changes. */
+ /**
+ * Updates default (global) configuration and notifies listeners about changes.
+ *
+ * @param values The new configuration. It must always be a new instance from the caller, and
+ * it won't be modified after calling this method.
+ */
int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
boolean persistent, int userId) {
@@ -4640,24 +4645,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
ProtoLog.i(WM_DEBUG_CONFIGURATION, "Updating global configuration "
+ "to: %s", values);
writeConfigurationChanged(changes);
- FrameworkStatsLog.write(FrameworkStatsLog.RESOURCE_CONFIGURATION_CHANGED,
- values.colorMode,
- values.densityDpi,
- values.fontScale,
- values.hardKeyboardHidden,
- values.keyboard,
- values.keyboardHidden,
- values.mcc,
- values.mnc,
- values.navigation,
- values.navigationHidden,
- values.orientation,
- values.screenHeightDp,
- values.screenLayout,
- values.screenWidthDp,
- values.smallestScreenWidthDp,
- values.touchscreen,
- values.uiMode);
// Note: certain tests currently run as platform_app which is not allowed
// to set debug system properties. To ensure that system properties are set
@@ -4705,13 +4692,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// resources have that config before following boot code is executed.
mSystemThread.applyConfigurationToResources(mTempConfig);
- if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
- final Message msg = PooledLambda.obtainMessage(
- ActivityTaskManagerService::sendPutConfigurationForUserMsg,
- this, userId, new Configuration(mTempConfig));
- mH.sendMessage(msg);
- }
-
SparseArray<WindowProcessController> pidMap = mProcessMap.getPidMap();
for (int i = pidMap.size() - 1; i >= 0; i--) {
final int pid = pidMap.keyAt(i);
@@ -4721,19 +4701,32 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
app.onConfigurationChanged(mTempConfig);
}
- final Message msg = PooledLambda.obtainMessage(
- ActivityManagerInternal::broadcastGlobalConfigurationChanged,
- mAmInternal, changes, initLocale);
- mH.sendMessage(msg);
+ final Configuration configurationForSettings =
+ persistent && Settings.System.hasInterestingConfigurationChanges(changes)
+ ? new Configuration(mTempConfig) : null;
+ mH.post(() -> {
+ FrameworkStatsLog.write(FrameworkStatsLog.RESOURCE_CONFIGURATION_CHANGED,
+ values.colorMode, values.densityDpi, values.fontScale,
+ values.hardKeyboardHidden, values.keyboard, values.keyboardHidden,
+ values.mcc, values.mnc, values.navigation, values.navigationHidden,
+ values.orientation, values.screenHeightDp, values.screenLayout,
+ values.screenWidthDp, values.smallestScreenWidthDp, values.touchscreen,
+ values.uiMode);
+ if ((changes & ActivityInfo.CONFIG_ORIENTATION) != 0) {
+ FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_ORIENTATION_CHANGED,
+ values.orientation);
+ }
+ if (configurationForSettings != null) {
+ Settings.System.putConfigurationForUser(mContext.getContentResolver(),
+ configurationForSettings, userId);
+ }
+ mAmInternal.broadcastGlobalConfigurationChanged(changes, initLocale);
+ });
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RootConfigChange");
// Update stored global config and notify everyone about the change.
mRootWindowContainer.onConfigurationChanged(mTempConfig);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- if ((changes & ActivityInfo.CONFIG_ORIENTATION) != 0) {
- FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_ORIENTATION_CHANGED,
- values.orientation);
- }
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return changes;
@@ -4883,11 +4876,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mWindowManager.setEventDispatching(booted && !mShuttingDown);
}
- private void sendPutConfigurationForUserMsg(int userId, Configuration config) {
- final ContentResolver resolver = mContext.getContentResolver();
- Settings.System.putConfigurationForUser(resolver, config, userId);
- }
-
boolean isActivityStartsLoggingEnabled() {
return mAmInternal.isActivityStartsLoggingEnabled();
}
diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java
index 44276055f346..cd795ae167ea 100644
--- a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java
@@ -233,7 +233,8 @@ class AppCompatAspectRatioOverrides {
return mAppCompatConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled();
}
- private float getDisplaySizeMinAspectRatio() {
+ @VisibleForTesting
+ float getDisplaySizeMinAspectRatio() {
final DisplayArea displayArea = mActivityRecord.getDisplayArea();
if (displayArea == null) {
return mActivityRecord.info.getMinAspectRatio();
@@ -270,7 +271,6 @@ class AppCompatAspectRatioOverrides {
return !mAllowUserAspectRatioOverrideOptProp.isFalse();
}
- @VisibleForTesting
int getUserMinAspectRatioOverrideCode() {
try {
return mActivityRecord.mAtmService.getPackageManager()
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
index 94ad61f3f4de..e3ff85171c0e 100644
--- a/services/core/java/com/android/server/wm/AppCompatUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -187,6 +187,8 @@ final class AppCompatUtils {
appCompatTaskInfo.setTopActivityLetterboxed(top.areBoundsLetterboxed());
appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode = top.mAppCompatController
.getAppCompatCameraOverrides().getFreeformCameraCompatMode();
+ appCompatTaskInfo.setHasMinAspectRatioOverride(top.mAppCompatController
+ .getDesktopAppCompatAspectRatioPolicy().hasMinAspectRatioOverride(task));
}
/**
diff --git a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
index 8477c6c5b1da..b936556c3264 100644
--- a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
+++ b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
@@ -258,7 +258,7 @@ public class DesktopAppCompatAspectRatioPolicy {
* Whether we should apply the user aspect ratio override to the min aspect ratio for the
* current app.
*/
- private boolean shouldApplyUserMinAspectRatioOverride(@NonNull Task task) {
+ boolean shouldApplyUserMinAspectRatioOverride(@NonNull Task task) {
if (!shouldEnableUserAspectRatioSettings(task)) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index 8f1828d741c5..c3db7dd7bfaf 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -16,31 +16,28 @@
package com.android.server.wm;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.isFixedOrientation;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static com.android.server.wm.AppCompatConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
-import static com.android.server.wm.AppCompatConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
-import static com.android.server.wm.AppCompatUtils.computeAspectRatio;
import static com.android.server.wm.LaunchParamsUtil.applyLayoutGravity;
import static com.android.server.wm.LaunchParamsUtil.calculateLayoutBounds;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
-import android.app.AppCompatTaskInfo;
import android.app.TaskInfo;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
+import android.content.pm.ActivityInfo.ScreenOrientation;
+import android.content.pm.ActivityInfo.WindowLayout;
import android.graphics.Rect;
import android.os.SystemProperties;
import android.util.Size;
import android.view.Gravity;
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wm.utils.DesktopModeFlagsUtil;
import java.util.function.Consumer;
@@ -60,7 +57,7 @@ public final class DesktopModeBoundsCalculator {
* Updates launch bounds for an activity with respect to its activity options, window layout,
* android manifest and task configuration.
*/
- static void updateInitialBounds(@NonNull Task task, @Nullable ActivityInfo.WindowLayout layout,
+ static void updateInitialBounds(@NonNull Task task, @Nullable WindowLayout layout,
@Nullable ActivityRecord activity, @Nullable ActivityOptions options,
@NonNull Rect outBounds, @NonNull Consumer<String> logger) {
// Use stable frame instead of raw frame to avoid launching freeform windows on top of
@@ -98,7 +95,8 @@ public final class DesktopModeBoundsCalculator {
* fullscreen size, aspect ratio, orientation and resizability to calculate an area this is
* compatible with the applications previous configuration.
*/
- private static @NonNull Rect calculateInitialBounds(@NonNull Task task,
+ @NonNull
+ private static Rect calculateInitialBounds(@NonNull Task task,
@NonNull ActivityRecord activity, @NonNull Rect stableBounds
) {
final TaskInfo taskInfo = task.getTaskInfo();
@@ -116,18 +114,19 @@ public final class DesktopModeBoundsCalculator {
// applied.
return centerInScreen(idealSize, screenBounds);
}
- // TODO(b/353457301): Replace with app compat aspect ratio method when refactoring complete.
- float appAspectRatio = calculateAspectRatio(task, activity);
+ final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
+ activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ float appAspectRatio = desktopAppCompatAspectRatioPolicy.calculateAspectRatio(task);
final float tdaWidth = stableBounds.width();
final float tdaHeight = stableBounds.height();
- final int activityOrientation = activity.getOverrideOrientation();
+ final int activityOrientation = getActivityOrientation(activity, task);
final Size initialSize = switch (taskInfo.configuration.orientation) {
case ORIENTATION_LANDSCAPE -> {
// Device in landscape orientation.
if (appAspectRatio == 0) {
appAspectRatio = 1;
}
- if (taskInfo.isResizeable) {
+ if (canChangeAspectRatio(desktopAppCompatAspectRatioPolicy, taskInfo, task)) {
if (isFixedOrientationPortrait(activityOrientation)) {
// For portrait resizeable activities, respect apps fullscreen width but
// apply ideal size height.
@@ -139,14 +138,13 @@ public final class DesktopModeBoundsCalculator {
}
// If activity is unresizeable, regardless of orientation, calculate maximum size
// (within the ideal size) maintaining original aspect ratio.
- yield maximizeSizeGivenAspectRatio(
- activity.getOverrideOrientation(), idealSize, appAspectRatio);
+ yield maximizeSizeGivenAspectRatio(activityOrientation, idealSize, appAspectRatio);
}
case ORIENTATION_PORTRAIT -> {
// Device in portrait orientation.
final int customPortraitWidthForLandscapeApp = screenBounds.width()
- (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
- if (taskInfo.isResizeable) {
+ if (canChangeAspectRatio(desktopAppCompatAspectRatioPolicy, taskInfo, task)) {
if (isFixedOrientationLandscape(activityOrientation)) {
if (appAspectRatio == 0) {
appAspectRatio = tdaWidth / (tdaWidth - 1);
@@ -180,11 +178,38 @@ public final class DesktopModeBoundsCalculator {
}
/**
+ * Whether the activity's aspect ratio can be changed or if it should be maintained as if it was
+ * unresizeable.
+ */
+ private static boolean canChangeAspectRatio(
+ @NonNull DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy,
+ @NonNull TaskInfo taskInfo, @NonNull Task task) {
+ return taskInfo.isResizeable
+ && !desktopAppCompatAspectRatioPolicy.hasMinAspectRatioOverride(task);
+ }
+
+ private static @ScreenOrientation int getActivityOrientation(
+ @NonNull ActivityRecord activity, @NonNull Task task) {
+ final int activityOrientation = activity.getOverrideOrientation();
+ final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
+ activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ if (desktopAppCompatAspectRatioPolicy.shouldApplyUserMinAspectRatioOverride(task)
+ && (!isFixedOrientation(activityOrientation)
+ || activityOrientation == SCREEN_ORIENTATION_LOCKED)) {
+ // If a user aspect ratio override should be applied, treat the activity as portrait if
+ // it has not specified a fix orientation.
+ return SCREEN_ORIENTATION_PORTRAIT;
+ }
+ return activityOrientation;
+ }
+
+ /**
* Calculates the largest size that can fit in a given area while maintaining a specific aspect
* ratio.
*/
- private static @NonNull Size maximizeSizeGivenAspectRatio(
- @ActivityInfo.ScreenOrientation int orientation,
+ @NonNull
+ private static Size maximizeSizeGivenAspectRatio(
+ @ScreenOrientation int orientation,
@NonNull Size targetArea,
float aspectRatio
) {
@@ -229,68 +254,11 @@ public final class DesktopModeBoundsCalculator {
}
/**
- * Calculates the aspect ratio of an activity from its fullscreen bounds.
- */
- @VisibleForTesting
- static float calculateAspectRatio(@NonNull Task task, @NonNull ActivityRecord activity) {
- final TaskInfo taskInfo = task.getTaskInfo();
- final float fullscreenWidth = task.getDisplayArea().getBounds().width();
- final float fullscreenHeight = task.getDisplayArea().getBounds().height();
- final float maxAspectRatio = activity.getMaxAspectRatio();
- final float minAspectRatio = activity.getMinAspectRatio();
- float desiredAspectRatio = 0;
- if (taskInfo.isRunning) {
- final AppCompatTaskInfo appCompatTaskInfo = taskInfo.appCompatTaskInfo;
- final int appLetterboxWidth =
- taskInfo.appCompatTaskInfo.topActivityLetterboxAppWidth;
- final int appLetterboxHeight =
- taskInfo.appCompatTaskInfo.topActivityLetterboxAppHeight;
- if (appCompatTaskInfo.isTopActivityLetterboxed()) {
- desiredAspectRatio = (float) Math.max(appLetterboxWidth, appLetterboxHeight)
- / Math.min(appLetterboxWidth, appLetterboxHeight);
- } else {
- desiredAspectRatio = Math.max(fullscreenHeight, fullscreenWidth)
- / Math.min(fullscreenHeight, fullscreenWidth);
- }
- } else {
- final float letterboxAspectRatioOverride =
- getFixedOrientationLetterboxAspectRatio(activity, task);
- if (!task.mDisplayContent.getIgnoreOrientationRequest()) {
- desiredAspectRatio = DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
- } else if (letterboxAspectRatioOverride
- > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
- desiredAspectRatio = letterboxAspectRatioOverride;
- }
- }
- // If the activity matches display orientation, the display aspect ratio should be used
- if (activityMatchesDisplayOrientation(
- taskInfo.configuration.orientation,
- activity.getOverrideOrientation())) {
- desiredAspectRatio = Math.max(fullscreenWidth, fullscreenHeight)
- / Math.min(fullscreenWidth, fullscreenHeight);
- }
- if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) {
- desiredAspectRatio = maxAspectRatio;
- } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) {
- desiredAspectRatio = minAspectRatio;
- }
- return desiredAspectRatio;
- }
-
- private static boolean activityMatchesDisplayOrientation(
- @Configuration.Orientation int deviceOrientation,
- @ActivityInfo.ScreenOrientation int activityOrientation) {
- if (deviceOrientation == ORIENTATION_PORTRAIT) {
- return isFixedOrientationPortrait(activityOrientation);
- }
- return isFixedOrientationLandscape(activityOrientation);
- }
-
- /**
* Calculates the desired initial bounds for applications in desktop windowing. This is done as
* a scale of the screen bounds.
*/
- private static @NonNull Size calculateIdealSize(@NonNull Rect screenBounds, float scale) {
+ @NonNull
+ private static Size calculateIdealSize(@NonNull Rect screenBounds, float scale) {
final int width = (int) (screenBounds.width() * scale);
final int height = (int) (screenBounds.height() * scale);
return new Size(width, height);
@@ -299,7 +267,8 @@ public final class DesktopModeBoundsCalculator {
/**
* Adjusts bounds to be positioned in the middle of the screen.
*/
- private static @NonNull Rect centerInScreen(@NonNull Size desiredSize,
+ @NonNull
+ private static Rect centerInScreen(@NonNull Size desiredSize,
@NonNull Rect screenBounds) {
// TODO(b/325240051): Position apps with bottom heavy offset
final int heightOffset = (screenBounds.height() - desiredSize.getHeight()) / 2;
@@ -309,57 +278,4 @@ public final class DesktopModeBoundsCalculator {
resultBounds.offset(screenBounds.left + widthOffset, screenBounds.top + heightOffset);
return resultBounds;
}
-
- private static float getFixedOrientationLetterboxAspectRatio(@NonNull ActivityRecord activity,
- @NonNull Task task) {
- return activity.shouldCreateCompatDisplayInsets()
- ? getDefaultMinAspectRatioForUnresizableApps(activity, task)
- : activity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .getDefaultMinAspectRatio();
- }
-
- private static float getDefaultMinAspectRatioForUnresizableApps(
- @NonNull ActivityRecord activity,
- @NonNull Task task) {
- final AppCompatAspectRatioOverrides appCompatAspectRatioOverrides =
- activity.mAppCompatController.getAppCompatAspectRatioOverrides();
- if (appCompatAspectRatioOverrides.isSplitScreenAspectRatioForUnresizableAppsEnabled()) {
- // Default letterbox aspect ratio for unresizable apps.
- return getSplitScreenAspectRatio(activity, task);
- }
-
- if (appCompatAspectRatioOverrides.getDefaultMinAspectRatioForUnresizableAppsFromConfig()
- > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
- return appCompatAspectRatioOverrides
- .getDefaultMinAspectRatioForUnresizableAppsFromConfig();
- }
-
- return appCompatAspectRatioOverrides.getDefaultMinAspectRatio();
- }
-
- /**
- * Calculates the aspect ratio of the available display area when an app enters split-screen on
- * a given device, taking into account any dividers and insets.
- */
- private static float getSplitScreenAspectRatio(@NonNull ActivityRecord activity,
- @NonNull Task task) {
- final int dividerWindowWidth =
- activity.mWmService.mContext.getResources().getDimensionPixelSize(
- R.dimen.docked_stack_divider_thickness);
- final int dividerInsets =
- activity.mWmService.mContext.getResources().getDimensionPixelSize(
- R.dimen.docked_stack_divider_insets);
- final int dividerSize = dividerWindowWidth - dividerInsets * 2;
- final Rect bounds = new Rect(0, 0,
- task.mDisplayContent.getDisplayInfo().appWidth,
- task.mDisplayContent.getDisplayInfo().appHeight);
- if (bounds.width() >= bounds.height()) {
- bounds.inset(/* dx */ dividerSize / 2, /* dy */ 0);
- bounds.right = bounds.centerX();
- } else {
- bounds.inset(/* dx */ 0, /* dy */ dividerSize / 2);
- bounds.bottom = bounds.centerY();
- }
- return computeAspectRatio(bounds);
- }
}
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
index 3dba57f8c4cd..37e4449a2dd0 100644
--- a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -55,10 +55,11 @@ public class DimmerAnimationHelper {
Change() {}
- Change(@NonNull Change other) {
+ void copyFrom(@NonNull Change other) {
mAlpha = other.mAlpha;
mBlurRadius = other.mBlurRadius;
mDimmingContainer = other.mDimmingContainer;
+ mGeometryParent = other.mGeometryParent;
mRelativeLayer = other.mRelativeLayer;
}
@@ -83,8 +84,8 @@ public class DimmerAnimationHelper {
}
}
- private Change mCurrentProperties = new Change();
- private Change mRequestedProperties = new Change();
+ private final Change mCurrentProperties = new Change();
+ private final Change mRequestedProperties = new Change();
private AnimationSpec mAlphaAnimationSpec;
private final AnimationAdapterFactory mAnimationAdapterFactory;
@@ -128,7 +129,7 @@ public class DimmerAnimationHelper {
+ "call adjustRelativeLayer?");
return;
}
- if (mRequestedProperties.mDimmingContainer.mSurfaceControl == null) {
+ if (mRequestedProperties.mDimmingContainer.getSurfaceControl() == null) {
Log.w(TAG, "container " + mRequestedProperties.mDimmingContainer
+ "does not have a surface");
dim.remove(t);
@@ -154,35 +155,35 @@ public class DimmerAnimationHelper {
"%s skipping animation and directly setting alpha=%f, blur=%d",
dim, mRequestedProperties.mAlpha,
mRequestedProperties.mBlurRadius);
- setAlphaBlur(dim.mDimSurface, mRequestedProperties.mAlpha,
- mRequestedProperties.mBlurRadius, t);
+ mCurrentProperties.copyFrom(mRequestedProperties);
+ setCurrentAlphaBlur(dim.mDimSurface, t);
dim.mSkipAnimation = false;
} else {
- startAnimation(t, dim);
+ Change startProperties = mCurrentProperties;
+ mCurrentProperties.copyFrom(mRequestedProperties);
+ startAnimation(t, dim, startProperties, mRequestedProperties);
}
-
} else if (!dim.isDimming()) {
// We are not dimming, so we tried the exit animation but the alpha is already 0,
// therefore, let's just remove this surface
dim.remove(t);
}
- mCurrentProperties = new Change(mRequestedProperties);
}
private void startAnimation(
- @NonNull SurfaceControl.Transaction t, @NonNull Dimmer.DimState dim) {
+ @NonNull SurfaceControl.Transaction t, @NonNull Dimmer.DimState dim,
+ @NonNull Change from, @NonNull Change to) {
ProtoLog.v(WM_DEBUG_DIMMER, "Starting animation on %s", dim);
- mAlphaAnimationSpec = getRequestedAnimationSpec();
+ mAlphaAnimationSpec = getRequestedAnimationSpec(from, to);
mLocalAnimationAdapter = mAnimationAdapterFactory.get(mAlphaAnimationSpec,
dim.mHostContainer.mWmService.mSurfaceAnimationRunner);
- float targetAlpha = mRequestedProperties.mAlpha;
- int targetBlur = mRequestedProperties.mBlurRadius;
+ float targetAlpha = to.mAlpha;
mLocalAnimationAdapter.startAnimation(dim.mDimSurface, t,
ANIMATION_TYPE_DIMMER, /* finishCallback */ (type, animator) -> {
synchronized (dim.mHostContainer.mWmService.mGlobalLock) {
- setAlphaBlur(dim.mDimSurface, targetAlpha, targetBlur, t);
+ setCurrentAlphaBlur(dim.mDimSurface, t);
if (targetAlpha == 0f && !dim.isDimming()) {
dim.remove(t);
}
@@ -207,15 +208,15 @@ public class DimmerAnimationHelper {
}
@NonNull
- private AnimationSpec getRequestedAnimationSpec() {
- final float startAlpha = Math.max(mCurrentProperties.mAlpha, 0f);
- final int startBlur = Math.max(mCurrentProperties.mBlurRadius, 0);
- long duration = (long) (getDimDuration(mRequestedProperties.mDimmingContainer)
- * Math.abs(mRequestedProperties.mAlpha - startAlpha));
+ private static AnimationSpec getRequestedAnimationSpec(Change from, Change to) {
+ final float startAlpha = Math.max(from.mAlpha, 0f);
+ final int startBlur = Math.max(from.mBlurRadius, 0);
+ long duration = (long) (getDimDuration(to.mDimmingContainer)
+ * Math.abs(to.mAlpha - startAlpha));
final AnimationSpec spec = new AnimationSpec(
- new AnimationSpec.AnimationExtremes<>(startAlpha, mRequestedProperties.mAlpha),
- new AnimationSpec.AnimationExtremes<>(startBlur, mRequestedProperties.mBlurRadius),
+ new AnimationSpec.AnimationExtremes<>(startAlpha, to.mAlpha),
+ new AnimationSpec.AnimationExtremes<>(startBlur, to.mBlurRadius),
duration
);
ProtoLog.v(WM_DEBUG_DIMMER, "Dim animation requested: %s", spec);
@@ -225,7 +226,7 @@ public class DimmerAnimationHelper {
/**
* Change the geometry and relative parent of this dim layer
*/
- void reparent(@NonNull SurfaceControl dimLayer,
+ static void reparent(@NonNull SurfaceControl dimLayer,
@Nullable SurfaceControl newGeometryParent,
@NonNull SurfaceControl relativeParent,
int relativePosition,
@@ -240,17 +241,16 @@ public class DimmerAnimationHelper {
}
}
- void setAlphaBlur(@NonNull SurfaceControl sc, float alpha, int blur,
- @NonNull SurfaceControl.Transaction t) {
+ void setCurrentAlphaBlur(@NonNull SurfaceControl sc, @NonNull SurfaceControl.Transaction t) {
try {
- t.setAlpha(sc, alpha);
- t.setBackgroundBlurRadius(sc, blur);
+ t.setAlpha(sc, mCurrentProperties.mAlpha);
+ t.setBackgroundBlurRadius(sc, mCurrentProperties.mBlurRadius);
} catch (NullPointerException e) {
Log.w(TAG , "Tried to change look of dim " + sc + " after remove", e);
}
}
- private long getDimDuration(@NonNull WindowContainer<?> container) {
+ private static long getDimDuration(@NonNull WindowContainer<?> container) {
// Use the same duration as the animation on the WindowContainer
AnimationAdapter animationAdapter = container.mSurfaceAnimator.getAnimation();
final float durationScale = container.mWmService.getTransitionAnimationScaleLocked();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index b528e205eae6..401354c2193a 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1002,6 +1002,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// complete configuration.
continue;
}
+ win.updateSurfacePositionIfNeeded();
win.reportResized();
mWmService.mResizingWindows.remove(i);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 923ad4bb51bb..4568f2eac95c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5333,6 +5333,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
super.prepareSurfaces();
}
+ void updateSurfacePositionIfNeeded() {
+ if (mWindowFrames.mRelFrame.top == mWindowFrames.mLastRelFrame.top
+ && mWindowFrames.mRelFrame.left == mWindowFrames.mLastRelFrame.left) {
+ return;
+ }
+ updateSurfacePosition(getSyncTransaction());
+ }
+
@Override
@VisibleForTesting
void updateSurfacePosition(Transaction t) {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 4d6a90c81b27..07d39d957d70 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -291,6 +291,7 @@ public:
void setTouchpadNaturalScrollingEnabled(bool enabled);
void setTouchpadTapToClickEnabled(bool enabled);
void setTouchpadTapDraggingEnabled(bool enabled);
+ void setShouldNotifyTouchpadHardwareState(bool enabled);
void setTouchpadRightClickZoneEnabled(bool enabled);
void setInputDeviceEnabled(uint32_t deviceId, bool enabled);
void setShowTouches(bool enabled);
@@ -440,6 +441,9 @@ private:
// True to enable tap dragging on touchpads.
bool touchpadTapDraggingEnabled{false};
+ // True if hardware state update notifications should be sent to the policy.
+ bool shouldNotifyTouchpadHardwareState{false};
+
// True to enable a zone on the right-hand side of touchpads where clicks will be turned
// into context (a.k.a. "right") clicks.
bool touchpadRightClickZoneEnabled{false};
@@ -698,6 +702,7 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
outConfig->touchpadNaturalScrollingEnabled = mLocked.touchpadNaturalScrollingEnabled;
outConfig->touchpadTapToClickEnabled = mLocked.touchpadTapToClickEnabled;
outConfig->touchpadTapDraggingEnabled = mLocked.touchpadTapDraggingEnabled;
+ outConfig->shouldNotifyTouchpadHardwareState = mLocked.shouldNotifyTouchpadHardwareState;
outConfig->touchpadRightClickZoneEnabled = mLocked.touchpadRightClickZoneEnabled;
outConfig->disabledDevices = mLocked.disabledInputDevices;
@@ -1260,6 +1265,22 @@ void NativeInputManager::setTouchpadTapDraggingEnabled(bool enabled) {
InputReaderConfiguration::Change::TOUCHPAD_SETTINGS);
}
+void NativeInputManager::setShouldNotifyTouchpadHardwareState(bool enabled) {
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+
+ if (mLocked.shouldNotifyTouchpadHardwareState == enabled) {
+ return;
+ }
+
+ ALOGI("Should touchpad hardware state be notified: %s.", toString(enabled));
+ mLocked.shouldNotifyTouchpadHardwareState = enabled;
+ } // release lock
+
+ mInputManager->getReader().requestRefreshConfiguration(
+ InputReaderConfiguration::Change::TOUCHPAD_SETTINGS);
+}
+
void NativeInputManager::setTouchpadRightClickZoneEnabled(bool enabled) {
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -2144,6 +2165,13 @@ static void nativeSetTouchpadTapDraggingEnabled(JNIEnv* env, jobject nativeImplO
im->setTouchpadTapDraggingEnabled(enabled);
}
+static void nativeSetShouldNotifyTouchpadHardwareState(JNIEnv* env, jobject nativeImplObj,
+ jboolean enabled) {
+ NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+
+ im->setShouldNotifyTouchpadHardwareState(enabled);
+}
+
static void nativeSetTouchpadRightClickZoneEnabled(JNIEnv* env, jobject nativeImplObj,
jboolean enabled) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
@@ -2762,6 +2790,8 @@ static const JNINativeMethod gInputManagerMethods[] = {
(void*)nativeSetTouchpadNaturalScrollingEnabled},
{"setTouchpadTapToClickEnabled", "(Z)V", (void*)nativeSetTouchpadTapToClickEnabled},
{"setTouchpadTapDraggingEnabled", "(Z)V", (void*)nativeSetTouchpadTapDraggingEnabled},
+ {"setShouldNotifyTouchpadHardwareState", "(Z)V",
+ (void*)nativeSetShouldNotifyTouchpadHardwareState},
{"setTouchpadRightClickZoneEnabled", "(Z)V", (void*)nativeSetTouchpadRightClickZoneEnabled},
{"setShowTouches", "(Z)V", (void*)nativeSetShowTouches},
{"setInteractive", "(Z)V", (void*)nativeSetInteractive},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9ed645b6ca9b..d5013517cd88 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12215,34 +12215,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* permittedList or are a system app.
*/
private boolean checkPackagesInPermittedListOrSystem(List<String> enabledPackages,
- List<String> permittedList, int userIdToCheck) {
+ List<String> permittedList, int userId) {
long id = mInjector.binderClearCallingIdentity();
try {
- // If we have an enabled packages list for a managed profile the packages
- // we should check are installed for the parent user.
- UserInfo user = getUserInfo(userIdToCheck);
- if (user.isManagedProfile()) {
- userIdToCheck = user.profileGroupId;
- }
-
for (String enabledPackage : enabledPackages) {
- boolean systemService = false;
+ if (permittedList.contains(enabledPackage)) {
+ continue;
+ }
try {
ApplicationInfo applicationInfo = mIPackageManager.getApplicationInfo(
- enabledPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES,
- userIdToCheck);
+ enabledPackage, PackageManager.MATCH_ANY_USER, userId);
if (applicationInfo == null) {
+ Slogf.wtf(LOG_TAG, "Can't find ApplicationInfo for %s", enabledPackage);
return false;
}
- systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ if (!applicationInfo.isSystemApp()) {
+ Slogf.w(LOG_TAG,
+ "Enabled package neither permitted nor system: %s", enabledPackage);
+ return false;
+ }
} catch (RemoteException e) {
Slogf.i(LOG_TAG, "Can't talk to package managed", e);
}
- if (!systemService && !permittedList.contains(enabledPackage)) {
- return false;
- }
}
} finally {
mInjector.binderRestoreCallingIdentity(id);
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp
index 6393e11b7432..1db9e8d545e4 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp
@@ -1,7 +1,7 @@
aconfig_declarations {
name: "device_state_flags",
package: "com.android.server.policy.feature.flags",
- container: "system",
+ container: "system_ext",
srcs: [
"device_state_flags.aconfig",
],
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
index 21e33dd1b99a..f827b5508015 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
@@ -1,5 +1,5 @@
package: "com.android.server.policy.feature.flags"
-container: "system"
+container: "system_ext"
flag {
name: "enable_dual_display_blocking"
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 0bcc572cf745..5840cb937e67 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1621,16 +1621,21 @@ public final class DisplayPowerControllerTest {
advanceTime(1); // Run updatePowerState
reset(mHolder.wakelockController);
+ when(mHolder.wakelockController
+ .acquireWakelock(WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE))
+ .thenReturn(true);
mHolder.dpc.overrideDozeScreenState(
supportedTargetState, Display.STATE_REASON_DEFAULT_POLICY);
- advanceTime(1); // Run updatePowerState
// Should get a wakelock to notify powermanager
- verify(mHolder.wakelockController, atLeastOnce()).acquireWakelock(
- eq(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS));
+ verify(mHolder.wakelockController).acquireWakelock(
+ eq(WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE));
+ advanceTime(1); // Run updatePowerState
verify(mHolder.displayPowerState)
.setScreenState(supportedTargetState, Display.STATE_REASON_DEFAULT_POLICY);
+ verify(mHolder.wakelockController).releaseWakelock(
+ eq(WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE));
}
@Test
diff --git a/services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java
index c23d4b19cd3a..019b70ef1424 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java
@@ -64,6 +64,8 @@ public final class WakelockControllerTest {
"[" + DISPLAY_ID + "]prox negative");
assertEquals(mWakelockController.getSuspendBlockerProxDebounceId(),
"[" + DISPLAY_ID + "]prox debounce");
+ assertEquals(mWakelockController.getSuspendBlockerOverrideDozeScreenState(),
+ "[" + DISPLAY_ID + "]override doze screen state");
}
@Test
@@ -162,6 +164,28 @@ public final class WakelockControllerTest {
}
@Test
+ public void acquireOverrideDozeScreenStateSuspendBlocker() throws Exception {
+ // Acquire the suspend blocker
+ verifyWakelockAcquisitionAndReaquisition(WakelockController
+ .WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE,
+ () -> mWakelockController.isOverrideDozeScreenStateAcquired());
+
+ // Verify acquire happened only once
+ verify(mDisplayPowerCallbacks, times(1))
+ .acquireSuspendBlocker(mWakelockController
+ .getSuspendBlockerOverrideDozeScreenState());
+
+ // Release the suspend blocker
+ verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE,
+ () -> mWakelockController.isOverrideDozeScreenStateAcquired());
+
+ // Verify suspend blocker was released only once
+ verify(mDisplayPowerCallbacks, times(1))
+ .releaseSuspendBlocker(mWakelockController
+ .getSuspendBlockerOverrideDozeScreenState());
+ }
+
+ @Test
public void proximityPositiveRunnableWorksAsExpected() {
// Acquire the suspend blocker twice
assertTrue(mWakelockController.acquireWakelock(
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamServiceTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamServiceTest.java
index b4e1abff3bf7..265b74dcee22 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamServiceTest.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamServiceTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -215,4 +216,39 @@ public class DreamServiceTest {
// Ensure service does not crash from only receiving up event.
environment.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE));
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_DREAM_HANDLES_BEING_OBSCURED)
+ public void testComeToFront() throws Exception {
+ TestDreamEnvironment environment = new TestDreamEnvironment.Builder(mTestableLooper)
+ .setDreamOverlayPresent(true)
+ .build();
+ environment.advance(TestDreamEnvironment.DREAM_STATE_STARTED);
+
+ // Call comeToFront through binder.
+ environment.resetClientInvocations();
+ environment.comeToFront();
+ mTestableLooper.processAllMessages();
+
+ // Overlay client receives call.
+ verify(environment.getDreamOverlayClient()).comeToFront();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_DREAM_HANDLES_BEING_OBSCURED)
+ public void testComeToFront_noOverlay() throws Exception {
+ // Dream environment with no overlay present
+ TestDreamEnvironment environment = new TestDreamEnvironment.Builder(mTestableLooper)
+ .setDreamOverlayPresent(false)
+ .build();
+ environment.advance(TestDreamEnvironment.DREAM_STATE_STARTED);
+
+ // Call comeToFront through binder.
+ environment.resetClientInvocations();
+ environment.comeToFront();
+ mTestableLooper.processAllMessages();
+
+ // Overlay client receives call.
+ verify(environment.getDreamOverlayClient(), never()).comeToFront();
+ }
}
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
index e2b93ae3e9e7..43aa7fe46ca5 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
@@ -398,10 +398,14 @@ public class TestDreamEnvironment {
mService.dispatchKeyEvent(event);
}
- private void wakeDream() throws RemoteException {
+ private void wakeDream() {
mService.wakeUp();
}
+ void comeToFront() throws RemoteException {
+ mDreamServiceWrapper.comeToFront();
+ }
+
/**
* Retrieves the dream overlay callback.
*/
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e72d9e76e4e3..b7483d67563c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -70,14 +70,14 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.longThat;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@@ -1733,12 +1733,20 @@ public class DevicePolicyManagerTest extends DpmTestBase {
pi.applicationInfo.flags = flags;
doReturn(pi).when(getServices().ipackageManager).getPackageInfo(
eq(packageName),
- anyLong(),
+ longThat(flg -> (flg & PackageManager.MATCH_ANY_USER) == 0),
eq(userId));
+ doReturn(pi).when(getServices().ipackageManager).getPackageInfo(
+ eq(packageName),
+ longThat(flg -> (flg & PackageManager.MATCH_ANY_USER) != 0),
+ anyInt());
doReturn(pi.applicationInfo).when(getServices().ipackageManager).getApplicationInfo(
eq(packageName),
- anyLong(),
+ longThat(flg -> (flg & PackageManager.MATCH_ANY_USER) == 0),
eq(userId));
+ doReturn(pi.applicationInfo).when(getServices().ipackageManager).getApplicationInfo(
+ eq(packageName),
+ longThat(flg -> (flg & PackageManager.MATCH_ANY_USER) != 0),
+ anyInt());
doReturn(true).when(getServices().ipackageManager).isPackageAvailable(packageName, userId);
// Setup application UID with the PackageManager
getServices().addTestPackageUid(packageName, uid);
@@ -1757,7 +1765,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mServiceContext.packageName = mRealTestContext.getPackageName();
mServiceContext.applicationInfo = new ApplicationInfo();
mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
- when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
+ when(mContext.resources.getColor(anyInt(), any())).thenReturn(Color.WHITE);
StringParceledListSlice oneCert = asSlice(new String[] {"1"});
StringParceledListSlice fourCerts = asSlice(new String[] {"1", "2", "3", "4"});
@@ -4551,7 +4559,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.packageName = admin1.getPackageName();
mContext.applicationInfo = new ApplicationInfo();
- when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
+ when(mContext.resources.getColor(anyInt(), any())).thenReturn(Color.WHITE);
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
@@ -4597,12 +4605,12 @@ public class DevicePolicyManagerTest extends DpmTestBase {
setupDeviceOwner();
mContext.packageName = admin1.getPackageName();
mContext.applicationInfo = new ApplicationInfo();
- when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
+ when(mContext.resources.getColor(anyInt(), any())).thenReturn(Color.WHITE);
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
getServices().removeUser(CALLER_USER_HANDLE);
- when(getServices().iipConnectivityMetrics.addNetdEventCallback(anyInt(), anyObject()))
+ when(getServices().iipConnectivityMetrics.addNetdEventCallback(anyInt(), any()))
.thenReturn(true);
// No logs were retrieved so far.
@@ -4667,7 +4675,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.packageName = admin1.getPackageName();
addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.S);
when(getServices().iipConnectivityMetrics
- .addNetdEventCallback(anyInt(), anyObject())).thenReturn(true);
+ .addNetdEventCallback(anyInt(), any())).thenReturn(true);
// Check no logs have been retrieved so far.
assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);
@@ -4699,7 +4707,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.packageName = admin1.getPackageName();
mContext.applicationInfo = new ApplicationInfo();
when(getServices().iipConnectivityMetrics
- .addNetdEventCallback(anyInt(), anyObject())).thenReturn(true);
+ .addNetdEventCallback(anyInt(), any())).thenReturn(true);
// Check no logs have been retrieved so far.
assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);
@@ -6296,13 +6304,13 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
assertThat(dpms.isNotificationListenerServicePermitted(
- nonSystemPackage, MANAGED_PROFILE_USER_ID)).isTrue();
+ nonSystemPackage, MANAGED_PROFILE_USER_ID)).isTrue();
assertThat(dpms.isNotificationListenerServicePermitted(
- systemListener, MANAGED_PROFILE_USER_ID)).isTrue();
+ systemListener, MANAGED_PROFILE_USER_ID)).isTrue();
assertThat(dpms.isNotificationListenerServicePermitted(
- nonSystemPackage, UserHandle.USER_SYSTEM)).isTrue();
+ nonSystemPackage, UserHandle.USER_SYSTEM)).isTrue();
assertThat(dpms.isNotificationListenerServicePermitted(
- systemListener, UserHandle.USER_SYSTEM)).isTrue();
+ systemListener, UserHandle.USER_SYSTEM)).isTrue();
// Setting an empty allowlist - only system listeners allowed in managed profile, but
// all allowed in primary profile
@@ -6313,13 +6321,13 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
assertThat(dpms.isNotificationListenerServicePermitted(
- nonSystemPackage, MANAGED_PROFILE_USER_ID)).isFalse();
+ nonSystemPackage, MANAGED_PROFILE_USER_ID)).isFalse();
assertThat(dpms.isNotificationListenerServicePermitted(
- systemListener, MANAGED_PROFILE_USER_ID)).isTrue();
+ systemListener, MANAGED_PROFILE_USER_ID)).isTrue();
assertThat(dpms.isNotificationListenerServicePermitted(
- nonSystemPackage, UserHandle.USER_SYSTEM)).isTrue();
+ nonSystemPackage, UserHandle.USER_SYSTEM)).isTrue();
assertThat(dpms.isNotificationListenerServicePermitted(
- systemListener, UserHandle.USER_SYSTEM)).isTrue();
+ systemListener, UserHandle.USER_SYSTEM)).isTrue();
}
@Test
@@ -6455,7 +6463,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
if (admin1.getPackageName().equals(callerContext.getPackageName())) {
admin1Context = callerContext;
}
- when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
+ when(admin1Context.resources.getColor(anyInt(), any())).thenReturn(Color.WHITE);
// caller: device admin or delegated certificate installer
callerContext.applicationInfo = new ApplicationInfo();
@@ -6528,7 +6536,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
if (admin1.getPackageName().equals(callerContext.getPackageName())) {
admin1Context = callerContext;
}
- when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
+ when(admin1Context.resources.getColor(anyInt(), any())).thenReturn(Color.WHITE);
// caller: device admin or delegated certificate installer
callerContext.applicationInfo = new ApplicationInfo();
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 8e3633509cd3..963b27e010fa 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -119,7 +119,8 @@ public class TunerResourceManagerServiceTest {
tunerFrontendInfo(1 /*handle*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
- Map<Long, FrontendResource> resources = mTunerResourceManagerService.getFrontendResources();
+ Map<Integer, FrontendResource> resources =
+ mTunerResourceManagerService.getFrontendResources();
for (int id = 0; id < infos.length; id++) {
assertThat(resources.get(infos[id].handle)
.getExclusiveGroupMemberFeHandles().size()).isEqualTo(0);
@@ -146,14 +147,15 @@ public class TunerResourceManagerServiceTest {
tunerFrontendInfo(3 /*handle*/, FrontendSettings.TYPE_ATSC, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
- Map<Long, FrontendResource> resources = mTunerResourceManagerService.getFrontendResources();
+ Map<Integer, FrontendResource> resources =
+ mTunerResourceManagerService.getFrontendResources();
assertThat(resources.values()).comparingElementsUsing(FR_TFI_COMPARE)
.containsExactlyElementsIn(Arrays.asList(infos));
- assertThat(resources.get(0L).getExclusiveGroupMemberFeHandles()).isEmpty();
- assertThat(resources.get(1L).getExclusiveGroupMemberFeHandles()).containsExactly(2L, 3L);
- assertThat(resources.get(2L).getExclusiveGroupMemberFeHandles()).containsExactly(1L, 3L);
- assertThat(resources.get(3L).getExclusiveGroupMemberFeHandles()).containsExactly(1L, 2L);
+ assertThat(resources.get(0).getExclusiveGroupMemberFeHandles()).isEmpty();
+ assertThat(resources.get(1).getExclusiveGroupMemberFeHandles()).containsExactly(2, 3);
+ assertThat(resources.get(2).getExclusiveGroupMemberFeHandles()).containsExactly(1, 3);
+ assertThat(resources.get(3).getExclusiveGroupMemberFeHandles()).containsExactly(1, 2);
}
@Test
@@ -166,11 +168,11 @@ public class TunerResourceManagerServiceTest {
tunerFrontendInfo(1 /*handle*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
- Map<Long, FrontendResource> resources0 =
+ Map<Integer, FrontendResource> resources0 =
mTunerResourceManagerService.getFrontendResources();
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
- Map<Long, FrontendResource> resources1 =
+ Map<Integer, FrontendResource> resources1 =
mTunerResourceManagerService.getFrontendResources();
assertThat(resources0).isEqualTo(resources1);
@@ -193,7 +195,8 @@ public class TunerResourceManagerServiceTest {
tunerFrontendInfo(1 /*handle*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos1);
- Map<Long, FrontendResource> resources = mTunerResourceManagerService.getFrontendResources();
+ Map<Integer, FrontendResource> resources =
+ mTunerResourceManagerService.getFrontendResources();
for (int id = 0; id < infos1.length; id++) {
assertThat(resources.get(infos1[id].handle)
.getExclusiveGroupMemberFeHandles().size()).isEqualTo(0);
@@ -219,7 +222,8 @@ public class TunerResourceManagerServiceTest {
tunerFrontendInfo(1 /*handle*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos1);
- Map<Long, FrontendResource> resources = mTunerResourceManagerService.getFrontendResources();
+ Map<Integer, FrontendResource> resources =
+ mTunerResourceManagerService.getFrontendResources();
for (int id = 0; id < infos1.length; id++) {
assertThat(resources.get(infos1[id].handle)
.getExclusiveGroupMemberFeHandles().size()).isEqualTo(0);
@@ -236,7 +240,7 @@ public class TunerResourceManagerServiceTest {
mTunerResourceManagerService.setFrontendInfoListInternal(infos0);
TunerFrontendRequest request =
tunerFrontendRequest(0 /*clientId*/, FrontendSettings.TYPE_DVBT);
- long[] frontendHandle = new long[1];
+ int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
assertThat(frontendHandle[0]).isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE);
@@ -259,7 +263,7 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
tunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
- long[] frontendHandle = new long[1];
+ int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
assertThat(frontendHandle[0]).isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE);
@@ -292,7 +296,7 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
tunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
- long[] frontendHandle = new long[1];
+ int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(frontendHandle[0]).isEqualTo(0);
@@ -329,7 +333,7 @@ public class TunerResourceManagerServiceTest {
1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
- long[] frontendHandle = new long[1];
+ int[] frontendHandle = new int[1];
TunerFrontendRequest request =
tunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
assertThat(mTunerResourceManagerService
@@ -381,7 +385,7 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
tunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
- long[] frontendHandle = new long[1];
+ int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
@@ -431,13 +435,13 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
tunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
- long[] frontendHandle = new long[1];
+ int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
- .getInUseFrontendHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle, infos[1].handle)));
+ .getInUseFrontendHandles()).isEqualTo(new HashSet<Integer>(Arrays.asList(
+ infos[0].handle, infos[1].handle)));
request =
tunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
@@ -476,7 +480,7 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
tunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
- long[] frontendHandle = new long[1];
+ int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
@@ -521,7 +525,7 @@ public class TunerResourceManagerServiceTest {
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
CasSessionRequest request = casSessionRequest(clientId0[0], 1 /*casSystemId*/);
- long[] casSessionHandle = new long[1];
+ int[] casSessionHandle = new int[1];
// Request for 2 cas sessions.
assertThat(mTunerResourceManagerService
.requestCasSessionInternal(request, casSessionHandle)).isTrue();
@@ -577,7 +581,7 @@ public class TunerResourceManagerServiceTest {
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
TunerCiCamRequest request = tunerCiCamRequest(clientId0[0], 1 /*ciCamId*/);
- long[] ciCamHandle = new long[1];
+ int[] ciCamHandle = new int[1];
// Request for 2 ciCam sessions.
assertThat(mTunerResourceManagerService
.requestCiCamInternal(request, ciCamHandle)).isTrue();
@@ -621,7 +625,7 @@ public class TunerResourceManagerServiceTest {
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
CasSessionRequest request = casSessionRequest(clientId[0], 1 /*casSystemId*/);
- long[] casSessionHandle = new long[1];
+ int[] casSessionHandle = new int[1];
// Request for 1 cas sessions.
assertThat(mTunerResourceManagerService
.requestCasSessionInternal(request, casSessionHandle)).isTrue();
@@ -658,7 +662,7 @@ public class TunerResourceManagerServiceTest {
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
TunerCiCamRequest request = tunerCiCamRequest(clientId[0], 1 /*ciCamId*/);
- long[] ciCamHandle = new long[1];
+ int[] ciCamHandle = new int[1];
// Request for 1 ciCam sessions.
assertThat(mTunerResourceManagerService
.requestCiCamInternal(request, ciCamHandle)).isTrue();
@@ -704,17 +708,17 @@ public class TunerResourceManagerServiceTest {
clientId1[0], clientPriorities[1], 0/*niceValue*/);
// Init lnb resources.
- long[] lnbHandles = {1};
+ int[] lnbHandles = {1};
mTunerResourceManagerService.setLnbInfoListInternal(lnbHandles);
TunerLnbRequest request = new TunerLnbRequest();
request.clientId = clientId0[0];
- long[] lnbHandle = new long[1];
+ int[] lnbHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
assertThat(lnbHandle[0]).isEqualTo(lnbHandles[0]);
assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0]).getInUseLnbHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(lnbHandles[0])));
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(lnbHandles[0])));
request = new TunerLnbRequest();
request.clientId = clientId1[0];
@@ -743,12 +747,12 @@ public class TunerResourceManagerServiceTest {
assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
// Init lnb resources.
- long[] lnbHandles = {0};
+ int[] lnbHandles = {0};
mTunerResourceManagerService.setLnbInfoListInternal(lnbHandles);
TunerLnbRequest request = new TunerLnbRequest();
request.clientId = clientId[0];
- long[] lnbHandle = new long[1];
+ int[] lnbHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
assertThat(lnbHandle[0]).isEqualTo(lnbHandles[0]);
@@ -782,7 +786,7 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
tunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
- long[] frontendHandle = new long[1];
+ int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
@@ -819,12 +823,12 @@ public class TunerResourceManagerServiceTest {
infos[2] = tunerDemuxInfo(2 /* handle */, Filter.TYPE_TS);
mTunerResourceManagerService.setDemuxInfoListInternal(infos);
- long[] demuxHandle0 = new long[1];
+ int[] demuxHandle0 = new int[1];
// first with undefined type (should be the first one with least # of caps)
TunerDemuxRequest request = tunerDemuxRequest(clientId0[0], Filter.TYPE_UNDEFINED);
assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
.isTrue();
- assertThat(demuxHandle0[0]).isEqualTo(1L);
+ assertThat(demuxHandle0[0]).isEqualTo(1);
DemuxResource dr = mTunerResourceManagerService.getDemuxResource(demuxHandle0[0]);
mTunerResourceManagerService.releaseDemuxInternal(dr);
@@ -833,20 +837,20 @@ public class TunerResourceManagerServiceTest {
demuxHandle0[0] = -1;
assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
.isFalse();
- assertThat(demuxHandle0[0]).isEqualTo(-1L);
+ assertThat(demuxHandle0[0]).isEqualTo(-1);
// now with TS (should be the one with least # of caps that supports TS)
request.desiredFilterTypes = Filter.TYPE_TS;
assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
.isTrue();
- assertThat(demuxHandle0[0]).isEqualTo(2L);
+ assertThat(demuxHandle0[0]).isEqualTo(2);
// request for another TS
int[] clientId1 = new int[1];
mTunerResourceManagerService.registerClientProfileInternal(
profile1, null /*listener*/, clientId1);
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- long[] demuxHandle1 = new long[1];
+ int[] demuxHandle1 = new int[1];
TunerDemuxRequest request1 = tunerDemuxRequest(clientId1[0], Filter.TYPE_TS);
assertThat(mTunerResourceManagerService.requestDemuxInternal(request1, demuxHandle1))
.isTrue();
@@ -895,14 +899,14 @@ public class TunerResourceManagerServiceTest {
// let clientId0(prio:100) request for IP - should succeed
TunerDemuxRequest request0 = tunerDemuxRequest(clientId0[0], Filter.TYPE_IP);
- long[] demuxHandle0 = new long[1];
+ int[] demuxHandle0 = new int[1];
assertThat(mTunerResourceManagerService
.requestDemuxInternal(request0, demuxHandle0)).isTrue();
assertThat(demuxHandle0[0]).isEqualTo(0);
// let clientId1(prio:50) request for IP - should fail
TunerDemuxRequest request1 = tunerDemuxRequest(clientId1[0], Filter.TYPE_IP);
- long[] demuxHandle1 = new long[1];
+ int[] demuxHandle1 = new int[1];
demuxHandle1[0] = -1;
assertThat(mTunerResourceManagerService
.requestDemuxInternal(request1, demuxHandle1)).isFalse();
@@ -922,7 +926,7 @@ public class TunerResourceManagerServiceTest {
// let clientId2(prio:50) request for TS - should succeed
TunerDemuxRequest request2 = tunerDemuxRequest(clientId2[0], Filter.TYPE_TS);
- long[] demuxHandle2 = new long[1];
+ int[] demuxHandle2 = new int[1];
assertThat(mTunerResourceManagerService
.requestDemuxInternal(request2, demuxHandle2)).isTrue();
assertThat(demuxHandle2[0]).isEqualTo(0);
@@ -947,7 +951,7 @@ public class TunerResourceManagerServiceTest {
profile, null /*listener*/, clientId);
assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- long[] desHandle = new long[1];
+ int[] desHandle = new int[1];
TunerDescramblerRequest request = new TunerDescramblerRequest();
request.clientId = clientId[0];
assertThat(mTunerResourceManagerService.requestDescramblerInternal(request, desHandle))
@@ -1057,7 +1061,7 @@ public class TunerResourceManagerServiceTest {
1 /*exclusiveGroupId*/);
/**** Init Lnb Resources ****/
- long[] lnbHandles = {1};
+ int[] lnbHandles = {1};
mTunerResourceManagerService.setLnbInfoListInternal(lnbHandles);
// Update frontend list in TRM
@@ -1066,7 +1070,7 @@ public class TunerResourceManagerServiceTest {
/**** Request Frontend ****/
// Predefined frontend request and array to save returned frontend handle
- long[] frontendHandle = new long[1];
+ int[] frontendHandle = new int[1];
TunerFrontendRequest request = tunerFrontendRequest(
ownerClientId0[0] /*clientId*/,
FrontendSettings.TYPE_DVBT);
@@ -1076,9 +1080,12 @@ public class TunerResourceManagerServiceTest {
.requestFrontendInternal(request, frontendHandle))
.isTrue();
assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
- assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId0[0])
- .getInUseFrontendHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle, infos[1].handle)));
+ assertThat(mTunerResourceManagerService
+ .getClientProfile(ownerClientId0[0])
+ .getInUseFrontendHandles())
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(
+ infos[0].handle,
+ infos[1].handle)));
/**** Share Frontend ****/
@@ -1106,15 +1113,24 @@ public class TunerResourceManagerServiceTest {
shareClientId0[0],
shareClientId1[0])));
// Verify in use frontend list in all the primary owner and share owner clients
- assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId0[0])
- .getInUseFrontendHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle, infos[1].handle)));
- assertThat(mTunerResourceManagerService.getClientProfile(shareClientId0[0])
- .getInUseFrontendHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle, infos[1].handle)));
- assertThat(mTunerResourceManagerService.getClientProfile(shareClientId1[0])
- .getInUseFrontendHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle, infos[1].handle)));
+ assertThat(mTunerResourceManagerService
+ .getClientProfile(ownerClientId0[0])
+ .getInUseFrontendHandles())
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(
+ infos[0].handle,
+ infos[1].handle)));
+ assertThat(mTunerResourceManagerService
+ .getClientProfile(shareClientId0[0])
+ .getInUseFrontendHandles())
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(
+ infos[0].handle,
+ infos[1].handle)));
+ assertThat(mTunerResourceManagerService
+ .getClientProfile(shareClientId1[0])
+ .getInUseFrontendHandles())
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(
+ infos[0].handle,
+ infos[1].handle)));
/**** Remove Frontend Share Owner ****/
@@ -1126,12 +1142,18 @@ public class TunerResourceManagerServiceTest {
.getShareFeClientIds())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
shareClientId0[0])));
- assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId0[0])
- .getInUseFrontendHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle, infos[1].handle)));
- assertThat(mTunerResourceManagerService.getClientProfile(shareClientId0[0])
- .getInUseFrontendHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle, infos[1].handle)));
+ assertThat(mTunerResourceManagerService
+ .getClientProfile(ownerClientId0[0])
+ .getInUseFrontendHandles())
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(
+ infos[0].handle,
+ infos[1].handle)));
+ assertThat(mTunerResourceManagerService
+ .getClientProfile(shareClientId0[0])
+ .getInUseFrontendHandles())
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(
+ infos[0].handle,
+ infos[1].handle)));
/**** Request Shared Frontend with Higher Priority Client ****/
@@ -1151,9 +1173,12 @@ public class TunerResourceManagerServiceTest {
.getOwnerClientId()).isEqualTo(ownerClientId1[0]);
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].handle)
.getOwnerClientId()).isEqualTo(ownerClientId1[0]);
- assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId1[0])
- .getInUseFrontendHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle, infos[1].handle)));
+ assertThat(mTunerResourceManagerService
+ .getClientProfile(ownerClientId1[0])
+ .getInUseFrontendHandles())
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(
+ infos[0].handle,
+ infos[1].handle)));
assertThat(mTunerResourceManagerService
.getClientProfile(ownerClientId0[0])
.getInUseFrontendHandles()
@@ -1210,7 +1235,7 @@ public class TunerResourceManagerServiceTest {
// Predefined Lnb request and handle array
TunerLnbRequest requestLnb = new TunerLnbRequest();
requestLnb.clientId = shareClientId0[0];
- long[] lnbHandle = new long[1];
+ int[] lnbHandle = new int[1];
// Request for an Lnb
assertThat(mTunerResourceManagerService
@@ -1239,13 +1264,15 @@ public class TunerResourceManagerServiceTest {
.getInUseFrontendHandles()
.isEmpty())
.isTrue();
- assertThat(mTunerResourceManagerService.getClientProfile(shareClientId0[0])
- .getInUseLnbHandles())
- .isEqualTo(new HashSet<Long>(Arrays.asList(lnbHandles[0])));
+ assertThat(mTunerResourceManagerService
+ .getClientProfile(shareClientId0[0])
+ .getInUseLnbHandles())
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(
+ lnbHandles[0])));
}
private TunerFrontendInfo tunerFrontendInfo(
- long handle, int frontendType, int exclusiveGroupId) {
+ int handle, int frontendType, int exclusiveGroupId) {
TunerFrontendInfo info = new TunerFrontendInfo();
info.handle = handle;
info.type = frontendType;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index 225c1dc752c1..51f64ba2b483 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -31,10 +31,11 @@ import static android.app.Notification.VISIBILITY_PUBLIC;
import static android.app.Notification.VISIBILITY_SECRET;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION;
import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING;
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
-import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static com.android.server.notification.GroupHelper.AGGREGATE_GROUP_KEY;
import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY;
import static com.android.server.notification.GroupHelper.BASE_FLAGS;
@@ -2518,17 +2519,7 @@ public class GroupHelperTest extends UiServiceTestCase {
assertThat(cachedSummary).isNull();
}
- @Test
- @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
- public void testGroupSectioners() {
- final NotificationRecord notification_alerting = getNotificationRecord(mPkg, 0, "", mUser,
- "", false, IMPORTANCE_DEFAULT);
- assertThat(GroupHelper.getSection(notification_alerting).mName).isEqualTo("AlertingSection");
-
- final NotificationRecord notification_silent = getNotificationRecord(mPkg, 0, "", mUser,
- "", false, IMPORTANCE_LOW);
- assertThat(GroupHelper.getSection(notification_silent).mName).isEqualTo("SilentSection");
-
+ private void checkNonGroupableNotifications() {
NotificationRecord notification_conversation = mock(NotificationRecord.class);
when(notification_conversation.isConversation()).thenReturn(true);
assertThat(GroupHelper.getSection(notification_conversation)).isNull();
@@ -2545,7 +2536,7 @@ public class GroupHelperTest extends UiServiceTestCase {
assertThat(GroupHelper.getSection(notification_call)).isNull();
NotificationRecord notification_colorFg = spy(getNotificationRecord(mPkg, 0, "", mUser,
- "", false, IMPORTANCE_LOW));
+ "", false, IMPORTANCE_LOW));
sbn = spy(getSbn("package", 0, "0", UserHandle.SYSTEM));
n = mock(Notification.class);
when(notification_colorFg.isConversation()).thenReturn(false);
@@ -2558,4 +2549,97 @@ public class GroupHelperTest extends UiServiceTestCase {
assertThat(GroupHelper.getSection(notification_colorFg)).isNull();
}
+ @Test
+ @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
+ @DisableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testGroupSectioners() {
+ final NotificationRecord notification_alerting = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, IMPORTANCE_DEFAULT);
+ assertThat(GroupHelper.getSection(notification_alerting).mName).isEqualTo(
+ "AlertingSection");
+
+ final NotificationRecord notification_silent = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, IMPORTANCE_LOW);
+ assertThat(GroupHelper.getSection(notification_silent).mName).isEqualTo("SilentSection");
+
+ // Check that special categories are grouped by their importance
+ final NotificationChannel promoChannel = new NotificationChannel(
+ NotificationChannel.PROMOTIONS_ID, NotificationChannel.PROMOTIONS_ID,
+ IMPORTANCE_DEFAULT);
+ final NotificationRecord notification_promotion = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, promoChannel);
+ assertThat(GroupHelper.getSection(notification_promotion).mName).isEqualTo(
+ "AlertingSection");
+
+ final NotificationChannel newsChannel = new NotificationChannel(NotificationChannel.NEWS_ID,
+ NotificationChannel.NEWS_ID, IMPORTANCE_DEFAULT);
+ final NotificationRecord notification_news = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, newsChannel);
+ assertThat(GroupHelper.getSection(notification_news).mName).isEqualTo(
+ "AlertingSection");
+
+ final NotificationChannel socialChannel = new NotificationChannel(
+ NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID,
+ IMPORTANCE_DEFAULT);
+ final NotificationRecord notification_social = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, socialChannel);
+ assertThat(GroupHelper.getSection(notification_social).mName).isEqualTo(
+ "AlertingSection");
+
+ final NotificationChannel recsChannel = new NotificationChannel(NotificationChannel.RECS_ID,
+ NotificationChannel.RECS_ID, IMPORTANCE_DEFAULT);
+ final NotificationRecord notification_recs = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, recsChannel);
+ assertThat(GroupHelper.getSection(notification_recs).mName).isEqualTo(
+ "AlertingSection");
+
+ checkNonGroupableNotifications();
+ }
+
+ @Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_CLASSIFICATION})
+ public void testGroupSectioners_withClassificationSections() {
+ final NotificationRecord notification_alerting = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, IMPORTANCE_DEFAULT);
+ assertThat(GroupHelper.getSection(notification_alerting).mName).isEqualTo(
+ "AlertingSection");
+
+ final NotificationRecord notification_silent = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, IMPORTANCE_LOW);
+ assertThat(GroupHelper.getSection(notification_silent).mName).isEqualTo("SilentSection");
+
+ // Check that special categories are grouped in their own sections
+ final NotificationChannel promoChannel = new NotificationChannel(
+ NotificationChannel.PROMOTIONS_ID, NotificationChannel.PROMOTIONS_ID,
+ IMPORTANCE_DEFAULT);
+ final NotificationRecord notification_promotion = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, promoChannel);
+ assertThat(GroupHelper.getSection(notification_promotion).mName).isEqualTo(
+ "PromotionsSection");
+
+ final NotificationChannel newsChannel = new NotificationChannel(NotificationChannel.NEWS_ID,
+ NotificationChannel.NEWS_ID, IMPORTANCE_DEFAULT);
+ final NotificationRecord notification_news = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, newsChannel);
+ assertThat(GroupHelper.getSection(notification_news).mName).isEqualTo(
+ "NewsSection");
+
+ final NotificationChannel socialChannel = new NotificationChannel(
+ NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID,
+ IMPORTANCE_DEFAULT);
+ final NotificationRecord notification_social = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, socialChannel);
+ assertThat(GroupHelper.getSection(notification_social).mName).isEqualTo(
+ "SocialSection");
+
+ final NotificationChannel recsChannel = new NotificationChannel(NotificationChannel.RECS_ID,
+ NotificationChannel.RECS_ID, IMPORTANCE_DEFAULT);
+ final NotificationRecord notification_recs = getNotificationRecord(mPkg, 0, "", mUser,
+ "", false, recsChannel);
+ assertThat(GroupHelper.getSection(notification_recs).mName).isEqualTo(
+ "RecsSection");
+
+ checkNonGroupableNotifications();
+ }
+
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index 07e95d83d7bc..6d508eabcd52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -21,11 +21,19 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_SMALL_VALUE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_4_3;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
@@ -34,7 +42,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.DesktopModeBoundsCalculator.DESKTOP_MODE_INITIAL_BOUNDS_SCALE;
import static com.android.server.wm.DesktopModeBoundsCalculator.DESKTOP_MODE_LANDSCAPE_APP_PADDING;
-import static com.android.server.wm.DesktopModeBoundsCalculator.calculateAspectRatio;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
@@ -44,6 +51,8 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import android.app.ActivityOptions;
+import android.compat.testing.PlatformCompatChangeRule;
+import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.platform.test.annotations.DisableFlags;
@@ -55,8 +64,12 @@ import androidx.test.filters.SmallTest;
import com.android.window.flags.Flags;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
/**
@@ -74,6 +87,9 @@ public class DesktopModeLaunchParamsModifierTests extends
private static final Rect PORTRAIT_DISPLAY_BOUNDS = new Rect(0, 0, 1600, 2560);
private static final float LETTERBOX_ASPECT_RATIO = 1.3f;
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
@Before
public void setUp() throws Exception {
mActivity = new ActivityBuilder(mAtm).build();
@@ -199,14 +215,17 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
LANDSCAPE_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_UNSPECIFIED, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
final int desiredWidth =
(int) (LANDSCAPE_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -219,14 +238,17 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
LANDSCAPE_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
+ task, /* ignoreOrientationRequest */ true);
final int desiredWidth =
(int) (LANDSCAPE_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -239,7 +261,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
LANDSCAPE_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
+ task, /* ignoreOrientationRequest */ true);
spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
doReturn(true).when(
@@ -251,7 +275,8 @@ public class DesktopModeLaunchParamsModifierTests extends
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -264,7 +289,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
LANDSCAPE_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
+ task, /* ignoreOrientationRequest */ true);
spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
doReturn(true).when(
@@ -276,7 +303,8 @@ public class DesktopModeLaunchParamsModifierTests extends
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -285,19 +313,466 @@ public class DesktopModeLaunchParamsModifierTests extends
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
public void testResizablePortraitBounds_landscapeDevice_resizable_portraitOrientation() {
setupDesktopModeLaunchParamsModifier();
- doReturn(LETTERBOX_ASPECT_RATIO).when(()
- -> calculateAspectRatio(any(), any()));
final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
LANDSCAPE_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ true);
+
+ spyOn(activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy());
+ doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
+ .getDesktopAppCompatAspectRatioPolicy()).calculateAspectRatio(any());
final int desiredWidth =
(int) ((LANDSCAPE_DISPLAY_BOUNDS.height() / LETTERBOX_ASPECT_RATIO) + 0.5f);
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_SMALL})
+ public void testSmallAspectRatioOverride_landscapeDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
+ LANDSCAPE_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ false);
+
+ final int desiredHeight =
+ (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth =
+ (int) (desiredHeight / OVERRIDE_MIN_ASPECT_RATIO_SMALL_VALUE);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
+ public void testMediumAspectRatioOverride_landscapeDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
+ LANDSCAPE_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ false);
+
+ final int desiredHeight =
+ (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth =
+ (int) (desiredHeight / OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
+ public void testLargeAspectRatioOverride_landscapeDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
+ LANDSCAPE_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ false);
+
+ final int desiredHeight =
+ (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth =
+ (int) (desiredHeight / OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
+ public void testSplitScreenAspectRatioOverride_landscapeDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
+ LANDSCAPE_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ false);
+
+ final int desiredHeight =
+ (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth =
+ (int) (desiredHeight / activity.mAppCompatController
+ .getAppCompatAspectRatioOverrides().getSplitScreenAspectRatio());
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_SMALL})
+ public void testSmallAspectRatioOverride_portraitDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
+ PORTRAIT_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ false);
+ // Mock desired aspect ratio so min override can take effect.
+ setDesiredAspectRatio(activity, /* aspectRatio */ 1f);
+
+ final int desiredWidth =
+ (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredHeight = (int) (desiredWidth * OVERRIDE_MIN_ASPECT_RATIO_SMALL_VALUE);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
+ public void testMediumAspectRatioOverride_portraitDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
+ PORTRAIT_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ false);
+ // Mock desired aspect ratio so min override can take effect.
+ setDesiredAspectRatio(activity, /* aspectRatio */ 1f);
+
+ final int desiredWidth =
+ (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredHeight = (int) (desiredWidth * OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
+ public void testLargeAspectRatioOverride_portraitDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
+ PORTRAIT_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ false);
+ // Mock desired aspect ratio so min override can take effect.
+ setDesiredAspectRatio(activity, /* aspectRatio */ 1f);
+
+ final int desiredHeight =
+ (int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth = (int) (desiredHeight / OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
+ public void testSplitScreenAspectRatioOverride_portraitDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
+ PORTRAIT_DISPLAY_BOUNDS);
+ final Task task = createTask(display, true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ false);
+ // Mock desired aspect ratio so min override can take effect.
+ setDesiredAspectRatio(activity, /* aspectRatio */ 1f);
+
+ final int desiredWidth =
+ (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredHeight = (int) (desiredWidth * activity.mAppCompatController
+ .getAppCompatAspectRatioOverrides().getSplitScreenAspectRatio());
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatio32Override_landscapeDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
+ LANDSCAPE_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValue3_2 = 3 / 2f;
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_3_2,
+ userAspectRatioOverrideValue3_2);
+
+ final int desiredHeight =
+ (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth = (int) (desiredHeight / userAspectRatioOverrideValue3_2);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatio43Override_landscapeDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
+ LANDSCAPE_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValue4_3 = 4 / 3f;
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_4_3,
+ userAspectRatioOverrideValue4_3);
+
+ final int desiredHeight =
+ (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth = (int) (desiredHeight / userAspectRatioOverrideValue4_3);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatio169Override_landscapeDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
+ LANDSCAPE_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValue16_9 = 16 / 9f;
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_16_9,
+ userAspectRatioOverrideValue16_9);
+
+ final int desiredHeight =
+ (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth = (int) (desiredHeight / userAspectRatioOverrideValue16_9);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatioSplitScreenOverride_landscapeDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
+ LANDSCAPE_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValueSplitScreen = activity.mAppCompatController
+ .getAppCompatAspectRatioOverrides().getSplitScreenAspectRatio();
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_SPLIT_SCREEN,
+ userAspectRatioOverrideValueSplitScreen);
+
+ final int desiredHeight =
+ (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth = (int) (desiredHeight / userAspectRatioOverrideValueSplitScreen);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatioDisplaySizeOverride_landscapeDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
+ LANDSCAPE_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValueDisplaySize = activity.mAppCompatController
+ .getAppCompatAspectRatioOverrides().getDisplaySizeMinAspectRatio();
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_DISPLAY_SIZE,
+ userAspectRatioOverrideValueDisplaySize);
+
+ final int desiredHeight =
+ (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth = (int) (desiredHeight / userAspectRatioOverrideValueDisplaySize);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatio32Override_portraitDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
+ PORTRAIT_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValue3_2 = 3 / 2f;
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_3_2,
+ userAspectRatioOverrideValue3_2);
+
+ final int desiredWidth =
+ (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredHeight = (int) (desiredWidth * userAspectRatioOverrideValue3_2);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatio43Override_portraitDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
+ PORTRAIT_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValue4_3 = 4 / 3f;
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_4_3,
+ userAspectRatioOverrideValue4_3);
+
+ final int desiredWidth =
+ (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredHeight = (int) (desiredWidth * userAspectRatioOverrideValue4_3);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatio169Override_portraitDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
+ PORTRAIT_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValue16_9 = 16 / 9f;
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_16_9,
+ userAspectRatioOverrideValue16_9);
+
+ final int desiredHeight =
+ (int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth = (int) (desiredHeight / userAspectRatioOverrideValue16_9);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatioSplitScreenOverride_portraitDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
+ PORTRAIT_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValueSplitScreen = activity.mAppCompatController
+ .getAppCompatAspectRatioOverrides().getSplitScreenAspectRatio();
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_SPLIT_SCREEN,
+ userAspectRatioOverrideValueSplitScreen);
+
+ final int desiredWidth =
+ (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredHeight = (int) (desiredWidth * userAspectRatioOverrideValueSplitScreen);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
+ assertEquals(desiredWidth, mResult.mBounds.width());
+ assertEquals(desiredHeight, mResult.mBounds.height());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ public void testUserAspectRatioDisplaySizeOverride_portraitDevice() {
+ setupDesktopModeLaunchParamsModifier();
+
+ final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
+ PORTRAIT_DISPLAY_BOUNDS);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
+ final float userAspectRatioOverrideValueDisplaySize = activity.mAppCompatController
+ .getAppCompatAspectRatioOverrides().getDisplaySizeMinAspectRatio();
+ applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_DISPLAY_SIZE,
+ userAspectRatioOverrideValueDisplaySize);
+
+ final int desiredWidth =
+ (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredHeight = (int) (desiredWidth * userAspectRatioOverrideValueDisplaySize);
+
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -310,14 +785,18 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
LANDSCAPE_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, false);
+ final Task task = createTask(display, /* isResizeable */ false);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
+ task, /* ignoreOrientationRequest */ true);
+
final int desiredWidth =
(int) (LANDSCAPE_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -326,18 +805,23 @@ public class DesktopModeLaunchParamsModifierTests extends
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
public void testUnResizablePortraitBounds_landscapeDevice_unResizable_portraitOrientation() {
setupDesktopModeLaunchParamsModifier();
- doReturn(LETTERBOX_ASPECT_RATIO).when(()
- -> calculateAspectRatio(any(), any()));
final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
LANDSCAPE_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, false);
+ final Task task = createTask(display, /* isResizeable */ false);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ true);
+
+ spyOn(activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy());
+ doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
+ .getDesktopAppCompatAspectRatioPolicy()).calculateAspectRatio(any());
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
final int desiredWidth = (int) (desiredHeight / LETTERBOX_ASPECT_RATIO);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -350,14 +834,17 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
PORTRAIT_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_UNSPECIFIED, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
+ task, /* ignoreOrientationRequest */ true);
final int desiredWidth =
(int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
final int desiredHeight =
(int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -370,14 +857,17 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
PORTRAIT_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ true);
final int desiredWidth =
(int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
final int desiredHeight =
(int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -390,11 +880,13 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
PORTRAIT_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ true);
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
doReturn(true).when(
- mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ activity.mAppCompatController.getAppCompatAspectRatioOverrides())
.isUserFullscreenOverrideEnabled();
final int desiredWidth =
@@ -402,7 +894,8 @@ public class DesktopModeLaunchParamsModifierTests extends
final int desiredHeight =
(int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -415,11 +908,13 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
PORTRAIT_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ true);
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
doReturn(true).when(
- mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ activity.mAppCompatController.getAppCompatAspectRatioOverrides())
.isSystemOverrideToFullscreenEnabled();
final int desiredWidth =
@@ -427,7 +922,8 @@ public class DesktopModeLaunchParamsModifierTests extends
final int desiredHeight =
(int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -436,19 +932,24 @@ public class DesktopModeLaunchParamsModifierTests extends
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
public void testResizableLandscapeBounds_portraitDevice_resizable_landscapeOrientation() {
setupDesktopModeLaunchParamsModifier();
- doReturn(LETTERBOX_ASPECT_RATIO).when(()
- -> calculateAspectRatio(any(), any()));
final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
PORTRAIT_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, true);
+ final Task task = createTask(display, /* isResizeable */ true);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
+ task, /* ignoreOrientationRequest */ true);
+
+ spyOn(activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy());
+ doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
+ .getDesktopAppCompatAspectRatioPolicy()).calculateAspectRatio(any());
final int desiredWidth = PORTRAIT_DISPLAY_BOUNDS.width()
- (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
final int desiredHeight = (int)
((PORTRAIT_DISPLAY_BOUNDS.width() / LETTERBOX_ASPECT_RATIO) + 0.5f);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -461,14 +962,18 @@ public class DesktopModeLaunchParamsModifierTests extends
final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
PORTRAIT_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, false);
+ final Task task = createTask(display, /* isResizeable */ false);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
+ task, /* ignoreOrientationRequest */ true);
+
final int desiredWidth =
(int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
final int desiredHeight =
(int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -477,18 +982,23 @@ public class DesktopModeLaunchParamsModifierTests extends
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
public void testUnResizableLandscapeBounds_portraitDevice_unResizable_landscapeOrientation() {
setupDesktopModeLaunchParamsModifier();
- doReturn(LETTERBOX_ASPECT_RATIO).when(()
- -> calculateAspectRatio(any(), any()));
final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT,
PORTRAIT_DISPLAY_BOUNDS);
- final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, false);
+ final Task task = createTask(display, /* isResizeable */ false);
+ final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
+ task, /* ignoreOrientationRequest */ true);
+
+ spyOn(activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy());
+ doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
+ .getDesktopAppCompatAspectRatioPolicy()).calculateAspectRatio(any());
final int desiredWidth = PORTRAIT_DISPLAY_BOUNDS.width()
- (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
final int desiredHeight = (int) (desiredWidth / LETTERBOX_ASPECT_RATIO);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate());
+ assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
+ .setActivity(activity).calculate());
assertEquals(desiredWidth, mResult.mBounds.width());
assertEquals(desiredHeight, mResult.mBounds.height());
}
@@ -755,24 +1265,64 @@ public class DesktopModeLaunchParamsModifierTests extends
assertEquals(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode);
}
- private Task createTask(DisplayContent display, int orientation, Boolean isResizeable) {
+ private Task createTask(DisplayContent display, Boolean isResizeable) {
final int resizeMode = isResizeable ? RESIZE_MODE_RESIZEABLE
: RESIZE_MODE_UNRESIZEABLE;
final Task task = new TaskBuilder(mSupervisor).setActivityType(
ACTIVITY_TYPE_STANDARD).setDisplay(display).build();
task.setResizeMode(resizeMode);
- mActivity = new ActivityBuilder(task.mAtmService)
+ return task;
+ }
+
+ private ActivityRecord createActivity(DisplayContent display, int orientation, Task task,
+ boolean ignoreOrientationRequest) {
+ final ActivityRecord activity = new ActivityBuilder(task.mAtmService)
.setTask(task)
+ .setComponent(ComponentName.createRelative(task.mAtmService.mContext,
+ DesktopModeLaunchParamsModifierTests.class.getName()))
+ .setUid(android.os.Process.myUid())
.setScreenOrientation(orientation)
.setOnTop(true).build();
+ activity.onDisplayChanged(display);
+ activity.setOccludesParent(true);
+ activity.setVisible(true);
+ activity.setVisibleRequested(true);
+ activity.mDisplayContent.setIgnoreOrientationRequest(ignoreOrientationRequest);
- mActivity.onDisplayChanged(display);
- mActivity.setOccludesParent(true);
- mActivity.setVisible(true);
- mActivity.setVisibleRequested(true);
- mActivity.mDisplayContent.setIgnoreOrientationRequest(/* ignoreOrientationRequest */ true);
+ return activity;
+ }
- return task;
+ private void setDesiredAspectRatio(ActivityRecord activity, float aspectRatio) {
+ final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
+ activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ spyOn(desktopAppCompatAspectRatioPolicy);
+ doReturn(aspectRatio).when(desktopAppCompatAspectRatioPolicy)
+ .getDesiredAspectRatio(any());
+ }
+
+ private void applyUserMinAspectRatioOverride(ActivityRecord activity, int overrideCode,
+ float overrideValue) {
+ // Set desired aspect ratio to be below minimum so override can take effect.
+ final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
+ activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ spyOn(desktopAppCompatAspectRatioPolicy);
+ doReturn(1f).when(desktopAppCompatAspectRatioPolicy)
+ .getDesiredAspectRatio(any());
+
+ // Enable user aspect ratio settings
+ final AppCompatConfiguration appCompatConfiguration =
+ activity.mWmService.mAppCompatConfiguration;
+ spyOn(appCompatConfiguration);
+ doReturn(true).when(appCompatConfiguration)
+ .isUserAppAspectRatioSettingsEnabled();
+
+ // Simulate user min aspect ratio override being set.
+ final AppCompatAspectRatioOverrides appCompatAspectRatioOverrides =
+ activity.mAppCompatController.getAppCompatAspectRatioOverrides();
+ spyOn(appCompatAspectRatioOverrides);
+ doReturn(overrideValue).when(appCompatAspectRatioOverrides).getUserMinAspectRatio();
+ doReturn(overrideCode).when(appCompatAspectRatioOverrides)
+ .getUserMinAspectRatioOverrideCode();
}
private TestDisplayContent createDisplayContent(int orientation, Rect displayBounds) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 65e3baad87d1..1e1055bb233a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -2394,7 +2394,13 @@ public class SizeCompatTests extends WindowTestsBase {
private void testUserOverrideAspectRatio(boolean isUnresizable, int screenOrientation,
float expectedAspectRatio, @PackageManager.UserMinAspectRatio int aspectRatio,
boolean enabled) {
- final ActivityRecord activity = getActivityBuilderOnSameTask().build();
+ final ActivityRecord activity = getActivityBuilderWithoutTask().build();
+ final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
+ activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ spyOn(desktopAppCompatAspectRatioPolicy);
+ doReturn(enabled).when(desktopAppCompatAspectRatioPolicy)
+ .hasMinAspectRatioOverride(any());
+ mTask.addChild(activity);
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
spyOn(activity.mWmService.mAppCompatConfiguration);
doReturn(enabled).when(activity.mWmService.mAppCompatConfiguration)
@@ -4944,8 +4950,11 @@ public class SizeCompatTests extends WindowTestsBase {
}
private ActivityBuilder getActivityBuilderOnSameTask() {
+ return getActivityBuilderWithoutTask().setTask(mTask);
+ }
+
+ private ActivityBuilder getActivityBuilderWithoutTask() {
return new ActivityBuilder(mAtm)
- .setTask(mTask)
.setComponent(ComponentName.createRelative(mContext,
SizeCompatTests.class.getName()))
.setUid(android.os.Process.myUid());
diff --git a/telephony/java/android/telephony/satellite/SatelliteSubscriberInfo.java b/telephony/java/android/telephony/satellite/SatelliteSubscriberInfo.java
index 50ed6270ccfc..dbe5dddf8ce8 100644
--- a/telephony/java/android/telephony/satellite/SatelliteSubscriberInfo.java
+++ b/telephony/java/android/telephony/satellite/SatelliteSubscriberInfo.java
@@ -268,7 +268,7 @@ public final class SatelliteSubscriberInfo implements Parcelable {
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (!(o instanceof SatelliteSubscriberProvisionStatus)) return false;
+ if (!(o instanceof SatelliteSubscriberInfo)) return false;
SatelliteSubscriberInfo that = (SatelliteSubscriberInfo) o;
return Objects.equals(mSubscriberId, that.mSubscriberId) && mCarrierId == that.mCarrierId
&& Objects.equals(mNiddApn, that.mNiddApn) && mSubId == that.mSubId
diff --git a/telephony/java/android/telephony/satellite/SatelliteSubscriberProvisionStatus.java b/telephony/java/android/telephony/satellite/SatelliteSubscriberProvisionStatus.java
index e3d619ea0fc8..08ef3f2d8d12 100644
--- a/telephony/java/android/telephony/satellite/SatelliteSubscriberProvisionStatus.java
+++ b/telephony/java/android/telephony/satellite/SatelliteSubscriberProvisionStatus.java
@@ -90,7 +90,7 @@ public class SatelliteSubscriberProvisionStatus implements Parcelable {
@Override
@FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
public void writeToParcel(@NonNull Parcel out, int flags) {
- mSubscriberInfo.writeToParcel(out, flags);
+ out.writeParcelable(mSubscriberInfo, flags);
out.writeBoolean(mProvisionStatus);
}
diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
index 3c72498082e4..8829f74f5092 100644
--- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
@@ -151,6 +151,7 @@ class InputManagerServiceTests {
verify(native).setTouchpadNaturalScrollingEnabled(anyBoolean())
verify(native).setTouchpadTapToClickEnabled(anyBoolean())
verify(native).setTouchpadTapDraggingEnabled(anyBoolean())
+ verify(native).setShouldNotifyTouchpadHardwareState(anyBoolean())
verify(native).setTouchpadRightClickZoneEnabled(anyBoolean())
verify(native).setShowTouches(anyBoolean())
verify(native).setMotionClassifierEnabled(anyBoolean())
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index cb4db57bae0c..7b086784761f 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -22,6 +22,7 @@ import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter
import com.android.hoststubgen.filters.ConstantFilter
import com.android.hoststubgen.filters.DefaultHookInjectingFilter
import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.filters.FilterRemapper
import com.android.hoststubgen.filters.ImplicitOutputFilter
import com.android.hoststubgen.filters.OutputFilter
import com.android.hoststubgen.filters.StubIntersectingFilter
@@ -75,7 +76,9 @@ class HostStubGen(val options: HostStubGenOptions) {
}
// Build the filters.
- val (filter, policyFileRemapper) = buildFilter(errors, allClasses, options)
+ val filter = buildFilter(errors, allClasses, options)
+
+ val filterRemapper = FilterRemapper(filter)
// Transform the jar.
convert(
@@ -87,7 +90,7 @@ class HostStubGen(val options: HostStubGenOptions) {
allClasses,
errors,
stats,
- policyFileRemapper,
+ filterRemapper,
options.numShards.get,
options.shard.get,
)
@@ -117,7 +120,7 @@ class HostStubGen(val options: HostStubGenOptions) {
errors: HostStubGenErrors,
allClasses: ClassNodes,
options: HostStubGenOptions,
- ): Pair<OutputFilter, Remapper?> {
+ ): OutputFilter {
// We build a "chain" of multiple filters here.
//
// The filters are build in from "inside", meaning the first filter created here is
@@ -170,14 +173,10 @@ class HostStubGen(val options: HostStubGenOptions) {
filter,
)
- var policyFileRemapper: Remapper? = null
-
// Next, "text based" filter, which allows to override polices without touching
// the target code.
options.policyOverrideFile.ifSet {
- val (f, p) = createFilterFromTextPolicyFile(it, allClasses, filter)
- filter = f
- policyFileRemapper = p
+ filter = createFilterFromTextPolicyFile(it, allClasses, filter)
}
// If `--intersect-stub-jar` is provided, load from these jar files too.
@@ -192,7 +191,7 @@ class HostStubGen(val options: HostStubGenOptions) {
// Apply the implicit filter.
filter = ImplicitOutputFilter(errors, allClasses, filter)
- return Pair(filter, policyFileRemapper)
+ return filter
}
/**
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
index 3f2b13aed5c0..f219dac7f0a5 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
@@ -117,6 +117,14 @@ fun resolveClassNameWithDefaultPackage(className: String, defaultPackageName: St
return "$defaultPackageName.$className"
}
+fun splitWithLastPeriod(name: String): Pair<String, String>? {
+ val pos = name.lastIndexOf('.')
+ if (pos < 0) {
+ return null
+ }
+ return Pair(name.substring(0, pos), name.substring(pos + 1))
+}
+
fun String.toJvmClassName(): String {
return this.replace('.', '/')
}
@@ -198,11 +206,11 @@ fun writeByteCodeToReturn(methodDescriptor: String, writer: MethodVisitor) {
/**
* Given a method descriptor, insert an [argType] as the first argument to it.
*/
-fun prependArgTypeToMethodDescriptor(methodDescriptor: String, argType: Type): String {
+fun prependArgTypeToMethodDescriptor(methodDescriptor: String, classInternalName: String): String {
val returnType = Type.getReturnType(methodDescriptor)
val argTypes = Type.getArgumentTypes(methodDescriptor).toMutableList()
- argTypes.add(0, argType)
+ argTypes.add(0, Type.getType("L" + classInternalName + ";"))
return Type.getMethodDescriptor(returnType, *argTypes.toTypedArray())
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
index cdd24e809ff8..6fcffb89924a 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
@@ -87,4 +87,23 @@ abstract class DelegatingFilter(
): List<String> {
return fallback.getMethodCallHooks(className, methodName, descriptor)
}
+
+ override fun remapType(className: String): String? {
+ return fallback.remapType(className)
+ }
+
+ override fun hasAnyMethodCallReplace(): Boolean {
+ return fallback.hasAnyMethodCallReplace()
+ }
+
+ override fun getMethodCallReplaceTo(
+ callerClassName: String,
+ callerMethodName: String,
+ className: String,
+ methodName: String,
+ descriptor: String,
+ ): MethodReplaceTarget? {
+ return fallback.getMethodCallReplaceTo(
+ callerClassName, callerMethodName, className, methodName, descriptor)
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
index 4d211065f1c8..f839444abb46 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
@@ -70,7 +70,7 @@ enum class FilterPolicy {
get() = this == SubstituteAndStub || this == SubstituteAndKeep
val needsInStub: Boolean
- get() = this == Stub || this == StubClass || this == SubstituteAndStub
+ get() = this == Stub || this == StubClass || this == SubstituteAndStub || this == Ignore
val needsInImpl: Boolean
get() = this != Remove
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt
new file mode 100644
index 000000000000..c5a2f9ff5e96
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 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.hoststubgen.filters
+
+import org.objectweb.asm.commons.Remapper
+
+/**
+ * A [Remapper] that uses [OutputFilter.remapType]
+ */
+class FilterRemapper(val filter: OutputFilter) : Remapper() {
+ private val cache = mutableMapOf<String, String>()
+
+ override fun mapType(typeInternalName: String?): String? {
+ if (typeInternalName == null) {
+ return null
+ }
+
+ cache[typeInternalName]?.let {
+ return it
+ }
+
+ var mapped = filter.remapType(typeInternalName) ?: typeInternalName
+ cache[typeInternalName] = mapped
+ return mapped
+ }
+
+ // TODO Do we need to implement mapPackage(), etc too?
+} \ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
index 3df16ffa99b3..1049e2bf94cf 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
@@ -89,4 +89,35 @@ abstract class OutputFilter {
List<String> {
return emptyList()
}
-} \ No newline at end of file
+
+ /**
+ * Take a class (internal) name. If the class needs to be renamed, return the new name.
+ * This is used by [FilterRemapper].
+ */
+ open fun remapType(className: String): String? {
+ return null
+ }
+
+ data class MethodReplaceTarget(val className: String, val methodName: String)
+
+ /**
+ * Return if this filter may return non-null from [getMethodCallReplaceTo].
+ * (Used for a small optimization)
+ */
+ open fun hasAnyMethodCallReplace(): Boolean {
+ return false
+ }
+
+ /**
+ * If a method call should be forwarded to another method, return the target's class / method.
+ */
+ open fun getMethodCallReplaceTo(
+ callerClassName: String,
+ callerMethodName: String,
+ className: String,
+ methodName: String,
+ descriptor: String,
+ ): MethodReplaceTarget? {
+ return null
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index 18280034c2f4..53bcf103cad4 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -17,12 +17,13 @@ package com.android.hoststubgen.filters
import com.android.hoststubgen.ParseException
import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.splitWithLastPeriod
import com.android.hoststubgen.asm.toHumanReadableClassName
+import com.android.hoststubgen.asm.toJvmClassName
import com.android.hoststubgen.log
import com.android.hoststubgen.normalizeTextLine
import com.android.hoststubgen.whitespaceRegex
import org.objectweb.asm.Opcodes
-import org.objectweb.asm.commons.Remapper
import org.objectweb.asm.tree.ClassNode
import java.io.BufferedReader
import java.io.FileReader
@@ -62,7 +63,7 @@ fun createFilterFromTextPolicyFile(
filename: String,
classes: ClassNodes,
fallback: OutputFilter,
- ): Pair<OutputFilter, Remapper?> {
+ ): OutputFilter {
log.i("Loading offloaded annotations from $filename ...")
log.withIndent {
val subclassFilter = SubclassFilter(classes, fallback)
@@ -75,7 +76,9 @@ fun createFilterFromTextPolicyFile(
var featureFlagsPolicy: FilterPolicyWithReason? = null
var syspropsPolicy: FilterPolicyWithReason? = null
var rFilePolicy: FilterPolicyWithReason? = null
- val typeRenameSpec = mutableListOf<TextFilePolicyRemapper.TypeRenameSpec>()
+ val typeRenameSpec = mutableListOf<TextFilePolicyRemapperFilter.TypeRenameSpec>()
+ val methodReplaceSpec =
+ mutableListOf<TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec>()
try {
BufferedReader(FileReader(filename)).use { reader ->
@@ -250,8 +253,24 @@ fun createFilterFromTextPolicyFile(
policy.getSubstitutionBasePolicy()
.withReason(FILTER_REASON))
- // Keep "from" -> "to" mapping.
- imf.setRenameTo(className, fromName, signature, name)
+ val classAndMethod = splitWithLastPeriod(fromName)
+ if (classAndMethod != null) {
+ // If the substitution target contains a ".", then
+ // it's a method call redirect.
+ methodReplaceSpec.add(
+ TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec(
+ className.toJvmClassName(),
+ name,
+ signature,
+ classAndMethod.first.toJvmClassName(),
+ classAndMethod.second,
+ )
+ )
+ } else {
+ // It's an in-class replace.
+ // ("@RavenwoodReplace" equivalent)
+ imf.setRenameTo(className, fromName, signature, name)
+ }
}
}
"r", "rename" -> {
@@ -267,7 +286,7 @@ fun createFilterFromTextPolicyFile(
// applied. (Which is needed for services.jar)
val prefix = fields[2].trimStart('/')
- typeRenameSpec += TextFilePolicyRemapper.TypeRenameSpec(
+ typeRenameSpec += TextFilePolicyRemapperFilter.TypeRenameSpec(
pattern, prefix)
}
@@ -281,16 +300,19 @@ fun createFilterFromTextPolicyFile(
throw e.withSourceInfo(filename, lineNo)
}
- var remapper: TextFilePolicyRemapper? = null
+ var ret: OutputFilter = imf
if (typeRenameSpec.isNotEmpty()) {
- remapper = TextFilePolicyRemapper(typeRenameSpec)
+ ret = TextFilePolicyRemapperFilter(typeRenameSpec, ret)
+ }
+ if (methodReplaceSpec.isNotEmpty()) {
+ ret = TextFilePolicyMethodReplaceFilter(methodReplaceSpec, classes, ret)
}
// Wrap the in-memory-filter with AHF.
- return Pair(
- AndroidHeuristicsFilter(
- classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, imf),
- remapper)
+ ret = AndroidHeuristicsFilter(
+ classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, ret)
+
+ return ret
}
}
@@ -330,6 +352,7 @@ private fun parsePolicy(s: String): FilterPolicy {
"r", "remove" -> FilterPolicy.Remove
"sc", "stubclass" -> FilterPolicy.StubClass
"kc", "keepclass" -> FilterPolicy.KeepClass
+ "i", "ignore" -> FilterPolicy.Ignore
else -> {
if (s.startsWith("@")) {
FilterPolicy.SubstituteAndStub
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
new file mode 100644
index 000000000000..d45f41407a52
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 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.hoststubgen.filters
+
+import com.android.hoststubgen.asm.ClassNodes
+
+/**
+ * Filter used by TextFileFilterPolicyParser for "method call relacement".
+ */
+class TextFilePolicyMethodReplaceFilter(
+ val spec: List<MethodCallReplaceSpec>,
+ val classes: ClassNodes,
+ val fallback: OutputFilter,
+) : DelegatingFilter(fallback) {
+
+ data class MethodCallReplaceSpec(
+ val fromClass: String,
+ val fromMethod: String,
+ val fromDescriptor: String,
+ val toClass: String,
+ val toMethod: String,
+ )
+
+ override fun hasAnyMethodCallReplace(): Boolean {
+ return true
+ }
+
+ override fun getMethodCallReplaceTo(
+ callerClassName: String,
+ callerMethodName: String,
+ className: String,
+ methodName: String,
+ descriptor: String,
+ ): MethodReplaceTarget? {
+ // Maybe use 'Tri' if we end up having too many replacements.
+ spec.forEach {
+ if (className == it.fromClass &&
+ methodName == it.fromMethod &&
+ descriptor == it.fromDescriptor
+ ) {
+ return MethodReplaceTarget(it.toClass, it.toMethod)
+ }
+ }
+ return null
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapper.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
index 2d94bb4758ba..a78c6552b8d0 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapper.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
@@ -16,15 +16,15 @@
package com.android.hoststubgen.filters
import com.android.hoststubgen.log
-import org.objectweb.asm.commons.Remapper
import java.util.regex.Pattern
/**
- * A [Remapper] that provides a simple "jarjar" functionality.
+ * A filter that provides a simple "jarjar" functionality via [mapType]
*/
-class TextFilePolicyRemapper(
- val typeRenameSpecs: List<TypeRenameSpec>
-) : Remapper() {
+class TextFilePolicyRemapperFilter(
+ val typeRenameSpecs: List<TypeRenameSpec>,
+ fallback: OutputFilter,
+) : DelegatingFilter(fallback) {
/**
* When a package name matches [typeInternalNamePattern], we prepend [typeInternalNamePrefix]
* to it.
@@ -36,24 +36,15 @@ class TextFilePolicyRemapper(
private val cache = mutableMapOf<String, String>()
- override fun mapType(typeInternalName: String): String {
-// if (typeInternalName == null) {
-// return null // do we need it??
-// }
- cache[typeInternalName]?.let {
- return it
- }
-
- var mapped: String = typeInternalName
+ override fun remapType(className: String): String? {
+ var mapped: String = className
typeRenameSpecs.forEach {
- if (it.typeInternalNamePattern.matcher(typeInternalName).matches()) {
- mapped = it.typeInternalNamePrefix + typeInternalName
- log.d("Renaming type $typeInternalName to $mapped")
+ if (it.typeInternalNamePattern.matcher(className).matches()) {
+ mapped = it.typeInternalNamePrefix + className
+ log.d("Renaming type $className to $mapped")
}
}
- cache[typeInternalName] = mapped
+ cache[className] = mapped
return mapped
}
-
- // TODO Do we need to implement mapPackage(), etc too?
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
index 416b78242899..3d2e1429a30f 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
@@ -33,6 +33,9 @@ import com.android.hoststubgen.log
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
+import org.objectweb.asm.Opcodes.INVOKEINTERFACE
+import org.objectweb.asm.Opcodes.INVOKESTATIC
+import org.objectweb.asm.Opcodes.INVOKEVIRTUAL
import org.objectweb.asm.Type
/**
@@ -211,17 +214,14 @@ class ImplGeneratingAdapter(
}
if (policy.policy == FilterPolicy.Ignore) {
- when (Type.getReturnType(descriptor)) {
- Type.VOID_TYPE -> {
- log.v("Making method ignored...")
- return IgnoreMethodAdapter(
- access, name, descriptor, signature, exceptions, innerVisitor)
- .withAnnotation(HostStubGenProcessedAsIgnore.CLASS_DESCRIPTOR)
- }
- else -> {
- throw RuntimeException("Ignored policy only allowed for void methods")
- }
- }
+ log.v("Making method ignored...")
+ return IgnoreMethodAdapter(
+ access, name, descriptor, signature, exceptions, innerVisitor)
+ .withAnnotation(HostStubGenProcessedAsIgnore.CLASS_DESCRIPTOR)
+ }
+ if (filter.hasAnyMethodCallReplace()) {
+ innerVisitor = MethodCallReplacingAdapter(
+ access, name, descriptor, signature, exceptions, innerVisitor)
}
}
if (substituted) {
@@ -290,14 +290,37 @@ class ImplGeneratingAdapter(
*/
private inner class IgnoreMethodAdapter(
access: Int,
- val name: String,
- descriptor: String,
+ name: String,
+ val descriptor: String,
signature: String?,
exceptions: Array<String>?,
next: MethodVisitor?
) : BodyReplacingMethodVisitor(access, name, descriptor, signature, exceptions, next) {
override fun emitNewCode() {
- visitInsn(Opcodes.RETURN)
+ when (Type.getReturnType(descriptor)) {
+ Type.VOID_TYPE -> visitInsn(Opcodes.RETURN)
+ Type.BOOLEAN_TYPE, Type.BYTE_TYPE, Type.CHAR_TYPE, Type.SHORT_TYPE,
+ Type.INT_TYPE -> {
+ visitInsn(Opcodes.ICONST_0)
+ visitInsn(Opcodes.IRETURN)
+ }
+ Type.LONG_TYPE -> {
+ visitInsn(Opcodes.LCONST_0)
+ visitInsn(Opcodes.LRETURN)
+ }
+ Type.FLOAT_TYPE -> {
+ visitInsn(Opcodes.FCONST_0)
+ visitInsn(Opcodes.FRETURN)
+ }
+ Type.DOUBLE_TYPE -> {
+ visitInsn(Opcodes.DCONST_0)
+ visitInsn(Opcodes.DRETURN)
+ }
+ else -> {
+ visitInsn(Opcodes.ACONST_NULL)
+ visitInsn(Opcodes.ARETURN)
+ }
+ }
visitMaxs(0, 0) // We let ASM figure them out.
}
}
@@ -332,11 +355,9 @@ class ImplGeneratingAdapter(
// Update the descriptor -- add this class's type as the first argument
// to the method descriptor.
- val thisType = Type.getType("L" + currentClassName + ";")
-
targetDescriptor = prependArgTypeToMethodDescriptor(
- descriptor,
- thisType,
+ descriptor,
+ currentClassName,
)
// Shift the original arguments by one.
@@ -451,4 +472,61 @@ class ImplGeneratingAdapter(
false)
}
}
+
+ private inner class MethodCallReplacingAdapter(
+ access: Int,
+ val callerMethodName: String,
+ val descriptor: String,
+ signature: String?,
+ exceptions: Array<String>?,
+ next: MethodVisitor?,
+ ) : MethodVisitor(OPCODE_VERSION, next) {
+ override fun visitMethodInsn(
+ opcode: Int,
+ owner: String?,
+ name: String?,
+ descriptor: String?,
+ isInterface: Boolean,
+ ) {
+ when (opcode) {
+ INVOKESTATIC, INVOKEVIRTUAL, INVOKEINTERFACE -> {}
+ else -> {
+ // Don't touch other opcodes.
+ super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
+ return
+ }
+ }
+ val to = filter.getMethodCallReplaceTo(
+ currentClassName, callerMethodName, owner!!, name!!, descriptor!!)
+
+ if (to == null
+ // Don't replace if the target is the callsite.
+ || (to.className == currentClassName && to.methodName == callerMethodName)
+ ) {
+ super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
+ return
+ }
+
+ // Replace the method call with a (static) call to the target method.
+ // If it's a non-static call, the target method's first argument will receive "this".
+ // (Because of that, we don't need to manipulate the stack. Just replace the
+ // method call.)
+
+ val toDesc = if (opcode == INVOKESTATIC) {
+ // Static call to static call, no need to change the desc.
+ descriptor
+ } else {
+ // Need to prepend the "this" type to the descriptor.
+ prependArgTypeToMethodDescriptor(descriptor, owner)
+ }
+
+ mv.visitMethodInsn(
+ INVOKESTATIC,
+ to.className,
+ to.methodName,
+ toDesc,
+ false
+ )
+ }
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index c127e677f84d..c2f593cf5ae3 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -1436,7 +1436,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
super_class: #x // java/lang/Object
- interfaces: 0, fields: 3, methods: 10, attributes: 1
+ interfaces: 0, fields: 3, methods: 19, attributes: 1
public int stub;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -1513,6 +1513,132 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
0 8 1 foo Ljava/lang/String;
+ public java.lang.String toBeIgnoredObj();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public void toBeIgnoredV();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public boolean toBeIgnoredZ();
+ descriptor: ()Z
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public byte toBeIgnoredB();
+ descriptor: ()B
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public char toBeIgnoredC();
+ descriptor: ()C
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public short toBeIgnoredS();
+ descriptor: ()S
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public int toBeIgnoredI();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public float toBeIgnoredF();
+ descriptor: ()F
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+ public double toBeIgnoredD();
+ descriptor: ()D
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
public int addTwo(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
@@ -1897,6 +2023,174 @@ BootstrapMethods:
InnerClasses:
public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo;
+
+ public static void startThread(java.lang.Thread);
+ descriptor: (Ljava/lang/Thread;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: iconst_1
+ x: invokevirtual #x // Method java/lang/Thread.setDaemon:(Z)V
+ x: aload_0
+ x: invokevirtual #x // Method java/lang/Thread.start:()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 thread Ljava/lang/Thread;
+
+ public static int add(int, int);
+ descriptor: (II)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+ 0 4 1 b I
+}
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 5, attributes: 5
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace;
+
+ public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+ descriptor: ()Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=2, args_size=0
+ x: new #x // class java/util/concurrent/atomic/AtomicBoolean
+ x: dup
+ x: iconst_0
+ x: invokespecial #x // Method java/util/concurrent/atomic/AtomicBoolean."<init>":(Z)V
+ x: astore_0
+ x: new #x // class java/lang/Thread
+ x: dup
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:run:(Ljava/util/concurrent/atomic/AtomicBoolean;)Ljava/lang/Runnable;
+ x: invokespecial #x // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
+ x: astore_1
+ x: aload_1
+ x: invokevirtual #x // Method java/lang/Thread.start:()V
+ x: aload_1
+ x: invokevirtual #x // Method java/lang/Thread.join:()V
+ x: aload_0
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.get:()Z
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 9 27 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ 23 13 1 th Ljava/lang/Thread;
+ Exceptions:
+ throws java.lang.Exception
+
+ public static int staticMethodCallReplaceTester();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: iconst_1
+ x: iconst_2
+ x: invokestatic #x // Method originalAdd:(II)I
+ x: ireturn
+ LineNumberTable:
+
+ private static int originalAdd(int, int);
+ descriptor: (II)I
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: iconst_1
+ x: isub
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 a I
+ 0 6 1 b I
+
+ private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+ descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
+ x: invokevirtual #x // Method java/lang/Thread.isDaemon:()Z
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+}
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()V
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ #x ()V
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
Compiled from "TinyFrameworkNative.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index 17ba48c67d98..1b83d244c55c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -1197,7 +1197,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 5, attributes: 2
+ interfaces: 0, fields: 1, methods: 14, attributes: 2
public int stub;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -1239,6 +1239,150 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ public java.lang.String toBeIgnoredObj();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public void toBeIgnoredV();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public boolean toBeIgnoredZ();
+ descriptor: ()Z
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public byte toBeIgnoredB();
+ descriptor: ()B
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public char toBeIgnoredC();
+ descriptor: ()C
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public short toBeIgnoredS();
+ descriptor: ()S
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int toBeIgnoredI();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public float toBeIgnoredF();
+ descriptor: ()F
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public double toBeIgnoredD();
+ descriptor: ()D
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
public int addTwo(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
@@ -1640,6 +1784,161 @@ RuntimeInvisibleAnnotations:
android.hosttest.annotation.HostSideTestStaticInitializerKeep
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static void startThread(java.lang.Thread);
+ descriptor: (Ljava/lang/Thread;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int add(int, int);
+ descriptor: (II)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 4, attributes: 5
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+ descriptor: ()Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ Exceptions:
+ throws java.lang.Exception
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int staticMethodCallReplaceTester();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+ descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
Compiled from "TinyFrameworkNative.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index 0f5f7e747a2e..d23b450c4076 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -1730,7 +1730,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 8, attributes: 2
+ interfaces: 0, fields: 2, methods: 17, attributes: 2
public int stub;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -1825,6 +1825,140 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ public java.lang.String toBeIgnoredObj();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aconst_null
+ x: areturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public void toBeIgnoredV();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=0, locals=1, args_size=1
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public boolean toBeIgnoredZ();
+ descriptor: ()Z
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public byte toBeIgnoredB();
+ descriptor: ()B
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public char toBeIgnoredC();
+ descriptor: ()C
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public short toBeIgnoredS();
+ descriptor: ()S
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int toBeIgnoredI();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public float toBeIgnoredF();
+ descriptor: ()F
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: fconst_0
+ x: freturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public double toBeIgnoredD();
+ descriptor: ()D
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: dconst_0
+ x: dreturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
public int addTwo(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
@@ -2330,6 +2464,202 @@ BootstrapMethods:
#x ()Ljava/lang/Integer;
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static void startThread(java.lang.Thread);
+ descriptor: (Ljava/lang/Thread;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: iconst_1
+ x: invokevirtual #x // Method java/lang/Thread.setDaemon:(Z)V
+ x: aload_0
+ x: invokevirtual #x // Method java/lang/Thread.start:()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 thread Ljava/lang/Thread;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int add(int, int);
+ descriptor: (II)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+ 0 4 1 b I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 4, attributes: 6
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+ descriptor: ()Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=2, args_size=0
+ x: new #x // class java/util/concurrent/atomic/AtomicBoolean
+ x: dup
+ x: iconst_0
+ x: invokespecial #x // Method java/util/concurrent/atomic/AtomicBoolean."<init>":(Z)V
+ x: astore_0
+ x: new #x // class java/lang/Thread
+ x: dup
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:run:(Ljava/util/concurrent/atomic/AtomicBoolean;)Ljava/lang/Runnable;
+ x: invokespecial #x // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
+ x: astore_1
+ x: aload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.startThread:(Ljava/lang/Thread;)V
+ x: aload_1
+ x: invokevirtual #x // Method java/lang/Thread.join:()V
+ x: aload_0
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.get:()Z
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 9 27 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ 23 13 1 th Ljava/lang/Thread;
+ Exceptions:
+ throws java.lang.Exception
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int staticMethodCallReplaceTester();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: iconst_1
+ x: iconst_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.add:(II)I
+ x: ireturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+ descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
+ x: invokevirtual #x // Method java/lang/Thread.isDaemon:()Z
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()V
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ #x ()V
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
Compiled from "TinyFrameworkNative.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index 17ba48c67d98..1b83d244c55c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -1197,7 +1197,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 5, attributes: 2
+ interfaces: 0, fields: 1, methods: 14, attributes: 2
public int stub;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -1239,6 +1239,150 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ public java.lang.String toBeIgnoredObj();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public void toBeIgnoredV();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public boolean toBeIgnoredZ();
+ descriptor: ()Z
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public byte toBeIgnoredB();
+ descriptor: ()B
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public char toBeIgnoredC();
+ descriptor: ()C
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public short toBeIgnoredS();
+ descriptor: ()S
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int toBeIgnoredI();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public float toBeIgnoredF();
+ descriptor: ()F
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public double toBeIgnoredD();
+ descriptor: ()D
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
public int addTwo(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
@@ -1640,6 +1784,161 @@ RuntimeInvisibleAnnotations:
android.hosttest.annotation.HostSideTestStaticInitializerKeep
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static void startThread(java.lang.Thread);
+ descriptor: (Ljava/lang/Thread;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int add(int, int);
+ descriptor: (II)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 4, attributes: 5
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+ descriptor: ()Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ Exceptions:
+ throws java.lang.Exception
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int staticMethodCallReplaceTester();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+ descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
Compiled from "TinyFrameworkNative.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 3beea643823a..d12a23d3d68f 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -2141,7 +2141,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 8, attributes: 2
+ interfaces: 0, fields: 2, methods: 17, attributes: 2
public int stub;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -2254,13 +2254,192 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ public java.lang.String toBeIgnoredObj();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredObj
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aconst_null
+ x: areturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public void toBeIgnoredV();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredV
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public boolean toBeIgnoredZ();
+ descriptor: ()Z
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredZ
+ x: ldc #x // String ()Z
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public byte toBeIgnoredB();
+ descriptor: ()B
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredB
+ x: ldc #x // String ()B
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public char toBeIgnoredC();
+ descriptor: ()C
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredC
+ x: ldc #x // String ()C
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public short toBeIgnoredS();
+ descriptor: ()S
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredS
+ x: ldc #x // String ()S
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int toBeIgnoredI();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredI
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public float toBeIgnoredF();
+ descriptor: ()F
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredF
+ x: ldc #x // String ()F
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: fconst_0
+ x: freturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public double toBeIgnoredD();
+ descriptor: ()D
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String toBeIgnoredD
+ x: ldc #x // String ()D
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: dconst_0
+ x: dreturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
public int addTwo(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
- x: ldc #x // String addTwo
+ x: ldc #x // String addTwo
x: ldc #x // String (I)I
x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
@@ -2287,7 +2466,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
Code:
stack=4, locals=1, args_size=1
x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
- x: ldc #x // String nativeAddThree
+ x: ldc #x // String nativeAddThree
x: ldc #x // String (I)I
x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
@@ -2313,21 +2492,21 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
Code:
stack=4, locals=1, args_size=1
x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
- x: ldc #x // String unsupportedMethod
+ x: ldc #x // String unsupportedMethod
x: ldc #x // String ()Ljava/lang/String;
x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
- x: ldc #x // String unsupportedMethod
+ x: ldc #x // String unsupportedMethod
x: ldc #x // String ()Ljava/lang/String;
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
- x: new #x // class java/lang/RuntimeException
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
x: dup
- x: ldc #x // String Unreachable
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
x: athrow
RuntimeVisibleAnnotations:
x: #x()
@@ -2341,12 +2520,12 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
Code:
stack=4, locals=1, args_size=1
x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
- x: ldc #x // String visibleButUsesUnsupportedMethod
+ x: ldc #x // String visibleButUsesUnsupportedMethod
x: ldc #x // String ()Ljava/lang/String;
x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
x: aload_0
- x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
x: areturn
LineNumberTable:
LocalVariableTable:
@@ -2865,6 +3044,257 @@ BootstrapMethods:
#x ()Ljava/lang/Integer;
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 4, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static void startThread(java.lang.Thread);
+ descriptor: (Ljava/lang/Thread;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ x: ldc #x // String startThread
+ x: ldc #x // String (Ljava/lang/Thread;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: iconst_1
+ x: invokevirtual #x // Method java/lang/Thread.setDaemon:(Z)V
+ x: aload_0
+ x: invokevirtual #x // Method java/lang/Thread.start:()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 thread Ljava/lang/Thread;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int add(int, int);
+ descriptor: (II)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+ x: ldc #x // String add
+ x: ldc #x // String (II)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 a I
+ 11 4 1 b I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+ Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 5, attributes: 6
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+ descriptor: ()Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String nonStaticMethodCallReplaceTester
+ x: ldc #x // String ()Z
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class java/util/concurrent/atomic/AtomicBoolean
+ x: dup
+ x: iconst_0
+ x: invokespecial #x // Method java/util/concurrent/atomic/AtomicBoolean."<init>":(Z)V
+ x: astore_0
+ x: new #x // class java/lang/Thread
+ x: dup
+ x: aload_0
+ x: invokedynamic #x, 0 // InvokeDynamic #x:run:(Ljava/util/concurrent/atomic/AtomicBoolean;)Ljava/lang/Runnable;
+ x: invokespecial #x // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
+ x: astore_1
+ x: aload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.startThread:(Ljava/lang/Thread;)V
+ x: aload_1
+ x: invokevirtual #x // Method java/lang/Thread.join:()V
+ x: aload_0
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.get:()Z
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 20 27 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ 34 13 1 th Ljava/lang/Thread;
+ Exceptions:
+ throws java.lang.Exception
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int staticMethodCallReplaceTester();
+ descriptor: ()I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String staticMethodCallReplaceTester
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_1
+ x: iconst_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.add:(II)I
+ x: ireturn
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+ descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ x: ldc #x // String lambda$nonStaticMethodCallReplaceTester$0
+ x: ldc #x // String (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
+ x: invokevirtual #x // Method java/lang/Thread.isDaemon:()Z
+ x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 11 0 ab Ljava/util/concurrent/atomic/AtomicBoolean;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+ public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+BootstrapMethods:
+ x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+ Method arguments:
+ #x ()V
+ #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+ #x ()V
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
Compiled from "TinyFrameworkNative.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
index 75c9721020bd..f06443362b1d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
@@ -12,6 +12,16 @@ class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy stub
# method addThree_host (I)I # used as a substitute
method unsupportedMethod ()Ljava/lang/String; throw
method visibleButUsesUnsupportedMethod ()Ljava/lang/String; stub
+ method toBeIgnoredObj ()Ljava/lang/String; ignore
+ method toBeIgnoredV ()V ignore
+ method toBeIgnoredZ ()Z ignore
+ method toBeIgnoredB ()B ignore
+ method toBeIgnoredC ()C ignore
+ method toBeIgnoredS ()S ignore
+ method toBeIgnoredI ()I ignore
+ method toBeIgnoredL ()L ignore
+ method toBeIgnoredF ()F ignore
+ method toBeIgnoredD ()D ignore
# Class load hook
class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy ~com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
@@ -49,8 +59,18 @@ class com.android.hoststubgen.test.tinyframework.packagetest.sub.B remove
# class com.android.hoststubgen.test.tinyframework.packagetest.A stub
# class com.android.hoststubgen.test.tinyframework.packagetest.sub.A stub
+# Used to test method call replacement.
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace stubclass
+ method originalAdd (II)I @com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo.add
+
+# Used to test method call replacement.
+# Note because java.lang.Thread is _not_ within the tiny-framework jar, the policy ("keep")
+# doesn't realy matter.
+class java.lang.Thread keep
+ method start ()V @com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo.startThread
+
# "rename" takes a type internal name, so '/'s is used as a separator.
# The leading / in the prefix is not needed (it'll be stripped), but it's added to make
# sure the stripping works.
-rename ^.*/TinyFrameworkToBeRenamed$ /rename_prefix/ \ No newline at end of file
+rename ^.*/TinyFrameworkToBeRenamed$ /rename_prefix/
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
index bde7c35dc294..1977c900ba11 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
@@ -42,6 +42,42 @@ public class TinyFrameworkForTextPolicy {
throw new RuntimeException();
}
+ public String toBeIgnoredObj() {
+ throw new RuntimeException();
+ }
+
+ public void toBeIgnoredV() {
+ throw new RuntimeException();
+ }
+
+ public boolean toBeIgnoredZ() {
+ throw new RuntimeException();
+ }
+
+ public byte toBeIgnoredB() {
+ throw new RuntimeException();
+ }
+
+ public char toBeIgnoredC() {
+ throw new RuntimeException();
+ }
+
+ public short toBeIgnoredS() {
+ throw new RuntimeException();
+ }
+
+ public int toBeIgnoredI() {
+ throw new RuntimeException();
+ }
+
+ public float toBeIgnoredF() {
+ throw new RuntimeException();
+ }
+
+ public double toBeIgnoredD() {
+ throw new RuntimeException();
+ }
+
public int addTwo(int value) {
throw new RuntimeException("not supported on host side");
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java
new file mode 100644
index 000000000000..1ff37441c262
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 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.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkMethodCallReplace {
+ // This method should return true.
+ public static boolean nonStaticMethodCallReplaceTester() throws Exception {
+ final AtomicBoolean ab = new AtomicBoolean(false);
+
+ Thread th = new Thread(() -> {
+ ab.set(Thread.currentThread().isDaemon());
+ });
+ // This Thread.start() call will be redirected to ReplaceTo.startThread()
+ // (because of the policy file directive) which will make the thread "daemon" and start it.
+ th.start();
+ th.join();
+
+ return ab.get(); // This should be true.
+ }
+
+ public static int staticMethodCallReplaceTester() {
+ // This method call will be replaced with ReplaceTo.add().
+ return originalAdd(1, 2);
+ }
+
+ private static int originalAdd(int a, int b) {
+ return a + b - 1; // Original is broken.
+ }
+
+ public static class ReplaceTo {
+ public static void startThread(Thread thread) {
+ thread.setDaemon(true);
+ thread.start();
+ }
+
+ public static int add(int a, int b) {
+ return a + b;
+ }
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index bf0f6545d1f5..1692c6e89e8c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -53,6 +53,20 @@ public class TinyFrameworkClassTest {
// }
@Test
+ public void testIgnore() {
+ TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
+ tfc.toBeIgnoredV();
+ assertThat(tfc.toBeIgnoredZ()).isEqualTo(false);
+ assertThat(tfc.toBeIgnoredB()).isEqualTo(0);
+ assertThat(tfc.toBeIgnoredC()).isEqualTo(0);
+ assertThat(tfc.toBeIgnoredS()).isEqualTo(0);
+ assertThat(tfc.toBeIgnoredI()).isEqualTo(0);
+ assertThat(tfc.toBeIgnoredF()).isEqualTo(0);
+ assertThat(tfc.toBeIgnoredD()).isEqualTo(0);
+ assertThat(tfc.toBeIgnoredObj()).isEqualTo(null);
+ }
+
+ @Test
public void testSubstitute() {
TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
assertThat(tfc.addTwo(1)).isEqualTo(3);
@@ -339,4 +353,16 @@ public class TinyFrameworkClassTest {
public void testTypeRename() {
assertThat(TinyFrameworkRenamedClassCaller.foo(1)).isEqualTo(1);
}
+
+ @Test
+ public void testMethodCallReplaceNonStatic() throws Exception {
+ assertThat(TinyFrameworkMethodCallReplace.nonStaticMethodCallReplaceTester())
+ .isEqualTo(true);
+ }
+
+ @Test
+ public void testMethodCallReplaceStatic() throws Exception {
+ assertThat(TinyFrameworkMethodCallReplace.staticMethodCallReplaceTester())
+ .isEqualTo(3);
+ }
}