summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt1
-rw-r--r--core/api/system-current.txt1
-rw-r--r--core/java/Android.bp33
-rw-r--r--core/java/android/app/AppOpsManager.java4
-rw-r--r--core/java/android/app/NotificationManager.java47
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceParams.java22
-rw-r--r--core/java/android/hardware/devicestate/feature/flags.aconfig9
-rw-r--r--core/java/android/os/BatteryStats.java4
-rw-r--r--core/java/android/os/ConcurrentMessageQueue/MessageQueue.java1648
-rw-r--r--core/java/android/os/Environment.java20
-rw-r--r--core/java/android/os/LegacyMessageQueue/MessageQueue.java (renamed from core/java/android/os/MessageQueue.java)19
-rw-r--r--core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java1589
-rw-r--r--core/java/android/provider/Settings.java14
-rw-r--r--core/java/android/provider/Telephony.java16
-rw-r--r--core/java/android/service/dreams/DreamService.java16
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl2
-rw-r--r--core/java/android/service/dreams/flags.aconfig10
-rw-r--r--core/java/android/tracing/flags.aconfig8
-rw-r--r--core/java/android/view/ImeBackAnimationController.java33
-rw-r--r--core/java/android/view/View.java5
-rw-r--r--core/java/android/view/ViewRootImpl.java21
-rw-r--r--core/java/android/view/autofill/AutofillFeatureFlags.java31
-rw-r--r--core/java/android/view/autofill/AutofillManager.java46
-rw-r--r--core/java/android/view/autofill/OWNERS5
-rw-r--r--core/java/android/view/flags/view_flags.aconfig8
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java3
-rw-r--r--core/java/android/window/flags/windowing_sdk.aconfig11
-rw-r--r--core/java/com/android/internal/protolog/ProtoLog.java (renamed from core/java/com/android/internal/protolog/common/ProtoLog.java)8
-rw-r--r--core/res/res/anim/overlay_task_fragment_change.xml20
-rw-r--r--core/res/res/anim/overlay_task_fragment_close_to_bottom.xml24
-rw-r--r--core/res/res/anim/overlay_task_fragment_close_to_left.xml24
-rw-r--r--core/res/res/anim/overlay_task_fragment_close_to_right.xml24
-rw-r--r--core/res/res/anim/overlay_task_fragment_close_to_top.xml24
-rw-r--r--core/res/res/anim/overlay_task_fragment_open_from_bottom.xml24
-rw-r--r--core/res/res/anim/overlay_task_fragment_open_from_left.xml24
-rw-r--r--core/res/res/anim/overlay_task_fragment_open_from_right.xml24
-rw-r--r--core/res/res/anim/overlay_task_fragment_open_from_top.xml24
-rw-r--r--core/res/res/layout/notification_template_header.xml2
-rw-r--r--core/res/res/values/strings.xml10
-rw-r--r--core/res/res/values/symbols.xml9
-rw-r--r--core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java33
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java123
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java66
-rw-r--r--libs/WindowManager/Shell/Android.bp6
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS4
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.pngbin56102 -> 56623 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.pngbin56102 -> 56623 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt2
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java50
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java34
-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/CustomCrossActivityBackAnimation.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.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/BubbleData.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/BubbleOverflowContainerView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java2
-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/common/SyncTransactionQueue.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipPerfHintController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt2
-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/SplitLayout.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/GlobalDragListener.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.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.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java2
-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/PipInputConsumer.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/pip/phone/PipTouchHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.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/PipInputConsumer.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/pip2/phone/PipScheduler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchState.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/MainStage.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java2
-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/startingsurface/SplashscreenContentDrawer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.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/TaskSnapshotWindow.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java2
-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/RemoteTransitionHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.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/util/KtProtoLog.kt16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java19
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java17
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt20
-rw-r--r--media/tests/MediaFrameworkTest/Android.bp1
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt28
-rw-r--r--packages/SettingsLib/aconfig/settingslib.aconfig7
-rw-r--r--packages/SettingsLib/res/values/strings.xml8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java52
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java67
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig10
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt9
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt22
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java35
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt11
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt38
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt97
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt1
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt1
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt22
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt21
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java17
-rw-r--r--packages/SystemUI/res/color/connected_network_primary_color.xml20
-rw-r--r--packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml3
-rw-r--r--packages/SystemUI/res/drawable/settingslib_thumb_on.xml5
-rw-r--r--packages/SystemUI/res/drawable/settingslib_track_on_background.xml3
-rw-r--r--packages/SystemUI/res/values-night/colors.xml4
-rw-r--r--packages/SystemUI/res/values-night/styles.xml12
-rw-r--r--packages/SystemUI/res/values/colors.xml3
-rw-r--r--packages/SystemUI/res/values/ids.xml1
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/res/values/styles.xml8
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt43
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt116
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java83
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerKosmos.kt47
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt10
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java6
-rw-r--r--services/autofill/java/com/android/server/autofill/RequestId.java152
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java17
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java27
-rw-r--r--services/core/Android.bp6
-rw-r--r--services/core/java/com/android/server/SystemServerInitThreadPool.java4
-rw-r--r--services/core/java/com/android/server/Watchdog.java9
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/ProcessErrorStateRecord.java22
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java4
-rw-r--r--services/core/java/com/android/server/am/StackTracesDumpHelper.java26
-rw-r--r--services/core/java/com/android/server/am/flags.aconfig10
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java33
-rw-r--r--services/core/java/com/android/server/audio/AudioServiceEvents.java19
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerService.java67
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java5
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java32
-rw-r--r--services/core/java/com/android/server/health/HealthServiceWrapper.java15
-rw-r--r--services/core/java/com/android/server/health/HealthServiceWrapperAidl.java11
-rw-r--r--services/core/java/com/android/server/input/BatteryController.java7
-rw-r--r--services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java4
-rw-r--r--services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java71
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeTrackerService.java5
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java112
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodBindingController.java7
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java168
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubService.java21
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java2
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java25
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java8
-rw-r--r--services/core/java/com/android/server/stats/pull/BatteryHealthUtility.java89
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java53
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRefresher.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java2
-rw-r--r--services/core/java/com/android/server/wm/AnrController.java2
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java2
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java2
-rw-r--r--services/core/java/com/android/server/wm/BLASTSyncEngine.java2
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java2
-rw-r--r--services/core/java/com/android/server/wm/BlackFrame.java2
-rw-r--r--services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/CameraStateMonitor.java2
-rw-r--r--services/core/java/com/android/server/wm/CompatModePackages.java2
-rw-r--r--services/core/java/com/android/server/wm/ContentRecorder.java2
-rw-r--r--services/core/java/com/android/server/wm/ContentRecordingController.java2
-rw-r--r--services/core/java/com/android/server/wm/DeferredDisplayUpdater.java2
-rw-r--r--services/core/java/com/android/server/wm/DimmerAnimationHelper.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotationReversionController.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java67
-rw-r--r--services/core/java/com/android/server/wm/DragState.java2
-rw-r--r--services/core/java/com/android/server/wm/EmbeddedWindowController.java2
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java2
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java2
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java2
-rw-r--r--services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java2
-rw-r--r--services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java2
-rw-r--r--services/core/java/com/android/server/wm/RemoteAnimationController.java2
-rw-r--r--services/core/java/com/android/server/wm/RemoteDisplayChangeController.java2
-rw-r--r--services/core/java/com/android/server/wm/ResetTargetTaskHelper.java2
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java2
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/Session.java2
-rw-r--r--services/core/java/com/android/server/wm/SmoothDimmer.java2
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java2
-rw-r--r--services/core/java/com/android/server/wm/SurfaceFreezer.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java2
-rw-r--r--services/core/java/com/android/server/wm/Transition.java2
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java2
-rw-r--r--services/core/java/com/android/server/wm/TrustedPresentationListenerController.java2
-rw-r--r--services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java2
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java2
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContainerThumbnail.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContextListenerController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowTracing.java2
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt46
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java21
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java4
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java1
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/autofill/RequestIdTest.java161
-rw-r--r--services/tests/wmtests/Android.bp2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java122
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java22
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java13
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java13
-rw-r--r--telephony/java/android/telephony/SubscriptionInfo.java49
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java45
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java22
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt5
-rw-r--r--tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt8
381 files changed, 6693 insertions, 1313 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 44a6c6b2803b..5456c15040ce 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -43901,6 +43901,7 @@ package android.telephony {
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT = "satellite_connection_hysteresis_sec_int";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT = "satellite_entitlement_status_refresh_days_int";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL = "satellite_entitlement_supported_bool";
+ field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ESOS_SUPPORTED_BOOL = "satellite_esos_supported_bool";
field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 4536f6f740ad..cd2c9ca55959 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3524,6 +3524,7 @@ package android.companion.virtual {
field @Deprecated public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
field @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public static final int POLICY_TYPE_ACTIVITY = 3; // 0x3
field public static final int POLICY_TYPE_AUDIO = 1; // 0x1
+ field @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public static final int POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR = 6; // 0x6
field @FlaggedApi("android.companion.virtual.flags.virtual_camera") public static final int POLICY_TYPE_CAMERA = 5; // 0x5
field @FlaggedApi("android.companion.virtual.flags.cross_device_clipboard") public static final int POLICY_TYPE_CLIPBOARD = 4; // 0x4
field public static final int POLICY_TYPE_RECENTS = 2; // 0x2
diff --git a/core/java/Android.bp b/core/java/Android.bp
index fae411d495ca..128fb62e21c9 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -20,10 +20,43 @@ filegroup {
"**/*.java",
"**/*.aidl",
":framework-nfc-non-updatable-sources",
+ ":messagequeue-gen",
+ ],
+ // Exactly one of the below will be added to srcs by messagequeue-gen
+ exclude_srcs: [
+ "android/os/LegacyMessageQueue/MessageQueue.java",
+ "android/os/ConcurrentMessageQueue/MessageQueue.java",
+ "android/os/SemiConcurrentMessageQueue/MessageQueue.java",
],
visibility: ["//frameworks/base"],
}
+// Add selected MessageQueue.java implementation to srcs
+soong_config_module_type {
+ name: "release_package_messagequeue_implementation_srcs",
+ module_type: "genrule",
+ config_namespace: "messagequeue",
+ value_variables: ["release_package_messagequeue_implementation"],
+ properties: [
+ "srcs",
+ ],
+}
+
+// Output the selected android/os/MessageQueue.java implementation
+release_package_messagequeue_implementation_srcs {
+ name: "messagequeue-gen",
+ soong_config_variables: {
+ release_package_messagequeue_implementation: {
+ srcs: ["android/os/%s"],
+ conditions_default: {
+ srcs: ["android/os/LegacyMessageQueue/MessageQueue.java"],
+ },
+ },
+ },
+ cmd: "mkdir -p android/os/; cp $(in) $(out);",
+ out: ["android/os/MessageQueue.java"],
+}
+
aidl_library {
name: "IDropBoxManagerService_aidl",
srcs: [
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 2313fa27afe1..5214d2c9c02a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2981,9 +2981,7 @@ public class AppOpsManager {
new AppOpInfo.Builder(OP_ESTABLISH_VPN_MANAGER, OPSTR_ESTABLISH_VPN_MANAGER,
"ESTABLISH_VPN_MANAGER").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
new AppOpInfo.Builder(OP_ACCESS_RESTRICTED_SETTINGS, OPSTR_ACCESS_RESTRICTED_SETTINGS,
- "ACCESS_RESTRICTED_SETTINGS").setDefaultMode(
- android.permission.flags.Flags.enhancedConfirmationModeApisEnabled()
- ? MODE_DEFAULT : MODE_ALLOWED)
+ "ACCESS_RESTRICTED_SETTINGS").setDefaultMode(AppOpsManager.MODE_ALLOWED)
.setDisableReset(true).setRestrictRead(true).build(),
new AppOpInfo.Builder(OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
"RECEIVE_SOUNDTRIGGER_AUDIO").setDefaultMode(AppOpsManager.MODE_ALLOWED)
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index bd80dc1e3c60..69b5222aa314 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -499,32 +499,31 @@ public class NotificationManager {
/**
* Activity Action: Launch an Automatic Zen Rule configuration screen
- * <p>
- * Input: Optionally, {@link #EXTRA_AUTOMATIC_RULE_ID}, if the configuration screen for an
+ *
+ * <p> Input: Optionally, {@link #EXTRA_AUTOMATIC_RULE_ID}, if the configuration screen for an
* existing rule should be displayed. If the rule id is missing or null, apps should display
* a configuration screen where users can create a new instance of the rule.
- * <p>
- * Output: Nothing
- * <p>
- * You can have multiple activities handling this intent, if you support multiple
- * {@link AutomaticZenRule rules}. In order for the system to properly display all of your
- * rule types so that users can create new instances or configure existing ones, you need
- * to add some extra metadata ({@link #META_DATA_AUTOMATIC_RULE_TYPE})
- * to your activity tag in your manifest. If you'd like to limit the number of rules a user
- * can create from this flow, you can additionally optionally include
- * {@link #META_DATA_RULE_INSTANCE_LIMIT}.
- *
- * For example,
- * &lt;meta-data
- * android:name="android.app.zen.automatic.ruleType"
- * android:value="@string/my_condition_rule">
- * &lt;/meta-data>
- * &lt;meta-data
- * android:name="android.app.zen.automatic.ruleInstanceLimit"
- * android:value="1">
- * &lt;/meta-data>
- * </p>
- * </p>
+ *
+ * <p> Output: Nothing
+ *
+ * <p> You can have multiple activities handling this intent, if you support multiple
+ * {@link AutomaticZenRule rules}. In order for the system to properly display all of your
+ * rule types so that users can create new instances or configure existing ones, you need
+ * to add some extra metadata ({@link #META_DATA_AUTOMATIC_RULE_TYPE})
+ * to your activity tag in your manifest. If you'd like to limit the number of rules a user
+ * can create from this flow, you can additionally optionally include
+ * {@link #META_DATA_RULE_INSTANCE_LIMIT}. For example,
+ *
+ * <pre>
+ * {@code
+ * <meta-data
+ * android:name="android.service.zen.automatic.ruleType"
+ * android:value="@string/my_condition_rule" />
+ * <meta-data
+ * android:name="android.service.zen.automatic.ruleInstanceLimit"
+ * android:value="1" />
+ * }
+ * </pre>
*
* @see #addAutomaticZenRule(AutomaticZenRule)
*/
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index f9a9da1ae448..f7f842f58511 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -171,7 +171,7 @@ public final class VirtualDeviceParams implements Parcelable {
* @hide
*/
@IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY,
- POLICY_TYPE_CLIPBOARD})
+ POLICY_TYPE_CLIPBOARD, POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public @interface DynamicPolicyType {}
@@ -263,6 +263,22 @@ public final class VirtualDeviceParams implements Parcelable {
@FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA)
public static final int POLICY_TYPE_CAMERA = 5;
+ /**
+ * Tells the virtual device framework how to handle activity launches that were blocked due to
+ * the current activity policy.
+ *
+ * <ul>
+ * <li>{@link #DEVICE_POLICY_DEFAULT}: Show UI informing the user of the blocked activity
+ * launch on the virtual display that the activity was originally launched on.
+ * <li>{@link #DEVICE_POLICY_CUSTOM}: Does not inform the user of the blocked activity
+ * launch. The virtual device owner can use this policy together with
+ * {@link VirtualDeviceManager.ActivityListener#onActivityLaunchBlocked} to provide custom
+ * experience on the virtual device.
+ * </ul>
+ */
+ @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
+ public static final int POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR = 6;
+
private final int mLockState;
@NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
@NavigationPolicy
@@ -1174,6 +1190,10 @@ public final class VirtualDeviceParams implements Parcelable {
mDevicePolicies.delete(POLICY_TYPE_CAMERA);
}
+ if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) {
+ mDevicePolicies.delete(POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR);
+ }
+
if ((mAudioPlaybackSessionId != AUDIO_SESSION_ID_GENERATE
|| mAudioRecordingSessionId != AUDIO_SESSION_ID_GENERATE)
&& mDevicePolicies.get(POLICY_TYPE_AUDIO, DEVICE_POLICY_DEFAULT)
diff --git a/core/java/android/hardware/devicestate/feature/flags.aconfig b/core/java/android/hardware/devicestate/feature/flags.aconfig
index 12d3f94ec982..a09c84dcedcb 100644
--- a/core/java/android/hardware/devicestate/feature/flags.aconfig
+++ b/core/java/android/hardware/devicestate/feature/flags.aconfig
@@ -8,4 +8,13 @@ flag {
description: "Updated DeviceState hasProperty API"
bug: "293636629"
is_fixed_read_only: true
+}
+
+flag {
+ name: "device_state_property_migration"
+ is_exported: true
+ namespace: "windowing_sdk"
+ description: "Client migration to updated DeviceStateManager API's"
+ bug: "336640888"
+ is_fixed_read_only: true
} \ No newline at end of file
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 065b3d6c7a8a..b2f333ae58e8 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -9025,6 +9025,10 @@ public abstract class BatteryStats {
final int uid = consumer.getUid();
final Uid u = uidStats.get(uid);
+ if (u == null) {
+ continue;
+ }
+
final long rxPackets = u.getNetworkActivityPackets(
BatteryStats.NETWORK_MOBILE_RX_DATA, STATS_SINCE_CHARGED);
final long txPackets = u.getNetworkActivityPackets(
diff --git a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java
new file mode 100644
index 000000000000..72b5cf79133d
--- /dev/null
+++ b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java
@@ -0,0 +1,1648 @@
+/*
+ * 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.os;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Handler;
+import android.os.Trace;
+import android.util.Log;
+import android.util.Printer;
+import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Low-level class holding the list of messages to be dispatched by a
+ * {@link Looper}. Messages are not added directly to a MessageQueue,
+ * but rather through {@link Handler} objects associated with the Looper.
+ *
+ * <p>You can retrieve the MessageQueue for the current thread with
+ * {@link Looper#myQueue() Looper.myQueue()}.
+ */
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+ "com.android.platform.test.ravenwood.nativesubstitution.MessageQueue_host")
+public final class MessageQueue {
+ private static final String TAG = "ConcurrentMessageQueue";
+ private static final boolean DEBUG = false;
+ private static final boolean TRACE = false;
+
+ // True if the message queue can be quit.
+ private final boolean mQuitAllowed;
+
+ @SuppressWarnings("unused")
+ private long mPtr; // used by native code
+
+ @IntDef(value = {
+ STACK_NODE_MESSAGE,
+ STACK_NODE_ACTIVE,
+ STACK_NODE_PARKED,
+ STACK_NODE_TIMEDPARK})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface StackNodeType {}
+
+ /*
+ * Stack node types. STACK_NODE_MESSAGE indicates a node containing a message.
+ * The other types indicate what state our Looper thread is in. The bottom of
+ * the stack is always a single state node. Message nodes are added on top.
+ */
+ private static final int STACK_NODE_MESSAGE = 0;
+ /*
+ * Active state indicates that next() is processing messages
+ */
+ private static final int STACK_NODE_ACTIVE = 1;
+ /*
+ * Parked state indicates that the Looper thread is sleeping indefinitely (nothing to deliver)
+ */
+ private static final int STACK_NODE_PARKED = 2;
+ /*
+ * Timed Park state indicates that the Looper thread is sleeping, waiting for a message
+ * deadline
+ */
+ private static final int STACK_NODE_TIMEDPARK = 3;
+
+ /* Describes a node in the Treiber stack */
+ static class StackNode {
+ @StackNodeType
+ private final int mType;
+
+ StackNode(@StackNodeType int type) {
+ mType = type;
+ }
+
+ @StackNodeType
+ final int getNodeType() {
+ return mType;
+ }
+
+ final boolean isMessageNode() {
+ return mType == STACK_NODE_MESSAGE;
+ }
+ }
+
+ static final class MessageNode extends StackNode implements Comparable<MessageNode> {
+ private final Message mMessage;
+ volatile StackNode mNext;
+ StateNode mBottomOfStack;
+ boolean mWokeUp;
+ final long mInsertSeq;
+ private static final VarHandle sRemovedFromStack;
+ private volatile boolean mRemovedFromStackValue;
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ sRemovedFromStack = l.findVarHandle(MessageQueue.MessageNode.class,
+ "mRemovedFromStackValue", boolean.class);
+ } catch (Exception e) {
+ Log.wtf(TAG, "VarHandle lookup failed with exception: " + e);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ MessageNode(@NonNull Message message, long insertSeq) {
+ super(STACK_NODE_MESSAGE);
+ mMessage = message;
+ mInsertSeq = insertSeq;
+ }
+
+ long getWhen() {
+ return mMessage.when;
+ }
+
+ boolean isRemovedFromStack() {
+ return mRemovedFromStackValue;
+ }
+
+ boolean removeFromStack() {
+ return sRemovedFromStack.compareAndSet(this, false, true);
+ }
+
+ boolean isAsync() {
+ return mMessage.isAsynchronous();
+ }
+
+ boolean isBarrier() {
+ return mMessage.target == null;
+ }
+
+ @Override
+ public int compareTo(@NonNull MessageNode messageNode) {
+ Message other = messageNode.mMessage;
+
+ int compared = Long.compare(mMessage.when, other.when);
+ if (compared == 0) {
+ compared = Long.compare(mInsertSeq, messageNode.mInsertSeq);
+ }
+ return compared;
+ }
+ }
+
+ static class StateNode extends StackNode {
+ StateNode(int type) {
+ super(type);
+ }
+ }
+
+ static final class TimedParkStateNode extends StateNode {
+ long mWhenToWake;
+
+ TimedParkStateNode() {
+ super(STACK_NODE_TIMEDPARK);
+ }
+ }
+
+ private static final StateNode sStackStateActive = new StateNode(STACK_NODE_ACTIVE);
+ private static final StateNode sStackStateParked = new StateNode(STACK_NODE_PARKED);
+ private final TimedParkStateNode mStackStateTimedPark = new TimedParkStateNode();
+
+ /* This is the top of our treiber stack. */
+ private static final VarHandle sState;
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ sState = l.findVarHandle(MessageQueue.class, "mStateValue",
+ MessageQueue.StackNode.class);
+ } catch (Exception e) {
+ Log.wtf(TAG, "VarHandle lookup failed with exception: " + e);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private volatile StackNode mStateValue = sStackStateParked;
+ private final ConcurrentSkipListSet<MessageNode> mPriorityQueue =
+ new ConcurrentSkipListSet<MessageNode>();
+ private final ConcurrentSkipListSet<MessageNode> mAsyncPriorityQueue =
+ new ConcurrentSkipListSet<MessageNode>();
+
+ /*
+ * This helps us ensure that messages with the same timestamp are inserted in FIFO order.
+ * Increments on each insert, starting at 0. MessageNode.compareTo() will compare sequences
+ * when delivery timestamps are identical.
+ */
+ private static final VarHandle sNextInsertSeq;
+ private volatile long mNextInsertSeqValue = 0;
+ /*
+ * The exception to the FIFO order rule is sendMessageAtFrontOfQueue().
+ * Those messages must be in LIFO order - SIGH.
+ * Decrements on each front of queue insert.
+ */
+ private static final VarHandle sNextFrontInsertSeq;
+ private volatile long mNextFrontInsertSeqValue = -1;
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ sNextInsertSeq = l.findVarHandle(MessageQueue.class, "mNextInsertSeqValue",
+ long.class);
+ sNextFrontInsertSeq = l.findVarHandle(MessageQueue.class, "mNextFrontInsertSeqValue",
+ long.class);
+ } catch (Exception e) {
+ Log.wtf(TAG, "VarHandle lookup failed with exception: " + e);
+ throw new ExceptionInInitializerError(e);
+ }
+
+ }
+
+ /*
+ * Tracks the number of queued and cancelled messages in our stack.
+ *
+ * On item cancellation, determine whether to wake next() to flush tombstoned messages.
+ * We track queued and cancelled counts as two ints packed into a single long.
+ */
+ private static final class MessageCounts {
+ private static VarHandle sCounts;
+ private volatile long mCountsValue = 0;
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ sCounts = l.findVarHandle(MessageQueue.MessageCounts.class, "mCountsValue",
+ long.class);
+ } catch (Exception e) {
+ Log.wtf(TAG, "VarHandle lookup failed with exception: " + e);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ /* We use a special value to indicate when next() has been woken for flush. */
+ private static final long AWAKE = Long.MAX_VALUE;
+ /*
+ * Minimum number of messages in the stack which we need before we consider flushing
+ * tombstoned items.
+ */
+ private static final int MESSAGE_FLUSH_THRESHOLD = 10;
+
+ private static int numQueued(long val) {
+ return (int) (val >>> Integer.SIZE);
+ }
+
+ private static int numCancelled(long val) {
+ return (int) val;
+ }
+
+ private static long combineCounts(int queued, int cancelled) {
+ return ((long) queued << Integer.SIZE) | (long) cancelled;
+ }
+
+ public void incrementQueued() {
+ while (true) {
+ long oldVal = mCountsValue;
+ int queued = numQueued(oldVal);
+ int cancelled = numCancelled(oldVal);
+ /* Use Math.max() to avoid overflow of queued count */
+ long newVal = combineCounts(Math.max(queued + 1, queued), cancelled);
+
+ /* Don't overwrite 'AWAKE' state */
+ if (oldVal == AWAKE || sCounts.compareAndSet(this, oldVal, newVal)) {
+ break;
+ }
+ }
+ }
+
+ public boolean incrementCancelled() {
+ while (true) {
+ long oldVal = mCountsValue;
+ if (oldVal == AWAKE) {
+ return false;
+ }
+ int queued = numQueued(oldVal);
+ int cancelled = numCancelled(oldVal);
+ boolean needsPurge = queued > MESSAGE_FLUSH_THRESHOLD
+ && (queued >> 1) < cancelled;
+ long newVal;
+ if (needsPurge) {
+ newVal = AWAKE;
+ } else {
+ newVal = combineCounts(queued,
+ Math.max(cancelled + 1, cancelled));
+ }
+
+ if (sCounts.compareAndSet(this, oldVal, newVal)) {
+ return needsPurge;
+ }
+ }
+ }
+
+ public void clearCounts() {
+ mCountsValue = 0;
+ }
+ }
+
+ private final MessageCounts mMessageCounts = new MessageCounts();
+
+ private final Object mIdleHandlersLock = new Object();
+ @GuardedBy("mIdleHandlersLock")
+ private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
+ private IdleHandler[] mPendingIdleHandlers;
+
+ private final Object mFileDescriptorRecordsLock = new Object();
+ @GuardedBy("mFileDescriptorRecordsLock")
+ private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
+
+ private static final VarHandle sQuitting;
+ private boolean mQuittingValue = false;
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ sQuitting = l.findVarHandle(MessageQueue.class, "mQuittingValue", boolean.class);
+ } catch (Exception e) {
+ Log.wtf(TAG, "VarHandle lookup failed with exception: " + e);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ // The next barrier token.
+ // Barriers are indicated by messages with a null target whose arg1 field carries the token.
+ private final AtomicInteger mNextBarrierToken = new AtomicInteger(1);
+
+ private static native long nativeInit();
+ private static native void nativeDestroy(long ptr);
+ private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
+ private static native void nativeWake(long ptr);
+ private static native boolean nativeIsPolling(long ptr);
+ private static native void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
+
+ MessageQueue(boolean quitAllowed) {
+ mQuitAllowed = quitAllowed;
+ mPtr = nativeInit();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ dispose();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ // Disposes of the underlying message queue.
+ // Must only be called on the looper thread or the finalizer.
+ private void dispose() {
+ if (mPtr != 0) {
+ nativeDestroy(mPtr);
+ mPtr = 0;
+ }
+ }
+
+ /**
+ * Returns true if the looper has no pending messages which are due to be processed.
+ *
+ * <p>This method is safe to call from any thread.
+ *
+ * @return True if the looper is idle.
+ */
+ public boolean isIdle() {
+ MessageNode msgNode = null;
+ MessageNode asyncMsgNode = null;
+
+ if (!mPriorityQueue.isEmpty()) {
+ try {
+ msgNode = mPriorityQueue.first();
+ } catch (NoSuchElementException e) { }
+ }
+
+ if (!mAsyncPriorityQueue.isEmpty()) {
+ try {
+ asyncMsgNode = mAsyncPriorityQueue.first();
+ } catch (NoSuchElementException e) { }
+ }
+
+ final long now = SystemClock.uptimeMillis();
+ if ((msgNode != null && msgNode.getWhen() <= now)
+ || (asyncMsgNode != null && asyncMsgNode.getWhen() <= now)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /* Protects mNextIsDrainingStack */
+ private final ReentrantLock mDrainingLock = new ReentrantLock();
+ private boolean mNextIsDrainingStack = false;
+ private final Condition mDrainCompleted = mDrainingLock.newCondition();
+
+ /**
+ * Add a new {@link IdleHandler} to this message queue. This may be
+ * removed automatically for you by returning false from
+ * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
+ * invoked, or explicitly removing it with {@link #removeIdleHandler}.
+ *
+ * <p>This method is safe to call from any thread.
+ *
+ * @param handler The IdleHandler to be added.
+ */
+ public void addIdleHandler(@NonNull IdleHandler handler) {
+ if (handler == null) {
+ throw new NullPointerException("Can't add a null IdleHandler");
+ }
+ synchronized (mIdleHandlersLock) {
+ mIdleHandlers.add(handler);
+ }
+ }
+
+ /**
+ * Remove an {@link IdleHandler} from the queue that was previously added
+ * with {@link #addIdleHandler}. If the given object is not currently
+ * in the idle list, nothing is done.
+ *
+ * <p>This method is safe to call from any thread.
+ *
+ * @param handler The IdleHandler to be removed.
+ */
+ public void removeIdleHandler(@NonNull IdleHandler handler) {
+ synchronized (mIdleHandlersLock) {
+ mIdleHandlers.remove(handler);
+ }
+ }
+
+ /**
+ * Returns whether this looper's thread is currently polling for more work to do.
+ * This is a good signal that the loop is still alive rather than being stuck
+ * handling a callback. Note that this method is intrinsically racy, since the
+ * state of the loop can change before you get the result back.
+ *
+ * <p>This method is safe to call from any thread.
+ *
+ * @return True if the looper is currently polling for events.
+ * @hide
+ */
+ public boolean isPolling() {
+ // If the loop is quitting then it must not be idling.
+ // We can assume mPtr != 0 when sQuitting is false.
+ return !((boolean) sQuitting.getVolatile(this)) && nativeIsPolling(mPtr);
+ }
+
+ /* Helper to choose the correct queue to insert into. */
+ private void insertIntoPriorityQueue(MessageNode msgNode) {
+ if (msgNode.isAsync()) {
+ mAsyncPriorityQueue.add(msgNode);
+ } else {
+ mPriorityQueue.add(msgNode);
+ }
+ }
+
+ private boolean removeFromPriorityQueue(MessageNode msgNode) {
+ if (msgNode.isAsync()) {
+ return mAsyncPriorityQueue.remove(msgNode);
+ } else {
+ return mPriorityQueue.remove(msgNode);
+ }
+ }
+
+ private MessageNode pickEarliestNode(MessageNode nodeA, MessageNode nodeB) {
+ if (nodeA != null && nodeB != null) {
+ if (nodeA.compareTo(nodeB) < 0) {
+ return nodeA;
+ }
+ return nodeB;
+ }
+
+ return nodeA != null ? nodeA : nodeB;
+ }
+
+ private MessageNode iterateNext(Iterator<MessageNode> iter) {
+ if (iter.hasNext()) {
+ try {
+ return iter.next();
+ } catch (NoSuchElementException e) {
+ /* The queue is empty - this can happen if we race with remove */
+ }
+ }
+ return null;
+ }
+
+ /* Move any non-cancelled messages into the priority queue */
+ private void drainStack(StackNode oldTop) {
+ while (oldTop.isMessageNode()) {
+ MessageNode oldTopMessageNode = (MessageNode) oldTop;
+ if (oldTopMessageNode.removeFromStack()) {
+ insertIntoPriorityQueue(oldTopMessageNode);
+ }
+ MessageNode inserted = oldTopMessageNode;
+ oldTop = oldTopMessageNode.mNext;
+ /*
+ * removeMessages can walk this list while we are consuming it.
+ * Set our next pointer to null *after* we add the message to our
+ * priority queue. This way removeMessages() will always find the
+ * message, either in our list or in the priority queue.
+ */
+ inserted.mNext = null;
+ }
+ }
+
+ /* Set the stack state to Active, return a list of nodes to walk. */
+ private StackNode swapAndSetStackStateActive() {
+ while (true) {
+ /* Set stack state to Active, get node list to walk later */
+ StackNode current = (StackNode) sState.getVolatile(this);
+ if (current == sStackStateActive
+ || sState.compareAndSet(this, current, sStackStateActive)) {
+ return current;
+ }
+ }
+ }
+
+ /* This is only read/written from the Looper thread */
+ private int mNextPollTimeoutMillis;
+ private static final AtomicLong mMessagesDelivered = new AtomicLong();
+
+ private Message nextMessage() {
+ int i = 0;
+
+ while (true) {
+ if (DEBUG) {
+ Log.d(TAG, "nextMessage loop #" + i);
+ i++;
+ }
+
+ mDrainingLock.lock();
+ mNextIsDrainingStack = true;
+ mDrainingLock.unlock();
+
+ /*
+ * Set our state to active, drain any items from the stack into our priority queues
+ */
+ StackNode oldTop;
+ oldTop = swapAndSetStackStateActive();
+ drainStack(oldTop);
+
+ mDrainingLock.lock();
+ mNextIsDrainingStack = false;
+ mDrainCompleted.signalAll();
+ mDrainingLock.unlock();
+
+ /*
+ * The objective of this next block of code is to:
+ * - find a message to return (if any is ready)
+ * - find a next message we would like to return, after scheduling.
+ * - we make our scheduling decision based on this next message (if it exists).
+ *
+ * We have two queues to juggle and the presence of barriers throws an additional
+ * wrench into our plans.
+ *
+ * The last wrinkle is that remove() may delete items from underneath us. If we hit
+ * that case, we simply restart the loop.
+ */
+
+ /* Get the first node from each queue */
+ Iterator<MessageNode> queueIter = mPriorityQueue.iterator();
+ MessageNode msgNode = iterateNext(queueIter);
+ Iterator<MessageNode> asyncQueueIter = mAsyncPriorityQueue.iterator();
+ MessageNode asyncMsgNode = iterateNext(asyncQueueIter);
+
+ if (DEBUG) {
+ if (msgNode != null) {
+ Message msg = msgNode.mMessage;
+ Log.d(TAG, "Next found node what: " + msg.what + " when: " + msg.when
+ + " seq: " + msgNode.mInsertSeq + "barrier: "
+ + msgNode.isBarrier() + " now: " + SystemClock.uptimeMillis());
+ }
+ if (asyncMsgNode != null) {
+ Message msg = asyncMsgNode.mMessage;
+ Log.d(TAG, "Next found async node what: " + msg.what + " when: " + msg.when
+ + " seq: " + asyncMsgNode.mInsertSeq + "barrier: "
+ + asyncMsgNode.isBarrier() + " now: "
+ + SystemClock.uptimeMillis());
+ }
+ }
+
+ /*
+ * the node which we will return, null if none are ready
+ */
+ MessageNode found = null;
+ /*
+ * The node from which we will determine our next wakeup time.
+ * Null indicates there is no next message ready. If we found a node,
+ * we can leave this null as Looper will call us again after delivering
+ * the message.
+ */
+ MessageNode next = null;
+
+ long now = SystemClock.uptimeMillis();
+ /*
+ * If we have a barrier we should return the async node (if it exists and is ready)
+ */
+ if (msgNode != null && msgNode.isBarrier()) {
+ if (asyncMsgNode != null && now >= asyncMsgNode.getWhen()) {
+ found = asyncMsgNode;
+ } else {
+ next = asyncMsgNode;
+ }
+ } else { /* No barrier. */
+ MessageNode earliest;
+ /*
+ * If we have two messages, pick the earliest option from either queue.
+ * Otherwise grab whichever node is non-null. If both are null we'll fall through.
+ */
+ earliest = pickEarliestNode(msgNode, asyncMsgNode);
+
+ if (earliest != null) {
+ if (now >= earliest.getWhen()) {
+ found = earliest;
+ } else {
+ next = earliest;
+ }
+ }
+ }
+
+ if (DEBUG) {
+ if (found != null) {
+ Message msg = found.mMessage;
+ Log.d(TAG, "Will deliver node what: " + msg.what + " when: " + msg.when
+ + " seq: " + found.mInsertSeq + " barrier: " + found.isBarrier()
+ + " async: " + found.isAsync() + " now: "
+ + SystemClock.uptimeMillis());
+ } else {
+ Log.d(TAG, "No node to deliver");
+ }
+ if (next != null) {
+ Message msg = next.mMessage;
+ Log.d(TAG, "Next node what: " + msg.what + " when: " + msg.when + " seq: "
+ + next.mInsertSeq + " barrier: " + next.isBarrier() + " async: "
+ + next.isAsync()
+ + " now: " + SystemClock.uptimeMillis());
+ } else {
+ Log.d(TAG, "No next node");
+ }
+ }
+
+ /*
+ * If we have a found message, we will get called again so there's no need to set state.
+ * In that case we can leave our state as ACTIVE.
+ *
+ * Otherwise we should determine how to park the thread.
+ */
+ StateNode nextOp = sStackStateActive;
+ if (found == null) {
+ if (next == null) {
+ /* No message to deliver, sleep indefinitely */
+ mNextPollTimeoutMillis = -1;
+ nextOp = sStackStateParked;
+ if (DEBUG) {
+ Log.d(TAG, "nextMessage next state is StackStateParked");
+ }
+ } else {
+ /* Message not ready, or we found one to deliver already, set a timeout */
+ long nextMessageWhen = next.getWhen();
+ if (nextMessageWhen > now) {
+ mNextPollTimeoutMillis = (int) Math.min(nextMessageWhen - now,
+ Integer.MAX_VALUE);
+ } else {
+ mNextPollTimeoutMillis = 0;
+ }
+
+ mStackStateTimedPark.mWhenToWake = now + mNextPollTimeoutMillis;
+ nextOp = mStackStateTimedPark;
+ if (DEBUG) {
+ Log.d(TAG, "nextMessage next state is StackStateTimedParked timeout ms "
+ + mNextPollTimeoutMillis + " mWhenToWake: "
+ + mStackStateTimedPark.mWhenToWake + " now " + now);
+ }
+ }
+ }
+
+ /*
+ * Try to swap our state from Active back to Park or TimedPark. If we raced with
+ * enqueue, loop back around to pick up any new items.
+ */
+ if (sState.compareAndSet(this, sStackStateActive, nextOp)) {
+ mMessageCounts.clearCounts();
+ if (found != null) {
+ if (!removeFromPriorityQueue(found)) {
+ /*
+ * RemoveMessages() might be able to pull messages out from under us
+ * However we can detect that here and just loop around if it happens.
+ */
+ continue;
+ }
+
+ if (TRACE) {
+ Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
+ }
+ return found.mMessage;
+ }
+ return null;
+ }
+ }
+ }
+
+ Message next() {
+ final long ptr = mPtr;
+ if (ptr == 0) {
+ return null;
+ }
+
+ mNextPollTimeoutMillis = 0;
+ int pendingIdleHandlerCount = -1; // -1 only during first iteration
+ while (true) {
+ if (mNextPollTimeoutMillis != 0) {
+ Binder.flushPendingCommands();
+ }
+
+ nativePollOnce(ptr, mNextPollTimeoutMillis);
+
+ Message msg = nextMessage();
+ if (msg != null) {
+ msg.markInUse();
+ return msg;
+ }
+
+ if ((boolean) sQuitting.getVolatile(this)) {
+ return null;
+ }
+
+ synchronized (mIdleHandlersLock) {
+ // If first time idle, then get the number of idlers to run.
+ // Idle handles only run if the queue is empty or if the first message
+ // in the queue (possibly a barrier) is due to be handled in the future.
+ if (pendingIdleHandlerCount < 0
+ && mNextPollTimeoutMillis != 0) {
+ pendingIdleHandlerCount = mIdleHandlers.size();
+ }
+ if (pendingIdleHandlerCount <= 0) {
+ // No idle handlers to run. Loop and wait some more.
+ continue;
+ }
+
+ if (mPendingIdleHandlers == null) {
+ mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
+ }
+ mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
+ }
+
+ // Run the idle handlers.
+ // We only ever reach this code block during the first iteration.
+ for (int i = 0; i < pendingIdleHandlerCount; i++) {
+ final IdleHandler idler = mPendingIdleHandlers[i];
+ mPendingIdleHandlers[i] = null; // release the reference to the handler
+
+ boolean keep = false;
+ try {
+ keep = idler.queueIdle();
+ } catch (Throwable t) {
+ Log.wtf(TAG, "IdleHandler threw exception", t);
+ }
+
+ if (!keep) {
+ synchronized (mIdleHandlersLock) {
+ mIdleHandlers.remove(idler);
+ }
+ }
+ }
+
+ // Reset the idle handler count to 0 so we do not run them again.
+ pendingIdleHandlerCount = 0;
+
+ // While calling an idle handler, a new message could have been delivered
+ // so go back and look again for a pending message without waiting.
+ mNextPollTimeoutMillis = 0;
+ }
+ }
+
+ void quit(boolean safe) {
+ if (!mQuitAllowed) {
+ throw new IllegalStateException("Main thread not allowed to quit.");
+ }
+ synchronized (mIdleHandlersLock) {
+ if (sQuitting.compareAndSet(this, false, true)) {
+ if (safe) {
+ removeAllFutureMessages();
+ } else {
+ removeAllMessages();
+ }
+
+ // We can assume mPtr != 0 because sQuitting was previously false.
+ nativeWake(mPtr);
+ }
+ }
+ }
+
+ boolean enqueueMessage(@NonNull Message msg, long when) {
+ if (msg.target == null) {
+ throw new IllegalArgumentException("Message must have a target.");
+ }
+
+ if (msg.isInUse()) {
+ throw new IllegalStateException(msg + " This message is already in use.");
+ }
+
+ return enqueueMessageUnchecked(msg, when);
+ }
+
+ private boolean enqueueMessageUnchecked(@NonNull Message msg, long when) {
+ if ((boolean) sQuitting.getVolatile(this)) {
+ IllegalStateException e = new IllegalStateException(
+ msg.target + " sending message to a Handler on a dead thread");
+ Log.w(TAG, e.getMessage(), e);
+ msg.recycleUnchecked();
+ return false;
+ }
+
+ long seq = when != 0 ? ((long)sNextInsertSeq.getAndAdd(this, 1L) + 1L)
+ : ((long)sNextFrontInsertSeq.getAndAdd(this, -1L) - 1L);
+ /* TODO: Add a MessageNode member to Message so we can avoid this allocation */
+ MessageNode node = new MessageNode(msg, seq);
+ msg.when = when;
+ msg.markInUse();
+
+ if (DEBUG) {
+ Log.d(TAG, "Insert message what: " + msg.what + " when: " + msg.when + " seq: "
+ + node.mInsertSeq + " barrier: " + node.isBarrier() + " async: "
+ + node.isAsync() + " now: " + SystemClock.uptimeMillis());
+ }
+
+ while (true) {
+ StackNode old = (StackNode) sState.getVolatile(this);
+ boolean wakeNeeded;
+ boolean inactive;
+
+ node.mNext = old;
+ switch (old.getNodeType()) {
+ case STACK_NODE_ACTIVE:
+ /*
+ * The worker thread is currently active and will process any elements added to
+ * the stack before parking again.
+ */
+ node.mBottomOfStack = (StateNode) old;
+ inactive = false;
+ node.mWokeUp = true;
+ wakeNeeded = false;
+ break;
+
+ case STACK_NODE_PARKED:
+ node.mBottomOfStack = (StateNode) old;
+ inactive = true;
+ node.mWokeUp = true;
+ wakeNeeded = true;
+ break;
+
+ case STACK_NODE_TIMEDPARK:
+ node.mBottomOfStack = (StateNode) old;
+ inactive = true;
+ wakeNeeded = mStackStateTimedPark.mWhenToWake >= node.getWhen();
+ node.mWokeUp = wakeNeeded;
+ break;
+
+ default:
+ MessageNode oldMessage = (MessageNode) old;
+
+ node.mBottomOfStack = oldMessage.mBottomOfStack;
+ int bottomType = node.mBottomOfStack.getNodeType();
+ inactive = bottomType >= STACK_NODE_PARKED;
+ wakeNeeded = (bottomType == STACK_NODE_TIMEDPARK
+ && mStackStateTimedPark.mWhenToWake >= node.getWhen()
+ && !oldMessage.mWokeUp);
+ node.mWokeUp = oldMessage.mWokeUp || wakeNeeded;
+ break;
+ }
+ if (sState.compareAndSet(this, old, node)) {
+ if (inactive) {
+ if (wakeNeeded) {
+ nativeWake(mPtr);
+ } else {
+ mMessageCounts.incrementQueued();
+ }
+ }
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Posts a synchronization barrier to the Looper's message queue.
+ *
+ * Message processing occurs as usual until the message queue encounters the
+ * synchronization barrier that has been posted. When the barrier is encountered,
+ * later synchronous messages in the queue are stalled (prevented from being executed)
+ * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
+ * the token that identifies the synchronization barrier.
+ *
+ * This method is used to immediately postpone execution of all subsequently posted
+ * synchronous messages until a condition is met that releases the barrier.
+ * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
+ * and continue to be processed as usual.
+ *
+ * This call must be always matched by a call to {@link #removeSyncBarrier} with
+ * the same token to ensure that the message queue resumes normal operation.
+ * Otherwise the application will probably hang!
+ *
+ * @return A token that uniquely identifies the barrier. This token must be
+ * passed to {@link #removeSyncBarrier} to release the barrier.
+ *
+ * @hide
+ */
+ @TestApi
+ public int postSyncBarrier() {
+ return postSyncBarrier(SystemClock.uptimeMillis());
+ }
+
+ private int postSyncBarrier(long when) {
+ final int token = mNextBarrierToken.getAndIncrement();
+ final Message msg = Message.obtain();
+
+ msg.markInUse();
+ msg.arg1 = token;
+
+ if (!enqueueMessageUnchecked(msg, when)) {
+ Log.wtf(TAG, "Unexpected error while adding sync barrier!");
+ return -1;
+ }
+
+ return token;
+ }
+
+ private class MatchBarrierToken extends MessageCompare {
+ int mBarrierToken;
+
+ MatchBarrierToken(int token) {
+ super();
+ mBarrierToken = token;
+ }
+
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == null && m.arg1 == mBarrierToken) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Removes a synchronization barrier.
+ *
+ * @param token The synchronization barrier token that was returned by
+ * {@link #postSyncBarrier}.
+ *
+ * @throws IllegalStateException if the barrier was not found.
+ *
+ * @hide
+ */
+ @TestApi
+ public void removeSyncBarrier(int token) {
+ boolean removed;
+ MessageNode first;
+ final MatchBarrierToken matchBarrierToken = new MatchBarrierToken(token);
+
+ try {
+ /* Retain the first element to see if we are currently stuck on a barrier. */
+ first = mPriorityQueue.first();
+ } catch (NoSuchElementException e) {
+ /* The queue is empty */
+ first = null;
+ }
+
+ removed = findOrRemoveMessages(null, 0, null, null, 0, matchBarrierToken, true);
+ if (removed && first != null) {
+ Message m = first.mMessage;
+ if (m.target == null && m.arg1 == token) {
+ /* Wake up next() in case it was sleeping on this barrier. */
+ nativeWake(mPtr);
+ }
+ } else if (!removed) {
+ throw new IllegalStateException("The specified message queue synchronization "
+ + " barrier token has not been posted or has already been removed.");
+ }
+ }
+
+ private StateNode getStateNode(StackNode node) {
+ if (node.isMessageNode()) {
+ return ((MessageNode) node).mBottomOfStack;
+ }
+ return (StateNode) node;
+ }
+
+ private void waitForDrainCompleted() {
+ mDrainingLock.lock();
+ while (mNextIsDrainingStack) {
+ mDrainCompleted.awaitUninterruptibly();
+ }
+ mDrainingLock.unlock();
+ }
+
+ /*
+ * This class is used to find matches for hasMessages() and removeMessages()
+ */
+ private abstract static class MessageCompare {
+ public abstract boolean compareMessage(Message m, Handler h, int what, Object object,
+ Runnable r, long when);
+ }
+
+ private boolean stackHasMessages(Handler h, int what, Object object, Runnable r, long when,
+ MessageCompare compare, boolean removeMatches) {
+ boolean found = false;
+ StackNode top = (StackNode) sState.getVolatile(this);
+ StateNode bottom = getStateNode(top);
+
+ /*
+ * If the top node is a state node, there are no reachable messages.
+ * If it's anything other than Active, we can quit as we know that next() is not
+ * consuming items.
+ * If the top node is Active then we know that next() is currently consuming items.
+ * In that case we should wait next() has drained the stack.
+ */
+ if (top == bottom) {
+ if (bottom != sStackStateActive) {
+ return false;
+ }
+ waitForDrainCompleted();
+ return false;
+ }
+
+ /*
+ * We have messages that we may tombstone. Walk the stack until we hit the bottom or we
+ * hit a null pointer.
+ * If we hit the bottom, we are done.
+ * If we hit a null pointer, then the stack is being consumed by next() and we must cycle
+ * until the stack has been drained.
+ */
+ MessageNode p = (MessageNode) top;
+
+ while (true) {
+ if (compare.compareMessage(p.mMessage, h, what, object, r, when)) {
+ found = true;
+ if (DEBUG) {
+ Log.w(TAG, "stackHasMessages node matches");
+ }
+ if (removeMatches) {
+ if (p.removeFromStack()) {
+ p.mMessage.recycleUnchecked();
+ if (mMessageCounts.incrementCancelled()) {
+ nativeWake(mPtr);
+ }
+ }
+ } else {
+ return true;
+ }
+ }
+
+ StackNode n = p.mNext;
+ if (n == null) {
+ /* Next() is walking the stack, we must re-sample */
+ if (DEBUG) {
+ Log.d(TAG, "stackHasMessages next() is walking the stack, we must re-sample");
+ }
+ waitForDrainCompleted();
+ break;
+ }
+ if (!n.isMessageNode()) {
+ /* We reached the end of the stack */
+ return found;
+ }
+ p = (MessageNode) n;
+ }
+
+ return found;
+ }
+
+ private boolean priorityQueueHasMessage(ConcurrentSkipListSet<MessageNode> queue, Handler h,
+ int what, Object object, Runnable r, long when, MessageCompare compare,
+ boolean removeMatches) {
+ Iterator<MessageNode> iterator = queue.iterator();
+ boolean found = false;
+
+ while (iterator.hasNext()) {
+ MessageNode msg = iterator.next();
+
+ if (compare.compareMessage(msg.mMessage, h, what, object, r, when)) {
+ if (removeMatches) {
+ found = true;
+ if (queue.remove(msg)) {
+ msg.mMessage.recycleUnchecked();
+ }
+ } else {
+ return true;
+ }
+ }
+ }
+ return found;
+ }
+
+ private boolean findOrRemoveMessages(Handler h, int what, Object object, Runnable r, long when,
+ MessageCompare compare, boolean removeMatches) {
+ boolean foundInStack, foundInQueue;
+
+ foundInStack = stackHasMessages(h, what, object, r, when, compare, removeMatches);
+ foundInQueue = priorityQueueHasMessage(mPriorityQueue, h, what, object, r, when, compare,
+ removeMatches);
+ foundInQueue |= priorityQueueHasMessage(mAsyncPriorityQueue, h, what, object, r, when,
+ compare, removeMatches);
+
+ return foundInStack || foundInQueue;
+ }
+
+ private static class MatchHandlerWhatAndObject extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && m.what == what && (object == null || m.obj == object)) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerWhatAndObject mMatchHandlerWhatAndObject =
+ new MatchHandlerWhatAndObject();
+ boolean hasMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return false;
+ }
+
+ return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, false);
+ }
+
+ private static class MatchHandlerWhatAndObjectEquals extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && m.what == what && (object == null || object.equals(m.obj))) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerWhatAndObjectEquals mMatchHandlerWhatAndObjectEquals =
+ new MatchHandlerWhatAndObjectEquals();
+ boolean hasEqualMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return false;
+ }
+
+ return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals,
+ false);
+ }
+
+ private static class MatchHandlerRunnableAndObject extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && m.callback == r && (object == null || m.obj == object)) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerRunnableAndObject mMatchHandlerRunnableAndObject =
+ new MatchHandlerRunnableAndObject();
+
+ boolean hasMessages(Handler h, Runnable r, Object object) {
+ if (h == null) {
+ return false;
+ }
+
+ return findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, false);
+ }
+
+ private static class MatchHandler extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandler mMatchHandler = new MatchHandler();
+ boolean hasMessages(Handler h) {
+ if (h == null) {
+ return false;
+ }
+ return findOrRemoveMessages(h, -1, null, null, 0, mMatchHandler, false);
+ }
+
+ void removeMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return;
+ }
+ findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, true);
+ }
+
+ void removeEqualMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return;
+ }
+ findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals, true);
+ }
+
+ void removeMessages(Handler h, Runnable r, Object object) {
+ if (h == null || r == null) {
+ return;
+ }
+ findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, true);
+ }
+
+ private static class MatchHandlerRunnableAndObjectEquals extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && m.callback == r && (object == null || object.equals(m.obj))) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerRunnableAndObjectEquals mMatchHandlerRunnableAndObjectEquals =
+ new MatchHandlerRunnableAndObjectEquals();
+ void removeEqualMessages(Handler h, Runnable r, Object object) {
+ if (h == null || r == null) {
+ return;
+ }
+ findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObjectEquals, true);
+ }
+
+ private static class MatchHandlerAndObject extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && (object == null || m.obj == object)) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerAndObject mMatchHandlerAndObject = new MatchHandlerAndObject();
+ void removeCallbacksAndMessages(Handler h, Object object) {
+ if (h == null) {
+ return;
+ }
+ findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObject, true);
+ }
+
+ private static class MatchHandlerAndObjectEquals extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && (object == null || object.equals(m.obj))) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerAndObjectEquals mMatchHandlerAndObjectEquals =
+ new MatchHandlerAndObjectEquals();
+ void removeCallbacksAndEqualMessages(Handler h, Object object) {
+ if (h == null) {
+ return;
+ }
+ findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObjectEquals, true);
+ }
+
+ private static class MatchAllMessages extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ return true;
+ }
+ }
+ private final MatchAllMessages mMatchAllMessages = new MatchAllMessages();
+ private void removeAllMessages() {
+ findOrRemoveMessages(null, -1, null, null, 0, mMatchAllMessages, true);
+ }
+
+ private static class MatchAllFutureMessages extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.when > when) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchAllFutureMessages mMatchAllFutureMessages = new MatchAllFutureMessages();
+ private void removeAllFutureMessages() {
+ findOrRemoveMessages(null, -1, null, null, SystemClock.uptimeMillis(),
+ mMatchAllFutureMessages, true);
+ }
+
+ private void printPriorityQueueNodes() {
+ Iterator<MessageNode> iterator = mPriorityQueue.iterator();
+
+ Log.d(TAG, "* Dump priority queue");
+ while (iterator.hasNext()) {
+ MessageNode msgNode = iterator.next();
+ Log.d(TAG, "** MessageNode what: " + msgNode.mMessage.what + " when "
+ + msgNode.mMessage.when + " seq: " + msgNode.mInsertSeq);
+ }
+ }
+
+ private int dumpPriorityQueue(ConcurrentSkipListSet<MessageNode> queue, Printer pw,
+ String prefix, Handler h, int n) {
+ int count = 0;
+ long now = SystemClock.uptimeMillis();
+
+ for (MessageNode msgNode : queue) {
+ Message msg = msgNode.mMessage;
+ if (h == null || h == msg.target) {
+ pw.println(prefix + "Message " + (n + count) + ": " + msg.toString(now));
+ }
+ count++;
+ }
+ return count;
+ }
+
+ void dump(Printer pw, String prefix, Handler h) {
+ long now = SystemClock.uptimeMillis();
+ int n = 0;
+
+ pw.println(prefix + "(MessageQueue is using Concurrent implementation)");
+
+ StackNode node = (StackNode) sState.getVolatile(this);
+ while (node != null) {
+ if (node.isMessageNode()) {
+ Message msg = ((MessageNode) node).mMessage;
+ if (h == null || h == msg.target) {
+ pw.println(prefix + "Message " + n + ": " + msg.toString(now));
+ }
+ node = ((MessageNode) node).mNext;
+ } else {
+ pw.println(prefix + "State: " + node);
+ node = null;
+ }
+ n++;
+ }
+
+ pw.println(prefix + "PriorityQueue Messages: ");
+ n += dumpPriorityQueue(mPriorityQueue, pw, prefix, h, n);
+ pw.println(prefix + "AsyncPriorityQueue Messages: ");
+ n += dumpPriorityQueue(mAsyncPriorityQueue, pw, prefix, h, n);
+
+ pw.println(prefix + "(Total messages: " + n + ", polling=" + isPolling()
+ + ", quitting=" + (boolean) sQuitting.getVolatile(this) + ")");
+ }
+
+ private int dumpPriorityQueue(ConcurrentSkipListSet<MessageNode> queue,
+ ProtoOutputStream proto) {
+ int count = 0;
+
+ for (MessageNode msgNode : queue) {
+ Message msg = msgNode.mMessage;
+ msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
+ count++;
+ }
+ return count;
+ }
+
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long messageQueueToken = proto.start(fieldId);
+
+ StackNode node = (StackNode) sState.getVolatile(this);
+ while (node.isMessageNode()) {
+ Message msg = ((MessageNode) node).mMessage;
+ msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
+ node = ((MessageNode) node).mNext;
+ }
+
+ dumpPriorityQueue(mPriorityQueue, proto);
+ dumpPriorityQueue(mAsyncPriorityQueue, proto);
+
+ proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPolling());
+ proto.write(MessageQueueProto.IS_QUITTING, (boolean) sQuitting.getVolatile(this));
+ proto.end(messageQueueToken);
+ }
+
+ /**
+ * Adds a file descriptor listener to receive notification when file descriptor
+ * related events occur.
+ * <p>
+ * If the file descriptor has already been registered, the specified events
+ * and listener will replace any that were previously associated with it.
+ * It is not possible to set more than one listener per file descriptor.
+ * </p><p>
+ * It is important to always unregister the listener when the file descriptor
+ * is no longer of use.
+ * </p>
+ *
+ * @param fd The file descriptor for which a listener will be registered.
+ * @param events The set of events to receive: a combination of the
+ * {@link OnFileDescriptorEventListener#EVENT_INPUT},
+ * {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
+ * {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested
+ * set of events is zero, then the listener is unregistered.
+ * @param listener The listener to invoke when file descriptor events occur.
+ *
+ * @see OnFileDescriptorEventListener
+ * @see #removeOnFileDescriptorEventListener
+ */
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
+ public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
+ @OnFileDescriptorEventListener.Events int events,
+ @NonNull OnFileDescriptorEventListener listener) {
+ if (fd == null) {
+ throw new IllegalArgumentException("fd must not be null");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ synchronized (mFileDescriptorRecordsLock) {
+ updateOnFileDescriptorEventListenerLocked(fd, events, listener);
+ }
+ }
+
+ /**
+ * Removes a file descriptor listener.
+ * <p>
+ * This method does nothing if no listener has been registered for the
+ * specified file descriptor.
+ * </p>
+ *
+ * @param fd The file descriptor whose listener will be unregistered.
+ *
+ * @see OnFileDescriptorEventListener
+ * @see #addOnFileDescriptorEventListener
+ */
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
+ public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
+ if (fd == null) {
+ throw new IllegalArgumentException("fd must not be null");
+ }
+
+ synchronized (mFileDescriptorRecordsLock) {
+ updateOnFileDescriptorEventListenerLocked(fd, 0, null);
+ }
+ }
+
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
+ private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
+ OnFileDescriptorEventListener listener) {
+ final int fdNum = fd.getInt$();
+
+ int index = -1;
+ FileDescriptorRecord record = null;
+ if (mFileDescriptorRecords != null) {
+ index = mFileDescriptorRecords.indexOfKey(fdNum);
+ if (index >= 0) {
+ record = mFileDescriptorRecords.valueAt(index);
+ if (record != null && record.mEvents == events) {
+ return;
+ }
+ }
+ }
+
+ if (events != 0) {
+ events |= OnFileDescriptorEventListener.EVENT_ERROR;
+ if (record == null) {
+ if (mFileDescriptorRecords == null) {
+ mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
+ }
+ record = new FileDescriptorRecord(fd, events, listener);
+ mFileDescriptorRecords.put(fdNum, record);
+ } else {
+ record.mListener = listener;
+ record.mEvents = events;
+ record.mSeq += 1;
+ }
+ nativeSetFileDescriptorEvents(mPtr, fdNum, events);
+ } else if (record != null) {
+ record.mEvents = 0;
+ mFileDescriptorRecords.removeAt(index);
+ nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
+ }
+ }
+
+ // Called from native code.
+ private int dispatchEvents(int fd, int events) {
+ // Get the file descriptor record and any state that might change.
+ final FileDescriptorRecord record;
+ final int oldWatchedEvents;
+ final OnFileDescriptorEventListener listener;
+ final int seq;
+ synchronized (mFileDescriptorRecordsLock) {
+ record = mFileDescriptorRecords.get(fd);
+ if (record == null) {
+ return 0; // spurious, no listener registered
+ }
+
+ oldWatchedEvents = record.mEvents;
+ events &= oldWatchedEvents; // filter events based on current watched set
+ if (events == 0) {
+ return oldWatchedEvents; // spurious, watched events changed
+ }
+
+ listener = record.mListener;
+ seq = record.mSeq;
+ }
+
+ // Invoke the listener outside of the lock.
+ int newWatchedEvents = listener.onFileDescriptorEvents(
+ record.mDescriptor, events);
+ if (newWatchedEvents != 0) {
+ newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
+ }
+
+ // Update the file descriptor record if the listener changed the set of
+ // events to watch and the listener itself hasn't been updated since.
+ if (newWatchedEvents != oldWatchedEvents) {
+ synchronized (mFileDescriptorRecordsLock) {
+ int index = mFileDescriptorRecords.indexOfKey(fd);
+ if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
+ && record.mSeq == seq) {
+ record.mEvents = newWatchedEvents;
+ if (newWatchedEvents == 0) {
+ mFileDescriptorRecords.removeAt(index);
+ }
+ }
+ }
+ }
+
+ // Return the new set of events to watch for native code to take care of.
+ return newWatchedEvents;
+ }
+
+ /**
+ * Callback interface for discovering when a thread is going to block
+ * waiting for more messages.
+ */
+ public static interface IdleHandler {
+ /**
+ * Called when the message queue has run out of messages and will now
+ * wait for more. Return true to keep your idle handler active, false
+ * to have it removed. This may be called if there are still messages
+ * pending in the queue, but they are all scheduled to be dispatched
+ * after the current time.
+ */
+ boolean queueIdle();
+ }
+
+ /**
+ * A listener which is invoked when file descriptor related events occur.
+ */
+ public interface OnFileDescriptorEventListener {
+ /**
+ * File descriptor event: Indicates that the file descriptor is ready for input
+ * operations, such as reading.
+ * <p>
+ * The listener should read all available data from the file descriptor
+ * then return <code>true</code> to keep the listener active or <code>false</code>
+ * to remove the listener.
+ * </p><p>
+ * In the case of a socket, this event may be generated to indicate
+ * that there is at least one incoming connection that the listener
+ * should accept.
+ * </p><p>
+ * This event will only be generated if the {@link #EVENT_INPUT} event mask was
+ * specified when the listener was added.
+ * </p>
+ */
+ public static final int EVENT_INPUT = 1 << 0;
+
+ /**
+ * File descriptor event: Indicates that the file descriptor is ready for output
+ * operations, such as writing.
+ * <p>
+ * The listener should write as much data as it needs. If it could not
+ * write everything at once, then it should return <code>true</code> to
+ * keep the listener active. Otherwise, it should return <code>false</code>
+ * to remove the listener then re-register it later when it needs to write
+ * something else.
+ * </p><p>
+ * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
+ * specified when the listener was added.
+ * </p>
+ */
+ public static final int EVENT_OUTPUT = 1 << 1;
+
+ /**
+ * File descriptor event: Indicates that the file descriptor encountered a
+ * fatal error.
+ * <p>
+ * File descriptor errors can occur for various reasons. One common error
+ * is when the remote peer of a socket or pipe closes its end of the connection.
+ * </p><p>
+ * This event may be generated at any time regardless of whether the
+ * {@link #EVENT_ERROR} event mask was specified when the listener was added.
+ * </p>
+ */
+ public static final int EVENT_ERROR = 1 << 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "EVENT_" }, value = {
+ EVENT_INPUT,
+ EVENT_OUTPUT,
+ EVENT_ERROR
+ })
+ public @interface Events {}
+
+ /**
+ * Called when a file descriptor receives events.
+ *
+ * @param fd The file descriptor.
+ * @param events The set of events that occurred: a combination of the
+ * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
+ * @return The new set of events to watch, or 0 to unregister the listener.
+ *
+ * @see #EVENT_INPUT
+ * @see #EVENT_OUTPUT
+ * @see #EVENT_ERROR
+ */
+ @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
+ }
+
+ static final class FileDescriptorRecord {
+ public final FileDescriptor mDescriptor;
+ public int mEvents;
+ public OnFileDescriptorEventListener mListener;
+ public int mSeq;
+
+ public FileDescriptorRecord(FileDescriptor descriptor,
+ int events, OnFileDescriptorEventListener listener) {
+ mDescriptor = descriptor;
+ mEvents = events;
+ mListener = listener;
+ }
+ }
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index a459aaa42930..2c7b9c02330e 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -159,6 +159,8 @@ public class Environment {
@UnsupportedAppUsage
private static UserEnvironment sCurrentUser;
private static boolean sUserRequired;
+ private static Boolean sLegacyStorageAppOp;
+ private static Boolean sNoIsolatedStorageAppOp;
static {
initForCurrentUser();
@@ -1459,15 +1461,23 @@ public class Environment {
final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
final String opPackageName = context.getOpPackageName();
- if (appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid,
- opPackageName) == AppOpsManager.MODE_ALLOWED) {
- return true;
+ if (sLegacyStorageAppOp == null) {
+ sLegacyStorageAppOp =
+ appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid, opPackageName) ==
+ AppOpsManager.MODE_ALLOWED;
+ }
+ if (sLegacyStorageAppOp) {
+ return sLegacyStorageAppOp;
}
// Legacy external storage access is granted to instrumentations invoked with
// "--no-isolated-storage" flag.
- return appOps.noteOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid,
- opPackageName) == AppOpsManager.MODE_ALLOWED;
+ if (sNoIsolatedStorageAppOp == null) {
+ sNoIsolatedStorageAppOp =
+ appOps.checkOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid,
+ opPackageName) == AppOpsManager.MODE_ALLOWED;
+ }
+ return sNoIsolatedStorageAppOp;
}
private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java
index 5b711c9d8401..6b9b3496d1c0 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java
@@ -20,6 +20,9 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Handler;
+import android.os.Process;
+import android.os.Trace;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
@@ -29,6 +32,7 @@ import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Low-level class holding the list of messages to be dispatched by a
@@ -44,6 +48,7 @@ import java.util.ArrayList;
public final class MessageQueue {
private static final String TAG = "MessageQueue";
private static final boolean DEBUG = false;
+ private static final boolean TRACE = false;
// True if the message queue can be quit.
@UnsupportedAppUsage
@@ -326,6 +331,8 @@ public final class MessageQueue {
return newWatchedEvents;
}
+ private static final AtomicLong mMessagesDelivered = new AtomicLong();
+
@UnsupportedAppUsage
Message next() {
// Return here if the message loop has already quit and been disposed.
@@ -381,6 +388,9 @@ public final class MessageQueue {
if (msg.isAsynchronous()) {
mAsyncMessageCount--;
}
+ if (TRACE) {
+ Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
+ }
return msg;
}
} else {
@@ -794,7 +804,7 @@ public final class MessageQueue {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
- && (object == null || n.obj == object)) {
+ && (object == null || n.obj == object)) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
@@ -841,7 +851,7 @@ public final class MessageQueue {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
- && (object == null || object.equals(n.obj))) {
+ && (object == null || object.equals(n.obj))) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
@@ -888,7 +898,7 @@ public final class MessageQueue {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
- && (object == null || n.obj == object)) {
+ && (object == null || n.obj == object)) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
@@ -935,7 +945,7 @@ public final class MessageQueue {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
- && (object == null || object.equals(n.obj))) {
+ && (object == null || object.equals(n.obj))) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
@@ -1093,6 +1103,7 @@ public final class MessageQueue {
void dump(Printer pw, String prefix, Handler h) {
synchronized (this) {
+ pw.println(prefix + "(MessageQueue is using Legacy implementation)");
long now = SystemClock.uptimeMillis();
int n = 0;
for (Message msg = mMessages; msg != null; msg = msg.next) {
diff --git a/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java
new file mode 100644
index 000000000000..967332fcf80c
--- /dev/null
+++ b/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java
@@ -0,0 +1,1589 @@
+/*
+ * 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.os;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Handler;
+import android.os.Trace;
+import android.util.Log;
+import android.util.Printer;
+import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
+import java.util.PriorityQueue;
+import java.util.PriorityQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Low-level class holding the list of messages to be dispatched by a
+ * {@link Looper}. Messages are not added directly to a MessageQueue,
+ * but rather through {@link Handler} objects associated with the Looper.
+ *
+ * <p>You can retrieve the MessageQueue for the current thread with
+ * {@link Looper#myQueue() Looper.myQueue()}.
+ */
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+ "com.android.platform.test.ravenwood.nativesubstitution.MessageQueue_host")
+public final class MessageQueue {
+ private static final String TAG = "SemiConcurrentMessageQueue";
+ private static final boolean DEBUG = false;
+ private static final boolean TRACE = false;
+
+ // True if the message queue can be quit.
+ private final boolean mQuitAllowed;
+
+ @SuppressWarnings("unused")
+ private long mPtr; // used by native code
+
+ @IntDef(value = {
+ STACK_NODE_MESSAGE,
+ STACK_NODE_ACTIVE,
+ STACK_NODE_PARKED,
+ STACK_NODE_TIMEDPARK})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface StackNodeType {}
+
+ /*
+ * Stack node types. STACK_NODE_MESSAGE indicates a node containing a message.
+ * The other types indicate what state our Looper thread is in. The bottom of
+ * the stack is always a single state node. Message nodes are added on top.
+ */
+ private static final int STACK_NODE_MESSAGE = 0;
+ /*
+ * Active state indicates that next() is processing messages
+ */
+ private static final int STACK_NODE_ACTIVE = 1;
+ /*
+ * Parked state indicates that the Looper thread is sleeping indefinitely (nothing to deliver)
+ */
+ private static final int STACK_NODE_PARKED = 2;
+ /*
+ * Timed Park state indicates that the Looper thread is sleeping, waiting for a message
+ * deadline
+ */
+ private static final int STACK_NODE_TIMEDPARK = 3;
+
+ /* Describes a node in the Treiber stack */
+ static class StackNode {
+ @StackNodeType
+ private final int mType;
+
+ StackNode(@StackNodeType int type) {
+ mType = type;
+ }
+
+ @StackNodeType
+ final int getNodeType() {
+ return mType;
+ }
+
+ final boolean isMessageNode() {
+ return mType == STACK_NODE_MESSAGE;
+ }
+ }
+
+ static final class MessageNode extends StackNode implements Comparable<MessageNode> {
+ private final Message mMessage;
+ volatile StackNode mNext;
+ StateNode mBottomOfStack;
+ boolean mWokeUp;
+ boolean mRemovedFromStack = false;
+ final long mInsertSeq;
+
+ MessageNode(@NonNull Message message, long insertSeq) {
+ super(STACK_NODE_MESSAGE);
+ mMessage = message;
+ mInsertSeq = insertSeq;
+ }
+
+ long getWhen() {
+ return mMessage.when;
+ }
+
+ boolean isRemovedFromStack() {
+ return mRemovedFromStack;
+ }
+
+ boolean removeFromStack() {
+ if (!mRemovedFromStack) {
+ mRemovedFromStack = true;
+ return true;
+ }
+ return false;
+ }
+
+ boolean isAsync() {
+ return mMessage.isAsynchronous();
+ }
+
+ boolean isBarrier() {
+ return mMessage.target == null;
+ }
+
+ @Override
+ public int compareTo(@NonNull MessageNode messageNode) {
+ Message other = messageNode.mMessage;
+
+ int compared = Long.compare(mMessage.when, other.when);
+ if (compared == 0) {
+ compared = Long.compare(mInsertSeq, messageNode.mInsertSeq);
+ }
+ return compared;
+ }
+ }
+
+ static class StateNode extends StackNode {
+ StateNode(int type) {
+ super(type);
+ }
+ }
+
+ static final class TimedParkStateNode extends StateNode {
+ long mWhenToWake;
+
+ TimedParkStateNode() {
+ super(STACK_NODE_TIMEDPARK);
+ }
+ }
+
+ private static final StateNode sStackStateActive = new StateNode(STACK_NODE_ACTIVE);
+ private static final StateNode sStackStateParked = new StateNode(STACK_NODE_PARKED);
+ private final TimedParkStateNode mStackStateTimedPark = new TimedParkStateNode();
+
+ /* This is the top of our treiber stack. */
+ private static final VarHandle sState;
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ sState = l.findVarHandle(MessageQueue.class, "mStateValue",
+ MessageQueue.StackNode.class);
+ } catch (Exception e) {
+ Log.wtf(TAG, "VarHandle lookup failed with exception: " + e);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private volatile StackNode mStateValue = sStackStateParked;
+ @GuardedBy("mPriorityQueue")
+ private final PriorityQueue<MessageNode> mPriorityQueue =
+ new PriorityQueue<MessageNode>();
+ @GuardedBy("mPriorityQueue")
+ private final PriorityQueue<MessageNode> mAsyncPriorityQueue =
+ new PriorityQueue<MessageNode>();
+
+ /*
+ * This helps us ensure that messages with the same timestamp are inserted in FIFO order.
+ * Increments on each insert, starting at 0. MessageNode.compareTo() will compare sequences
+ * when delivery timestamps are identical.
+ */
+ private static final VarHandle sNextInsertSeq;
+ private volatile long mNextInsertSeqValue = 0;
+ /*
+ * The exception to the FIFO order rule is sendMessageAtFrontOfQueue().
+ * Those messages must be in LIFO order - SIGH.
+ * Decrements on each front of queue insert.
+ */
+ private static final VarHandle sNextFrontInsertSeq;
+ private volatile long mNextFrontInsertSeqValue = -1;
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ sNextInsertSeq = l.findVarHandle(MessageQueue.class, "mNextInsertSeqValue",
+ long.class);
+ sNextFrontInsertSeq = l.findVarHandle(MessageQueue.class, "mNextFrontInsertSeqValue",
+ long.class);
+ } catch (Exception e) {
+ Log.wtf(TAG, "VarHandle lookup failed with exception: " + e);
+ throw new ExceptionInInitializerError(e);
+ }
+
+ }
+
+ /*
+ * Tracks the number of queued and cancelled messages in our stack.
+ *
+ * On item cancellation, determine whether to wake next() to flush tombstoned messages.
+ * We track queued and cancelled counts as two ints packed into a single long.
+ */
+ private static final class MessageCounts {
+ private static VarHandle sCounts;
+ private volatile long mCountsValue = 0;
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ sCounts = l.findVarHandle(MessageQueue.MessageCounts.class, "mCountsValue",
+ long.class);
+ } catch (Exception e) {
+ Log.wtf(TAG, "VarHandle lookup failed with exception: " + e);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+ /* We use a special value to indicate when next() has been woken for flush. */
+ private static final long AWAKE = Long.MAX_VALUE;
+ /*
+ * Minimum number of messages in the stack which we need before we consider flushing
+ * tombstoned items.
+ */
+ private static final int MESSAGE_FLUSH_THRESHOLD = 10;
+
+ private static int numQueued(long val) {
+ return (int) (val >>> Integer.SIZE);
+ }
+
+ private static int numCancelled(long val) {
+ return (int) val;
+ }
+
+ private static long combineCounts(int queued, int cancelled) {
+ return ((long) queued << Integer.SIZE) | (long) cancelled;
+ }
+
+ public void incrementQueued() {
+ while (true) {
+ long oldVal = mCountsValue;
+ int queued = numQueued(oldVal);
+ int cancelled = numCancelled(oldVal);
+ /* Use Math.max() to avoid overflow of queued count */
+ long newVal = combineCounts(Math.max(queued + 1, queued), cancelled);
+
+ /* Don't overwrite 'AWAKE' state */
+ if (oldVal == AWAKE || sCounts.compareAndSet(this, oldVal, newVal)) {
+ break;
+ }
+ }
+ }
+
+ public boolean incrementCancelled() {
+ while (true) {
+ long oldVal = mCountsValue;
+ if (oldVal == AWAKE) {
+ return false;
+ }
+ int queued = numQueued(oldVal);
+ int cancelled = numCancelled(oldVal);
+ boolean needsPurge = queued > MESSAGE_FLUSH_THRESHOLD
+ && (queued >> 1) < cancelled;
+ long newVal;
+ if (needsPurge) {
+ newVal = AWAKE;
+ } else {
+ newVal = combineCounts(queued,
+ Math.max(cancelled + 1, cancelled));
+ }
+
+ if (sCounts.compareAndSet(this, oldVal, newVal)) {
+ return needsPurge;
+ }
+ }
+ }
+
+ public void clearCounts() {
+ mCountsValue = 0;
+ }
+ }
+
+ private final MessageCounts mMessageCounts = new MessageCounts();
+
+ private final Object mIdleHandlersLock = new Object();
+ @GuardedBy("mIdleHandlersLock")
+ private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
+ private IdleHandler[] mPendingIdleHandlers;
+
+ private final Object mFileDescriptorRecordsLock = new Object();
+ @GuardedBy("mFileDescriptorRecordsLock")
+ private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
+
+ private static final VarHandle sQuitting;
+ private boolean mQuittingValue = false;
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ sQuitting = l.findVarHandle(MessageQueue.class, "mQuittingValue", boolean.class);
+ } catch (Exception e) {
+ Log.wtf(TAG, "VarHandle lookup failed with exception: " + e);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ // The next barrier token.
+ // Barriers are indicated by messages with a null target whose arg1 field carries the token.
+ private final AtomicInteger mNextBarrierToken = new AtomicInteger(1);
+
+ private static native long nativeInit();
+ private static native void nativeDestroy(long ptr);
+ private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
+ private static native void nativeWake(long ptr);
+ private static native boolean nativeIsPolling(long ptr);
+ private static native void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
+
+ MessageQueue(boolean quitAllowed) {
+ mQuitAllowed = quitAllowed;
+ mPtr = nativeInit();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ dispose();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ // Disposes of the underlying message queue.
+ // Must only be called on the looper thread or the finalizer.
+ private void dispose() {
+ if (mPtr != 0) {
+ nativeDestroy(mPtr);
+ mPtr = 0;
+ }
+ }
+
+ /**
+ * Returns true if the looper has no pending messages which are due to be processed.
+ *
+ * <p>This method is safe to call from any thread.
+ *
+ * @return True if the looper is idle.
+ */
+ public boolean isIdle() {
+ MessageNode msgNode = null;
+ MessageNode asyncMsgNode = null;
+
+ synchronized (mPriorityQueue) {
+ msgNode = mPriorityQueue.peek();
+ asyncMsgNode = mAsyncPriorityQueue.peek();
+
+ final long now = SystemClock.uptimeMillis();
+ if ((msgNode != null && msgNode.getWhen() <= now)
+ || (asyncMsgNode != null && asyncMsgNode.getWhen() <= now)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Add a new {@link IdleHandler} to this message queue. This may be
+ * removed automatically for you by returning false from
+ * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
+ * invoked, or explicitly removing it with {@link #removeIdleHandler}.
+ *
+ * <p>This method is safe to call from any thread.
+ *
+ * @param handler The IdleHandler to be added.
+ */
+ public void addIdleHandler(@NonNull IdleHandler handler) {
+ if (handler == null) {
+ throw new NullPointerException("Can't add a null IdleHandler");
+ }
+ synchronized (mIdleHandlersLock) {
+ mIdleHandlers.add(handler);
+ }
+ }
+
+ /**
+ * Remove an {@link IdleHandler} from the queue that was previously added
+ * with {@link #addIdleHandler}. If the given object is not currently
+ * in the idle list, nothing is done.
+ *
+ * <p>This method is safe to call from any thread.
+ *
+ * @param handler The IdleHandler to be removed.
+ */
+ public void removeIdleHandler(@NonNull IdleHandler handler) {
+ synchronized (mIdleHandlersLock) {
+ mIdleHandlers.remove(handler);
+ }
+ }
+
+ /**
+ * Returns whether this looper's thread is currently polling for more work to do.
+ * This is a good signal that the loop is still alive rather than being stuck
+ * handling a callback. Note that this method is intrinsically racy, since the
+ * state of the loop can change before you get the result back.
+ *
+ * <p>This method is safe to call from any thread.
+ *
+ * @return True if the looper is currently polling for events.
+ * @hide
+ */
+ public boolean isPolling() {
+ // If the loop is quitting then it must not be idling.
+ // We can assume mPtr != 0 when sQuitting is false.
+ return !((boolean) sQuitting.getVolatile(this)) && nativeIsPolling(mPtr);
+ }
+
+ /* Helper to choose the correct queue to insert into. */
+ @GuardedBy("mPriorityQueue")
+ private void insertIntoPriorityQueue(MessageNode msgNode) {
+ if (msgNode.isAsync()) {
+ mAsyncPriorityQueue.offer(msgNode);
+ } else {
+ mPriorityQueue.offer(msgNode);
+ }
+ }
+
+ @GuardedBy("mPriorityQueue")
+ private boolean removeFromPriorityQueue(MessageNode msgNode) {
+ if (msgNode.isAsync()) {
+ return mAsyncPriorityQueue.remove(msgNode);
+ } else {
+ return mPriorityQueue.remove(msgNode);
+ }
+ }
+
+ private MessageNode pickEarliestNode(MessageNode nodeA, MessageNode nodeB) {
+ if (nodeA != null && nodeB != null) {
+ if (nodeA.compareTo(nodeB) < 0) {
+ return nodeA;
+ }
+ return nodeB;
+ }
+
+ return nodeA != null ? nodeA : nodeB;
+ }
+
+ /* Move any non-cancelled messages into the priority queue */
+ private void drainStack(StackNode oldTop) {
+ while (oldTop.isMessageNode()) {
+ MessageNode oldTopMessageNode = (MessageNode) oldTop;
+ if (oldTopMessageNode.removeFromStack()) {
+ insertIntoPriorityQueue(oldTopMessageNode);
+ }
+ MessageNode inserted = oldTopMessageNode;
+ oldTop = oldTopMessageNode.mNext;
+ }
+ }
+
+ /* Set the stack state to Active, return a list of nodes to walk. */
+ private StackNode swapAndSetStackStateActive() {
+ while (true) {
+ /* Set stack state to Active, get node list to walk later */
+ StackNode current = (StackNode) sState.getVolatile(this);
+ if (current == sStackStateActive
+ || sState.compareAndSet(this, current, sStackStateActive)) {
+ return current;
+ }
+ }
+ }
+
+ /* This is only read/written from the Looper thread */
+ private int mNextPollTimeoutMillis;
+ private static final AtomicLong mMessagesDelivered = new AtomicLong();
+
+ private Message nextMessage() {
+ int i = 0;
+
+ while (true) {
+ if (DEBUG) {
+ Log.d(TAG, "nextMessage loop #" + i);
+ i++;
+ }
+
+ /* This protects us from racing with remove. Enqueue can still add items. */
+ synchronized (mPriorityQueue) {
+
+ /*
+ * Set our state to active, drain any items from the stack into our priority queues
+ */
+ StackNode oldTop;
+ oldTop = swapAndSetStackStateActive();
+ drainStack(oldTop);
+
+ /*
+ * The objective of this next block of code is to:
+ * - find a message to return (if any is ready)
+ * - find a next message we would like to return, after scheduling.
+ * - we make our scheduling decision based on this next message (if it exists).
+ *
+ * We have two queues to juggle and the presence of barriers throws an additional
+ * wrench into our plans.
+ */
+
+ /* Get the first node from each queue */
+ MessageNode msgNode = mPriorityQueue.peek();
+ MessageNode asyncMsgNode = mAsyncPriorityQueue.peek();
+
+ if (DEBUG) {
+ if (msgNode != null) {
+ Message msg = msgNode.mMessage;
+ Log.d(TAG, "Next found node what: " + msg.what + " when: " + msg.when
+ + " seq: " + msgNode.mInsertSeq + "barrier: "
+ + msgNode.isBarrier() + " now: "
+ + SystemClock.uptimeMillis());
+ }
+ if (asyncMsgNode != null) {
+ Message msg = asyncMsgNode.mMessage;
+ Log.d(TAG, "Next found async node what: " + msg.what + " when: " + msg.when
+ + " seq: " + asyncMsgNode.mInsertSeq + "barrier: "
+ + asyncMsgNode.isBarrier() + " now: "
+ + SystemClock.uptimeMillis());
+ }
+ }
+
+ /*
+ * the node which we will return, null if none are ready
+ */
+ MessageNode found = null;
+ /*
+ * The node from which we will determine our next wakeup time.
+ * Null indicates there is no next message ready. If we found a node,
+ * we can leave this null as Looper will call us again after delivering
+ * the message.
+ */
+ MessageNode next = null;
+
+ long now = SystemClock.uptimeMillis();
+ /*
+ * If we have a barrier we should return the async node if it exists and is
+ * ready
+ */
+ if (msgNode != null && msgNode.isBarrier()) {
+ if (asyncMsgNode != null && now >= asyncMsgNode.getWhen()) {
+ found = asyncMsgNode;
+ removeFromPriorityQueue(found);
+ } else {
+ next = asyncMsgNode;
+ }
+ } else { /* No barrier. */
+ MessageNode earliest;
+ /*
+ * If we have two messages, pick the earliest option from either queue.
+ * Otherwise grab whichever node is non-null. If both are null we'll fall
+ * through.
+ */
+ earliest = pickEarliestNode(msgNode, asyncMsgNode);
+
+ if (earliest != null) {
+ if (now >= earliest.getWhen()) {
+ found = earliest;
+ removeFromPriorityQueue(found);
+ } else {
+ next = earliest;
+ }
+ }
+ }
+
+ if (DEBUG) {
+ if (found != null) {
+ Message msg = found.mMessage;
+ Log.d(TAG, "Will deliver node what: " + msg.what + " when: " + msg.when
+ + " seq: " + found.mInsertSeq + " barrier: "
+ + found.isBarrier() + " async: " + found.isAsync()
+ + " now: " + SystemClock.uptimeMillis());
+ } else {
+ Log.d(TAG, "No node to deliver");
+ }
+ if (next != null) {
+ Message msg = next.mMessage;
+ Log.d(TAG, "Next node what: " + msg.what + " when: " + msg.when + " seq: "
+ + next.mInsertSeq + " barrier: " + next.isBarrier()
+ + " async: " + next.isAsync()
+ + " now: " + SystemClock.uptimeMillis());
+ } else {
+ Log.d(TAG, "No next node");
+ }
+ }
+
+ /*
+ * If we have a found message, we will get called again so there's no need to set
+ * state.
+ * In that case we can leave our state as ACTIVE.
+ *
+ * Otherwise we should determine how to park the thread.
+ */
+ StateNode nextOp = sStackStateActive;
+ if (found == null) {
+ if (next == null) {
+ /* No message to deliver, sleep indefinitely */
+ mNextPollTimeoutMillis = -1;
+ nextOp = sStackStateParked;
+ if (DEBUG) {
+ Log.d(TAG, "nextMessage next state is StackStateParked");
+ }
+ } else {
+ /* Message not ready, or we found one to deliver already, set a timeout */
+ long nextMessageWhen = next.getWhen();
+ if (nextMessageWhen > now) {
+ mNextPollTimeoutMillis = (int) Math.min(nextMessageWhen - now,
+ Integer.MAX_VALUE);
+ } else {
+ mNextPollTimeoutMillis = 0;
+ }
+
+ mStackStateTimedPark.mWhenToWake = now + mNextPollTimeoutMillis;
+ nextOp = mStackStateTimedPark;
+ if (DEBUG) {
+ Log.d(TAG, "nextMessage next state is StackStateTimedParked "
+ + " next timeout ms " + mNextPollTimeoutMillis
+ + " mWhenToWake: " + mStackStateTimedPark.mWhenToWake
+ + " now " + now);
+ }
+ }
+ }
+
+ /*
+ * Try to swap our state from Active back to Park or TimedPark. If we raced with
+ * enqueue, loop back around to pick up any new items.
+ */
+ if (sState.compareAndSet(this, sStackStateActive, nextOp)) {
+ mMessageCounts.clearCounts();
+ if (found != null) {
+ if (TRACE) {
+ Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
+ }
+ return found.mMessage;
+ }
+ return null;
+ }
+ if (found != null) {
+ /*
+ * Add this node back - we will be adding new nodes into our priority queue, and
+ * recalculating what to return.
+ */
+ insertIntoPriorityQueue(found);
+ }
+ }
+ }
+ }
+
+ Message next() {
+ final long ptr = mPtr;
+ if (ptr == 0) {
+ return null;
+ }
+
+ mNextPollTimeoutMillis = 0;
+ int pendingIdleHandlerCount = -1; // -1 only during first iteration
+ while (true) {
+ if (mNextPollTimeoutMillis != 0) {
+ Binder.flushPendingCommands();
+ }
+
+ nativePollOnce(ptr, mNextPollTimeoutMillis);
+
+ Message msg = nextMessage();
+ if (msg != null) {
+ msg.markInUse();
+ return msg;
+ }
+
+ if ((boolean) sQuitting.getVolatile(this)) {
+ return null;
+ }
+
+ synchronized (mIdleHandlersLock) {
+ // If first time idle, then get the number of idlers to run.
+ // Idle handles only run if the queue is empty or if the first message
+ // in the queue (possibly a barrier) is due to be handled in the future.
+ if (pendingIdleHandlerCount < 0
+ && mNextPollTimeoutMillis != 0) {
+ pendingIdleHandlerCount = mIdleHandlers.size();
+ }
+ if (pendingIdleHandlerCount <= 0) {
+ // No idle handlers to run. Loop and wait some more.
+ continue;
+ }
+
+ if (mPendingIdleHandlers == null) {
+ mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
+ }
+ mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
+ }
+
+ // Run the idle handlers.
+ // We only ever reach this code block during the first iteration.
+ for (int i = 0; i < pendingIdleHandlerCount; i++) {
+ final IdleHandler idler = mPendingIdleHandlers[i];
+ mPendingIdleHandlers[i] = null; // release the reference to the handler
+
+ boolean keep = false;
+ try {
+ keep = idler.queueIdle();
+ } catch (Throwable t) {
+ Log.wtf(TAG, "IdleHandler threw exception", t);
+ }
+
+ if (!keep) {
+ synchronized (mIdleHandlersLock) {
+ mIdleHandlers.remove(idler);
+ }
+ }
+ }
+
+ // Reset the idle handler count to 0 so we do not run them again.
+ pendingIdleHandlerCount = 0;
+
+ // While calling an idle handler, a new message could have been delivered
+ // so go back and look again for a pending message without waiting.
+ mNextPollTimeoutMillis = 0;
+ }
+ }
+
+ void quit(boolean safe) {
+ if (!mQuitAllowed) {
+ throw new IllegalStateException("Main thread not allowed to quit.");
+ }
+ synchronized (mIdleHandlersLock) {
+ if (sQuitting.compareAndSet(this, false, true)) {
+ if (safe) {
+ removeAllFutureMessages();
+ } else {
+ removeAllMessages();
+ }
+
+ // We can assume mPtr != 0 because sQuitting was previously false.
+ nativeWake(mPtr);
+ }
+ }
+ }
+
+ boolean enqueueMessage(@NonNull Message msg, long when) {
+ if (msg.target == null) {
+ throw new IllegalArgumentException("Message must have a target.");
+ }
+
+ if (msg.isInUse()) {
+ throw new IllegalStateException(msg + " This message is already in use.");
+ }
+
+ return enqueueMessageUnchecked(msg, when);
+ }
+
+ private boolean enqueueMessageUnchecked(@NonNull Message msg, long when) {
+ if ((boolean) sQuitting.getVolatile(this)) {
+ IllegalStateException e = new IllegalStateException(
+ msg.target + " sending message to a Handler on a dead thread");
+ Log.w(TAG, e.getMessage(), e);
+ msg.recycleUnchecked();
+ return false;
+ }
+
+ long seq = when != 0 ? ((long)sNextInsertSeq.getAndAdd(this, 1L) + 1L)
+ : ((long)sNextFrontInsertSeq.getAndAdd(this, -1L) - 1L);
+ /* TODO: Add a MessageNode member to Message so we can avoid this allocation */
+ MessageNode node = new MessageNode(msg, seq);
+ msg.when = when;
+ msg.markInUse();
+
+ if (DEBUG) {
+ Log.d(TAG, "Insert message what: " + msg.what + " when: " + msg.when + " seq: "
+ + node.mInsertSeq + " barrier: " + node.isBarrier() + " async: "
+ + node.isAsync() + " now: " + SystemClock.uptimeMillis());
+ }
+
+ while (true) {
+ StackNode old = (StackNode) sState.getVolatile(this);
+ boolean wakeNeeded;
+ boolean inactive;
+
+ node.mNext = old;
+ switch (old.getNodeType()) {
+ case STACK_NODE_ACTIVE:
+ /*
+ * The worker thread is currently active and will process any elements added to
+ * the stack before parking again.
+ */
+ node.mBottomOfStack = (StateNode) old;
+ inactive = false;
+ node.mWokeUp = true;
+ wakeNeeded = false;
+ break;
+
+ case STACK_NODE_PARKED:
+ node.mBottomOfStack = (StateNode) old;
+ inactive = true;
+ node.mWokeUp = true;
+ wakeNeeded = true;
+ break;
+
+ case STACK_NODE_TIMEDPARK:
+ node.mBottomOfStack = (StateNode) old;
+ inactive = true;
+ wakeNeeded = mStackStateTimedPark.mWhenToWake >= node.getWhen();
+ node.mWokeUp = wakeNeeded;
+ break;
+
+ default:
+ MessageNode oldMessage = (MessageNode) old;
+
+ node.mBottomOfStack = oldMessage.mBottomOfStack;
+ int bottomType = node.mBottomOfStack.getNodeType();
+ inactive = bottomType >= STACK_NODE_PARKED;
+ wakeNeeded = (bottomType == STACK_NODE_TIMEDPARK
+ && mStackStateTimedPark.mWhenToWake >= node.getWhen()
+ && !oldMessage.mWokeUp);
+ node.mWokeUp = oldMessage.mWokeUp || wakeNeeded;
+ break;
+ }
+ if (sState.compareAndSet(this, old, node)) {
+ if (inactive) {
+ if (wakeNeeded) {
+ nativeWake(mPtr);
+ } else {
+ mMessageCounts.incrementQueued();
+ }
+ }
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Posts a synchronization barrier to the Looper's message queue.
+ *
+ * Message processing occurs as usual until the message queue encounters the
+ * synchronization barrier that has been posted. When the barrier is encountered,
+ * later synchronous messages in the queue are stalled (prevented from being executed)
+ * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
+ * the token that identifies the synchronization barrier.
+ *
+ * This method is used to immediately postpone execution of all subsequently posted
+ * synchronous messages until a condition is met that releases the barrier.
+ * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
+ * and continue to be processed as usual.
+ *
+ * This call must be always matched by a call to {@link #removeSyncBarrier} with
+ * the same token to ensure that the message queue resumes normal operation.
+ * Otherwise the application will probably hang!
+ *
+ * @return A token that uniquely identifies the barrier. This token must be
+ * passed to {@link #removeSyncBarrier} to release the barrier.
+ *
+ * @hide
+ */
+ @TestApi
+ public int postSyncBarrier() {
+ return postSyncBarrier(SystemClock.uptimeMillis());
+ }
+
+ private int postSyncBarrier(long when) {
+ final int token = mNextBarrierToken.getAndIncrement();
+ final Message msg = Message.obtain();
+
+ msg.markInUse();
+ msg.arg1 = token;
+
+ if (!enqueueMessageUnchecked(msg, when)) {
+ Log.wtf(TAG, "Unexpected error while adding sync barrier!");
+ return -1;
+ }
+
+ return token;
+ }
+
+ private class MatchBarrierToken extends MessageCompare {
+ int mBarrierToken;
+
+ MatchBarrierToken(int token) {
+ super();
+ mBarrierToken = token;
+ }
+
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == null && m.arg1 == mBarrierToken) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Removes a synchronization barrier.
+ *
+ * @param token The synchronization barrier token that was returned by
+ * {@link #postSyncBarrier}.
+ *
+ * @throws IllegalStateException if the barrier was not found.
+ *
+ * @hide
+ */
+ @TestApi
+ public void removeSyncBarrier(int token) {
+ boolean removed;
+ MessageNode first;
+ final MatchBarrierToken matchBarrierToken = new MatchBarrierToken(token);
+
+ synchronized (mPriorityQueue) {
+ try {
+ /* Retain the first element to see if we are currently stuck on a barrier. */
+ first = mPriorityQueue.peek();
+ } catch (NoSuchElementException e) {
+ /* The queue is empty */
+ first = null;
+ }
+
+ removed = findOrRemoveMessages(null, 0, null, null, 0, matchBarrierToken, true);
+ if (removed && first != null) {
+ Message m = first.mMessage;
+ if (m.target == null && m.arg1 == token) {
+ /* Wake up next() in case it was sleeping on this barrier. */
+ nativeWake(mPtr);
+ }
+ } else if (!removed) {
+ throw new IllegalStateException("The specified message queue synchronization "
+ + " barrier token has not been posted or has already been removed.");
+ }
+ }
+ }
+
+ private StateNode getStateNode(StackNode node) {
+ if (node.isMessageNode()) {
+ return ((MessageNode) node).mBottomOfStack;
+ }
+ return (StateNode) node;
+ }
+
+ /*
+ * This class is used to find matches for hasMessages() and removeMessages()
+ */
+ private abstract static class MessageCompare {
+ public abstract boolean compareMessage(Message m, Handler h, int what, Object object,
+ Runnable r, long when);
+ }
+ @GuardedBy("mPriorityQueue")
+ private boolean stackHasMessages(Handler h, int what, Object object, Runnable r, long when,
+ MessageCompare compare, boolean removeMatches) {
+ boolean found = false;
+ StackNode top = (StackNode) sState.getVolatile(this);
+ StateNode bottom = getStateNode(top);
+
+ /* No messages to search. */
+ if (!top.isMessageNode()) {
+ return false;
+ }
+
+ /*
+ * We have messages that we may tombstone. Walk the stack until we hit the bottom.
+ * next() will remove them on it's next pass.
+ */
+ if (!(top instanceof MessageNode)) {
+ Log.wtf(TAG, "Unknown node type found in Trieber stack");
+ }
+ MessageNode p = (MessageNode) top;
+
+ while (true) {
+ if (compare.compareMessage(p.mMessage, h, what, object, r, when)) {
+ found = true;
+ if (DEBUG) {
+ Log.w(TAG, "stackHasMessages node matches");
+ }
+ if (removeMatches) {
+ if (p.removeFromStack()) {
+ p.mMessage.recycleUnchecked();
+ if (mMessageCounts.incrementCancelled()) {
+ nativeWake(mPtr);
+ }
+ }
+ } else {
+ return true;
+ }
+ }
+
+ StackNode n = p.mNext;
+ if (!n.isMessageNode()) {
+ /* We reached the end of the stack */
+ return found;
+ }
+ p = (MessageNode) n;
+ }
+ }
+
+ @GuardedBy("mPriorityQueue")
+ private boolean priorityQueueHasMessage(PriorityQueue queue, Handler h,
+ int what, Object object, Runnable r, long when, MessageCompare compare,
+ boolean removeMatches) {
+ Iterator<MessageNode> iterator = queue.iterator();
+ boolean found = false;
+
+ while (iterator.hasNext()) {
+ MessageNode msg = iterator.next();
+
+ if (compare.compareMessage(msg.mMessage, h, what, object, r, when)) {
+ if (removeMatches) {
+ found = true;
+ iterator.remove();
+ msg.mMessage.recycleUnchecked();
+ } else {
+ return true;
+ }
+ }
+ }
+ return found;
+ }
+
+ private boolean findOrRemoveMessages(Handler h, int what, Object object, Runnable r, long when,
+ MessageCompare compare, boolean removeMatches) {
+ boolean foundInStack, foundInQueue;
+
+ synchronized (mPriorityQueue) {
+ foundInStack = stackHasMessages(h, what, object, r, when, compare, removeMatches);
+ foundInQueue = priorityQueueHasMessage(mPriorityQueue, h, what, object, r, when,
+ compare, removeMatches);
+ foundInQueue |= priorityQueueHasMessage(mAsyncPriorityQueue, h, what, object, r, when,
+ compare, removeMatches);
+
+ return foundInStack || foundInQueue;
+ }
+ }
+
+ private static class MatchHandlerWhatAndObject extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && m.what == what && (object == null || m.obj == object)) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerWhatAndObject mMatchHandlerWhatAndObject =
+ new MatchHandlerWhatAndObject();
+ boolean hasMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return false;
+ }
+
+ return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, false);
+ }
+
+ private static class MatchHandlerWhatAndObjectEquals extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && m.what == what && (object == null || object.equals(m.obj))) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerWhatAndObjectEquals mMatchHandlerWhatAndObjectEquals =
+ new MatchHandlerWhatAndObjectEquals();
+ boolean hasEqualMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return false;
+ }
+
+ return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals,
+ false);
+ }
+
+ private static class MatchHandlerRunnableAndObject extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && m.callback == r && (object == null || m.obj == object)) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerRunnableAndObject mMatchHandlerRunnableAndObject =
+ new MatchHandlerRunnableAndObject();
+
+ boolean hasMessages(Handler h, Runnable r, Object object) {
+ if (h == null) {
+ return false;
+ }
+
+ return findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, false);
+ }
+
+ private static class MatchHandler extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandler mMatchHandler = new MatchHandler();
+ boolean hasMessages(Handler h) {
+ if (h == null) {
+ return false;
+ }
+ return findOrRemoveMessages(h, -1, null, null, 0, mMatchHandler, false);
+ }
+
+ void removeMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return;
+ }
+ findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, true);
+ }
+
+ void removeEqualMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return;
+ }
+ findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals, true);
+ }
+
+ void removeMessages(Handler h, Runnable r, Object object) {
+ if (h == null || r == null) {
+ return;
+ }
+ findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, true);
+ }
+
+ private static class MatchHandlerRunnableAndObjectEquals extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && m.callback == r && (object == null || object.equals(m.obj))) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerRunnableAndObjectEquals mMatchHandlerRunnableAndObjectEquals =
+ new MatchHandlerRunnableAndObjectEquals();
+ void removeEqualMessages(Handler h, Runnable r, Object object) {
+ if (h == null || r == null) {
+ return;
+ }
+ findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObjectEquals, true);
+ }
+
+ private static class MatchHandlerAndObject extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && (object == null || m.obj == object)) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerAndObject mMatchHandlerAndObject = new MatchHandlerAndObject();
+ void removeCallbacksAndMessages(Handler h, Object object) {
+ if (h == null) {
+ return;
+ }
+ findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObject, true);
+ }
+
+ private static class MatchHandlerAndObjectEquals extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.target == h && (object == null || object.equals(m.obj))) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchHandlerAndObjectEquals mMatchHandlerAndObjectEquals =
+ new MatchHandlerAndObjectEquals();
+ void removeCallbacksAndEqualMessages(Handler h, Object object) {
+ if (h == null) {
+ return;
+ }
+ findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObjectEquals, true);
+ }
+
+ private static class MatchAllMessages extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ return true;
+ }
+ }
+ private final MatchAllMessages mMatchAllMessages = new MatchAllMessages();
+ private void removeAllMessages() {
+ findOrRemoveMessages(null, -1, null, null, 0, mMatchAllMessages, true);
+ }
+
+ private static class MatchAllFutureMessages extends MessageCompare {
+ @Override
+ public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
+ long when) {
+ if (m.when > when) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private final MatchAllFutureMessages mMatchAllFutureMessages = new MatchAllFutureMessages();
+ private void removeAllFutureMessages() {
+ findOrRemoveMessages(null, -1, null, null, SystemClock.uptimeMillis(),
+ mMatchAllFutureMessages, true);
+ }
+
+ private void printPriorityQueueNodes() {
+ Iterator<MessageNode> iterator = mPriorityQueue.iterator();
+
+ Log.d(TAG, "* Dump priority queue");
+ while (iterator.hasNext()) {
+ MessageNode msgNode = iterator.next();
+ Log.d(TAG, "** MessageNode what: " + msgNode.mMessage.what + " when "
+ + msgNode.mMessage.when + " seq: " + msgNode.mInsertSeq);
+ }
+ }
+
+ private int dumpPriorityQueue(PriorityQueue<MessageNode> queue, Printer pw, String prefix,
+ Handler h, int n) {
+ int count = 0;
+ long now = SystemClock.uptimeMillis();
+
+ for (MessageNode msgNode : queue) {
+ Message msg = msgNode.mMessage;
+ if (h == null || h == msg.target) {
+ pw.println(prefix + "Message " + (n + count) + ": " + msg.toString(now));
+ }
+ count++;
+ }
+ return count;
+ }
+
+ void dump(Printer pw, String prefix, Handler h) {
+ long now = SystemClock.uptimeMillis();
+ int n = 0;
+
+ pw.println(prefix + "(MessageQueue is using SemiConcurrent implementation)");
+
+ StackNode node = (StackNode) sState.getVolatile(this);
+ while (node != null) {
+ if (node.isMessageNode()) {
+ Message msg = ((MessageNode) node).mMessage;
+ if (h == null || h == msg.target) {
+ pw.println(prefix + "Message " + n + ": " + msg.toString(now));
+ }
+ node = ((MessageNode) node).mNext;
+ } else {
+ pw.println(prefix + "State: " + node);
+ node = null;
+ }
+ n++;
+ }
+
+ synchronized (mPriorityQueue) {
+ pw.println(prefix + "PriorityQueue Messages: ");
+ n += dumpPriorityQueue(mPriorityQueue, pw, prefix, h, n);
+ pw.println(prefix + "AsyncPriorityQueue Messages: ");
+ n += dumpPriorityQueue(mAsyncPriorityQueue, pw, prefix, h, n);
+ }
+
+ pw.println(prefix + "(Total messages: " + n + ", polling=" + isPolling()
+ + ", quitting=" + (boolean) sQuitting.getVolatile(this) + ")");
+ }
+
+ private int dumpPriorityQueue(PriorityQueue<MessageNode> queue, ProtoOutputStream proto) {
+ int count = 0;
+
+ for (MessageNode msgNode : queue) {
+ Message msg = msgNode.mMessage;
+ msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
+ count++;
+ }
+ return count;
+ }
+
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long messageQueueToken = proto.start(fieldId);
+
+ StackNode node = (StackNode) sState.getVolatile(this);
+ while (node.isMessageNode()) {
+ Message msg = ((MessageNode) node).mMessage;
+ msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
+ node = ((MessageNode) node).mNext;
+ }
+
+ synchronized (mPriorityQueue) {
+ dumpPriorityQueue(mPriorityQueue, proto);
+ dumpPriorityQueue(mAsyncPriorityQueue, proto);
+ }
+
+ proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPolling());
+ proto.write(MessageQueueProto.IS_QUITTING, (boolean) sQuitting.getVolatile(this));
+ proto.end(messageQueueToken);
+ }
+
+ /**
+ * Adds a file descriptor listener to receive notification when file descriptor
+ * related events occur.
+ * <p>
+ * If the file descriptor has already been registered, the specified events
+ * and listener will replace any that were previously associated with it.
+ * It is not possible to set more than one listener per file descriptor.
+ * </p><p>
+ * It is important to always unregister the listener when the file descriptor
+ * is no longer of use.
+ * </p>
+ *
+ * @param fd The file descriptor for which a listener will be registered.
+ * @param events The set of events to receive: a combination of the
+ * {@link OnFileDescriptorEventListener#EVENT_INPUT},
+ * {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
+ * {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested
+ * set of events is zero, then the listener is unregistered.
+ * @param listener The listener to invoke when file descriptor events occur.
+ *
+ * @see OnFileDescriptorEventListener
+ * @see #removeOnFileDescriptorEventListener
+ */
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
+ public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
+ @OnFileDescriptorEventListener.Events int events,
+ @NonNull OnFileDescriptorEventListener listener) {
+ if (fd == null) {
+ throw new IllegalArgumentException("fd must not be null");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ synchronized (mFileDescriptorRecordsLock) {
+ updateOnFileDescriptorEventListenerLocked(fd, events, listener);
+ }
+ }
+
+ /**
+ * Removes a file descriptor listener.
+ * <p>
+ * This method does nothing if no listener has been registered for the
+ * specified file descriptor.
+ * </p>
+ *
+ * @param fd The file descriptor whose listener will be unregistered.
+ *
+ * @see OnFileDescriptorEventListener
+ * @see #addOnFileDescriptorEventListener
+ */
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
+ public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
+ if (fd == null) {
+ throw new IllegalArgumentException("fd must not be null");
+ }
+
+ synchronized (mFileDescriptorRecordsLock) {
+ updateOnFileDescriptorEventListenerLocked(fd, 0, null);
+ }
+ }
+
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
+ private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
+ OnFileDescriptorEventListener listener) {
+ final int fdNum = fd.getInt$();
+
+ int index = -1;
+ FileDescriptorRecord record = null;
+ if (mFileDescriptorRecords != null) {
+ index = mFileDescriptorRecords.indexOfKey(fdNum);
+ if (index >= 0) {
+ record = mFileDescriptorRecords.valueAt(index);
+ if (record != null && record.mEvents == events) {
+ return;
+ }
+ }
+ }
+
+ if (events != 0) {
+ events |= OnFileDescriptorEventListener.EVENT_ERROR;
+ if (record == null) {
+ if (mFileDescriptorRecords == null) {
+ mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
+ }
+ record = new FileDescriptorRecord(fd, events, listener);
+ mFileDescriptorRecords.put(fdNum, record);
+ } else {
+ record.mListener = listener;
+ record.mEvents = events;
+ record.mSeq += 1;
+ }
+ nativeSetFileDescriptorEvents(mPtr, fdNum, events);
+ } else if (record != null) {
+ record.mEvents = 0;
+ mFileDescriptorRecords.removeAt(index);
+ nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
+ }
+ }
+
+ // Called from native code.
+ private int dispatchEvents(int fd, int events) {
+ // Get the file descriptor record and any state that might change.
+ final FileDescriptorRecord record;
+ final int oldWatchedEvents;
+ final OnFileDescriptorEventListener listener;
+ final int seq;
+ synchronized (mFileDescriptorRecordsLock) {
+ record = mFileDescriptorRecords.get(fd);
+ if (record == null) {
+ return 0; // spurious, no listener registered
+ }
+
+ oldWatchedEvents = record.mEvents;
+ events &= oldWatchedEvents; // filter events based on current watched set
+ if (events == 0) {
+ return oldWatchedEvents; // spurious, watched events changed
+ }
+
+ listener = record.mListener;
+ seq = record.mSeq;
+ }
+
+ // Invoke the listener outside of the lock.
+ int newWatchedEvents = listener.onFileDescriptorEvents(
+ record.mDescriptor, events);
+ if (newWatchedEvents != 0) {
+ newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
+ }
+
+ // Update the file descriptor record if the listener changed the set of
+ // events to watch and the listener itself hasn't been updated since.
+ if (newWatchedEvents != oldWatchedEvents) {
+ synchronized (mFileDescriptorRecordsLock) {
+ int index = mFileDescriptorRecords.indexOfKey(fd);
+ if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
+ && record.mSeq == seq) {
+ record.mEvents = newWatchedEvents;
+ if (newWatchedEvents == 0) {
+ mFileDescriptorRecords.removeAt(index);
+ }
+ }
+ }
+ }
+
+ // Return the new set of events to watch for native code to take care of.
+ return newWatchedEvents;
+ }
+
+ /**
+ * Callback interface for discovering when a thread is going to block
+ * waiting for more messages.
+ */
+ public static interface IdleHandler {
+ /**
+ * Called when the message queue has run out of messages and will now
+ * wait for more. Return true to keep your idle handler active, false
+ * to have it removed. This may be called if there are still messages
+ * pending in the queue, but they are all scheduled to be dispatched
+ * after the current time.
+ */
+ boolean queueIdle();
+ }
+
+ /**
+ * A listener which is invoked when file descriptor related events occur.
+ */
+ public interface OnFileDescriptorEventListener {
+ /**
+ * File descriptor event: Indicates that the file descriptor is ready for input
+ * operations, such as reading.
+ * <p>
+ * The listener should read all available data from the file descriptor
+ * then return <code>true</code> to keep the listener active or <code>false</code>
+ * to remove the listener.
+ * </p><p>
+ * In the case of a socket, this event may be generated to indicate
+ * that there is at least one incoming connection that the listener
+ * should accept.
+ * </p><p>
+ * This event will only be generated if the {@link #EVENT_INPUT} event mask was
+ * specified when the listener was added.
+ * </p>
+ */
+ public static final int EVENT_INPUT = 1 << 0;
+
+ /**
+ * File descriptor event: Indicates that the file descriptor is ready for output
+ * operations, such as writing.
+ * <p>
+ * The listener should write as much data as it needs. If it could not
+ * write everything at once, then it should return <code>true</code> to
+ * keep the listener active. Otherwise, it should return <code>false</code>
+ * to remove the listener then re-register it later when it needs to write
+ * something else.
+ * </p><p>
+ * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
+ * specified when the listener was added.
+ * </p>
+ */
+ public static final int EVENT_OUTPUT = 1 << 1;
+
+ /**
+ * File descriptor event: Indicates that the file descriptor encountered a
+ * fatal error.
+ * <p>
+ * File descriptor errors can occur for various reasons. One common error
+ * is when the remote peer of a socket or pipe closes its end of the connection.
+ * </p><p>
+ * This event may be generated at any time regardless of whether the
+ * {@link #EVENT_ERROR} event mask was specified when the listener was added.
+ * </p>
+ */
+ public static final int EVENT_ERROR = 1 << 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "EVENT_" }, value = {
+ EVENT_INPUT,
+ EVENT_OUTPUT,
+ EVENT_ERROR
+ })
+ public @interface Events {}
+
+ /**
+ * Called when a file descriptor receives events.
+ *
+ * @param fd The file descriptor.
+ * @param events The set of events that occurred: a combination of the
+ * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
+ * @return The new set of events to watch, or 0 to unregister the listener.
+ *
+ * @see #EVENT_INPUT
+ * @see #EVENT_OUTPUT
+ * @see #EVENT_ERROR
+ */
+ @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
+ }
+
+ static final class FileDescriptorRecord {
+ public final FileDescriptor mDescriptor;
+ public int mEvents;
+ public OnFileDescriptorEventListener mListener;
+ public int mSeq;
+
+ public FileDescriptorRecord(FileDescriptor descriptor,
+ int events, OnFileDescriptorEventListener listener) {
+ mDescriptor = descriptor;
+ mEvents = events;
+ mListener = listener;
+ }
+ }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 57853e7ded32..94c769293bff 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13396,7 +13396,19 @@ public final class Settings {
= "enable_freeform_support";
/**
- * Whether to enable experimental desktop mode on secondary displays.
+ * Whether to override the availability of the desktop mode on the main display of the
+ * device. If on, users can make move an app to the desktop, allowing a freeform windowing
+ * experience.
+ * @hide
+ */
+ @Readable
+ public static final String DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES =
+ "override_desktop_mode_features";
+
+ /**
+ * Whether to enable the legacy freeform support on secondary displays. If enabled, the
+ * SECONDARY_HOME of the launcher is started on any secondary display, allowing for a
+ * desktop experience.
* @hide
*/
@Readable
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 88bd87e6c27c..d019bad68cd5 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4940,7 +4940,7 @@ public final class Telephony {
*
* @hide
*/
- public static final String COLUMN_IS_NTN = "is_ntn";
+ public static final String COLUMN_IS_ONLY_NTN = "is_only_ntn";
/**
* TelephonyProvider column name for transferred status
@@ -4976,6 +4976,15 @@ public final class Telephony {
public static final String COLUMN_SATELLITE_ENTITLEMENT_PLMNS =
"satellite_entitlement_plmns";
+ /**
+ * TelephonyProvider column name to indicate the satellite ESOS supported. The value of this
+ * column is set based on {@link CarrierConfigManager#KEY_SATELLITE_ESOS_SUPPORTED_BOOL}.
+ * By default, it's disabled.
+ *
+ * @hide
+ */
+ public static final String COLUMN_SATELLITE_ESOS_SUPPORTED = "satellite_esos_supported";
+
/** All columns in {@link SimInfo} table. */
private static final List<String> ALL_COLUMNS = List.of(
COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
@@ -5047,11 +5056,12 @@ public final class Telephony {
COLUMN_USER_HANDLE,
COLUMN_SATELLITE_ENABLED,
COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
- COLUMN_IS_NTN,
+ COLUMN_IS_ONLY_NTN,
COLUMN_SERVICE_CAPABILITIES,
COLUMN_TRANSFER_STATUS,
COLUMN_SATELLITE_ENTITLEMENT_STATUS,
- COLUMN_SATELLITE_ENTITLEMENT_PLMNS
+ COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
+ COLUMN_SATELLITE_ESOS_SUPPORTED
);
/**
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 8ecb1fb4e9ad..2948129ae956 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -19,6 +19,7 @@ package android.service.dreams;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.service.dreams.Flags.dreamHandlesConfirmKeys;
import static android.service.dreams.Flags.dreamHandlesBeingObscured;
+import static android.service.dreams.Flags.startAndStopDozingInBackground;
import android.annotation.FlaggedApi;
import android.annotation.IdRes;
@@ -923,9 +924,16 @@ public class DreamService extends Service implements Window.Callback {
if (mDozing) {
try {
- mDreamManager.startDozing(
+ if (startAndStopDozingInBackground()) {
+ mDreamManager.startDozingOneway(
mDreamToken, mDozeScreenState, mDozeScreenStateReason,
mDozeScreenBrightness);
+ } else {
+ mDreamManager.startDozing(
+ mDreamToken, mDozeScreenState, mDozeScreenStateReason,
+ mDozeScreenBrightness);
+ }
+
} catch (RemoteException ex) {
// system server died
}
@@ -1250,7 +1258,11 @@ public class DreamService extends Service implements Window.Callback {
try {
// finishSelf will unbind the dream controller from the dream service. This will
// trigger DreamService.this.onDestroy and DreamService.this will die.
- mDreamManager.finishSelf(mDreamToken, true /*immediate*/);
+ if (startAndStopDozingInBackground()) {
+ mDreamManager.finishSelfOneway(mDreamToken, true /*immediate*/);
+ } else {
+ mDreamManager.finishSelf(mDreamToken, true /*immediate*/);
+ }
} catch (RemoteException ex) {
// system server died
}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index cf98bfe05faf..620eef66959f 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -50,4 +50,6 @@ interface IDreamManager {
void startDreamActivity(in Intent intent);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)")
oneway void setDreamIsObscured(in boolean isObscured);
+ oneway void startDozingOneway(in IBinder token, int screenState, int reason, int screenBrightness);
+ oneway void finishSelfOneway(in IBinder token, boolean immediate);
}
diff --git a/core/java/android/service/dreams/flags.aconfig b/core/java/android/service/dreams/flags.aconfig
index 54d950c18af8..83e0adfca3be 100644
--- a/core/java/android/service/dreams/flags.aconfig
+++ b/core/java/android/service/dreams/flags.aconfig
@@ -47,3 +47,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "start_and_stop_dozing_in_background"
+ namespace: "systemui"
+ description: "Move the start-dozing and stop-dozing operation to the background"
+ bug: "330287187"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig
index d7389bab8d6d..be60c2504f38 100644
--- a/core/java/android/tracing/flags.aconfig
+++ b/core/java/android/tracing/flags.aconfig
@@ -38,3 +38,11 @@ flag {
is_fixed_read_only: true
bug: "323166383"
}
+
+flag {
+ name: "perfetto_wm_tracing"
+ namespace: "windowing_tools"
+ description: "Migrate WindowManager tracing to Perfetto"
+ is_fixed_read_only: true
+ bug: "323165543"
+}
diff --git a/core/java/android/view/ImeBackAnimationController.java b/core/java/android/view/ImeBackAnimationController.java
index fc1852d739e2..c7e93c19484f 100644
--- a/core/java/android/view/ImeBackAnimationController.java
+++ b/core/java/android/view/ImeBackAnimationController.java
@@ -27,6 +27,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.WindowConfiguration;
import android.graphics.Insets;
import android.util.Log;
import android.view.animation.BackGestureInterpolator;
@@ -137,9 +138,10 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
@Override
public void onBackInvoked() {
if (!isBackAnimationAllowed() || !mIsPreCommitAnimationInProgress) {
- // play regular hide animation if back-animation is not allowed or if insets control has
- // been cancelled by the system (this can happen in split screen for example)
- mInsetsController.hide(ime());
+ // play regular hide animation if predictive back-animation is not allowed or if insets
+ // control has been cancelled by the system. This can happen in multi-window mode for
+ // example (i.e. split-screen or activity-embedding)
+ notifyHideIme();
return;
}
startPostCommitAnim(/*hideIme*/ true);
@@ -209,6 +211,11 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
if (triggerBack) {
mInsetsController.setPredictiveBackImeHideAnimInProgress(true);
notifyHideIme();
+ // requesting IME as invisible during post-commit
+ mInsetsController.setRequestedVisibleTypes(0, ime());
+ // Changes the animation state. This also notifies RootView of changed insets, which
+ // causes it to reset its scrollY to 0f (animated) if it was panned
+ mInsetsController.onAnimationStateChanged(ime(), /*running*/ true);
}
if (mStartRootScrollY != 0 && !triggerBack) {
// This causes RootView to update its scroll back to the panned position
@@ -228,12 +235,6 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
// the IME away
mInsetsController.getHost().getInputMethodManager()
.notifyImeHidden(mInsetsController.getHost().getWindowToken(), statsToken);
-
- // requesting IME as invisible during post-commit
- mInsetsController.setRequestedVisibleTypes(0, ime());
- // Changes the animation state. This also notifies RootView of changed insets, which causes
- // it to reset its scrollY to 0f (animated) if it was panned
- mInsetsController.onAnimationStateChanged(ime(), /*running*/ true);
}
private void reset() {
@@ -254,8 +255,18 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
}
private boolean isBackAnimationAllowed() {
- // back animation is allowed in all cases except when softInputMode is adjust_resize AND
- // there is no app-registered WindowInsetsAnimationCallback AND edge-to-edge is not enabled.
+
+ if (mViewRoot.mContext.getResources().getConfiguration().windowConfiguration
+ .getWindowingMode() == WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW) {
+ // TODO(b/346726115) enable predictive back animation in multi-window mode in
+ // DisplayImeController
+ return false;
+ }
+
+ // otherwise, the predictive back animation is allowed in all cases except when
+ // 1. softInputMode is adjust_resize AND
+ // 2. there is no app-registered WindowInsetsAnimationCallback AND
+ // 3. edge-to-edge is not enabled.
return (mViewRoot.mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
!= SOFT_INPUT_ADJUST_RESIZE
|| (mViewRoot.mView != null && mViewRoot.mView.hasWindowInsetsAnimationCallback())
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 47669427cb9d..766e02bf3198 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13859,6 +13859,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
})
@ResolvedLayoutDir
public int getLayoutDirection() {
+ final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
+ if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
+ return LAYOUT_DIRECTION_RESOLVED_DEFAULT;
+ }
return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ==
PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c0bd535f95f3..1525bd1d4af7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -114,6 +114,7 @@ import static android.view.accessibility.Flags.fixMergedContentChangeEventV2;
import static android.view.accessibility.Flags.forceInvertColor;
import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle;
import static android.view.flags.Flags.addSchandleToVriSurface;
+import static android.view.flags.Flags.disableDrawWakeLock;
import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
import static android.view.flags.Flags.toolkitFrameRateFunctionEnablingReadOnly;
@@ -149,6 +150,8 @@ import android.app.ResourcesManager;
import android.app.WindowConfiguration;
import android.app.compat.CompatChanges;
import android.app.servertransaction.WindowStateTransactionItem;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -337,6 +340,15 @@ public final class ViewRootImpl implements ViewParent,
private static final int LOGTAG_VIEWROOT_DRAW_EVENT = 60004;
/**
+ * This change disables the {@code DRAW_WAKE_LOCK}, an internal wakelock acquired per-frame
+ * duration display DOZE. It was added to allow animation during AOD. This wakelock consumes
+ * battery severely if the animation is too heavy, so, it will be removed.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private static final long DISABLE_DRAW_WAKE_LOCK = 349153669L;
+
+ /**
* Set to false if we do not want to use the multi threaded renderer even though
* threaded renderer (aka hardware renderering) is used. Note that by disabling
* this, WindowCallbacks will not fire.
@@ -2459,6 +2471,11 @@ public final class ViewRootImpl implements ViewParent,
}
void pokeDrawLockIfNeeded() {
+ // Disable DRAW_WAKE_LOCK starting U. Otherwise, only need to acquire it for DOZE state.
+ if (CompatChanges.isChangeEnabled(DISABLE_DRAW_WAKE_LOCK) && disableDrawWakeLock()) {
+ return;
+ }
+
if (!Display.isDozeState(mAttachInfo.mDisplayState)) {
// Only need to acquire wake lock for DOZE state.
return;
@@ -7451,6 +7468,10 @@ public final class ViewRootImpl implements ViewParent,
@Override
protected int onProcess(QueuedInputEvent q) {
+ if (q.forPreImeOnly()) {
+ // this event is intended for the ViewPreImeInputStage only, let's forward
+ return FORWARD;
+ }
if (q.mEvent instanceof KeyEvent) {
final KeyEvent keyEvent = (KeyEvent) q.mEvent;
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 199a69a723d8..5b1c7d54ddb7 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -256,6 +256,21 @@ public class AutofillFeatureFlags {
"ignore_relayout_auth_pending";
/**
+ * Fixes to handle apps relaying out, and causing problems for autofill.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_ENABLE_RELAYOUT = "enable_relayout";
+
+ /**
+ * Enable relative location of views for fingerprinting for relayout.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_ENABLE_RELATIVE_LOCATION_FOR_RELAYOUT =
+ "enable_relative_location_for_relayout";
+
+ /**
* Bugfix flag, Autofill should only fill in value from current session.
*
* See frameworks/base/services/autofill/bugfixes.aconfig#fill_fields_from_current_session_only
@@ -543,6 +558,22 @@ public class AutofillFeatureFlags {
false);
}
+ /** @hide */
+ public static boolean enableRelayoutFixes() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_ENABLE_RELAYOUT,
+ true);
+ }
+
+ /** @hide */
+ public static boolean enableRelativeLocationForRelayout() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_ENABLE_RELATIVE_LOCATION_FOR_RELAYOUT,
+ false);
+ }
+
/** @hide **/
public static boolean shouldFillFieldsFromCurrentSessionOnly() {
return DeviceConfig.getBoolean(
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 0d4c5560837c..515ed0e8f6af 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -748,7 +748,16 @@ public final class AutofillManager {
// Controls logic around apps changing some properties of their views when activity loses
// focus due to autofill showing biometric activity, password manager, or password breach check.
- private boolean mRelayoutFix;
+ // Deprecated. TODO: Remove it after ramp of new solution.
+ private boolean mRelayoutFixDeprecated;
+
+ // Controls logic around apps changing some properties of their views when activity loses
+ // focus due to autofill showing biometric activity, password manager, or password breach check.
+ private final boolean mRelayoutFix;
+
+ // Controls logic around apps changing some properties of their views when activity loses
+ // focus due to autofill showing biometric activity, password manager, or password breach check.
+ private final boolean mRelativePositionForRelayout;
// Indicates whether the credman integration is enabled.
private final boolean mIsCredmanIntegrationEnabled;
@@ -978,11 +987,31 @@ public final class AutofillManager {
mShouldIncludeInvisibleViewInAssistStructure =
AutofillFeatureFlags.shouldIncludeInvisibleViewInAssistStructure();
- mRelayoutFix = AutofillFeatureFlags.shouldIgnoreRelayoutWhenAuthPending();
+ mRelayoutFixDeprecated = AutofillFeatureFlags.shouldIgnoreRelayoutWhenAuthPending();
+ mRelayoutFix = AutofillFeatureFlags.enableRelayoutFixes();
+ mRelativePositionForRelayout = AutofillFeatureFlags.enableRelativeLocationForRelayout();
mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration();
}
/**
+ * Whether to apply relayout fixes.
+ *
+ * @hide
+ */
+ public boolean isRelayoutFixEnabled() {
+ return mRelayoutFix;
+ }
+
+ /**
+ * Whether to use relative positions and locations of the views for disambiguation.
+ *
+ * @hide
+ */
+ public boolean isRelativePositionForRelayoutEnabled() {
+ return mRelativePositionForRelayout;
+ }
+
+ /**
* Whether to apply heuristic check on important views before triggering fill request
*
* @hide
@@ -1779,7 +1808,7 @@ public final class AutofillManager {
}
return;
}
- if (mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION) {
+ if (mRelayoutFixDeprecated && mState == STATE_PENDING_AUTHENTICATION) {
if (sVerbose) {
Log.v(TAG, "notifyViewVisibilityChanged(): ignoring in auth pending mode");
}
@@ -2917,7 +2946,7 @@ public final class AutofillManager {
Intent fillInIntent, boolean authenticateInline) {
synchronized (mLock) {
if (sessionId == mSessionId) {
- if (mRelayoutFix) {
+ if (mRelayoutFixDeprecated) {
mState = STATE_PENDING_AUTHENTICATION;
}
final AutofillClient client = getClient();
@@ -3778,7 +3807,7 @@ public final class AutofillManager {
@GuardedBy("mLock")
private boolean isPendingAuthenticationLocked() {
- return mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION;
+ return mRelayoutFixDeprecated && mState == STATE_PENDING_AUTHENTICATION;
}
@GuardedBy("mLock")
@@ -4322,6 +4351,13 @@ public final class AutofillManager {
addToSet(mInvisibleDialogTrackedIds, id);
}
}
+ } else {
+ if (sDebug) {
+ // isClientVisibleForAutofillLocked() is checking whether
+ // activity has stopped under the hood
+ Log.d(TAG, "notifyViewVisibilityChangedLocked(): ignoring "
+ + "view visibility change since activity has stopped");
+ }
}
if (mIsTrackedSaveView && mVisibleTrackedIds.isEmpty()) {
diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS
index 898947adcd1b..7f3b4e5a21b3 100644
--- a/core/java/android/view/autofill/OWNERS
+++ b/core/java/android/view/autofill/OWNERS
@@ -1,10 +1,11 @@
# Bug component: 351486
-simranjit@google.com
haoranzhang@google.com
+jiewenlei@google.com
+simranjit@google.com
skxu@google.com
+shuc@google.com
yunicorn@google.com
-reemabajwa@google.com
# Bug component: 543785 = per-file *Augmented*
per-file *Augmented* = wangqi@google.com
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 4d4e4afb621c..f570a9a50ebf 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -89,4 +89,12 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "disable_draw_wake_lock"
+ namespace: "wear_frameworks"
+ description: "Disable Draw Wakelock starting U."
+ bug: "331698645"
+ is_fixed_read_only: true
} \ No newline at end of file
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 4fb6e698d592..9b87e2351e3f 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -489,7 +489,8 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
return;
}
OnBackAnimationCallback animationCallback = getBackAnimationCallback();
- if (animationCallback != null) {
+ if (animationCallback != null
+ && !(callback instanceof ImeBackAnimationController)) {
mProgressAnimator.onBackInvoked(callback::onBackInvoked);
} else {
mProgressAnimator.reset();
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 8cd2a3ed124e..68e33c61f71f 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -181,3 +181,14 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "per_user_display_window_settings"
+ description: "Whether to store display window settings per user to avoid conflicts"
+ bug: "346668297"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/protolog/common/ProtoLog.java b/core/java/com/android/internal/protolog/ProtoLog.java
index 8149cd5bbd3b..0118c056d682 100644
--- a/core/java/com/android/internal/protolog/common/ProtoLog.java
+++ b/core/java/com/android/internal/protolog/ProtoLog.java
@@ -14,7 +14,11 @@
* limitations under the License.
*/
-package com.android.internal.protolog.common;
+package com.android.internal.protolog;
+
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogLevel;
/**
* ProtoLog API - exposes static logging methods. Usage of this API is similar
@@ -35,7 +39,9 @@ package com.android.internal.protolog.common;
* Methods in this class are stubs, that are replaced by optimised versions by the ProtoLogTool
* during build.
*/
+// LINT.IfChange
public class ProtoLog {
+// LINT.ThenChange(frameworks/base/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt)
// Needs to be set directly otherwise the protologtool tries to transform the method call
public static boolean REQUIRE_PROTOLOGTOOL = true;
diff --git a/core/res/res/anim/overlay_task_fragment_change.xml b/core/res/res/anim/overlay_task_fragment_change.xml
new file mode 100644
index 000000000000..eb02ba84d6c1
--- /dev/null
+++ b/core/res/res/anim/overlay_task_fragment_change.xml
@@ -0,0 +1,20 @@
+<?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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:showBackdrop="false">
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/overlay_task_fragment_close_to_bottom.xml b/core/res/res/anim/overlay_task_fragment_close_to_bottom.xml
new file mode 100644
index 000000000000..d9487cba3265
--- /dev/null
+++ b/core/res/res/anim/overlay_task_fragment_close_to_bottom.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate
+ android:fromYDelta="0"
+ android:toYDelta="100%"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="517" />
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/overlay_task_fragment_close_to_left.xml b/core/res/res/anim/overlay_task_fragment_close_to_left.xml
new file mode 100644
index 000000000000..3cdb77a307d4
--- /dev/null
+++ b/core/res/res/anim/overlay_task_fragment_close_to_left.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="-100%"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="517" />
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/overlay_task_fragment_close_to_right.xml b/core/res/res/anim/overlay_task_fragment_close_to_right.xml
new file mode 100644
index 000000000000..37645610796e
--- /dev/null
+++ b/core/res/res/anim/overlay_task_fragment_close_to_right.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="100%"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="517" />
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/overlay_task_fragment_close_to_top.xml b/core/res/res/anim/overlay_task_fragment_close_to_top.xml
new file mode 100644
index 000000000000..a8bfbbdd0e78
--- /dev/null
+++ b/core/res/res/anim/overlay_task_fragment_close_to_top.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate
+ android:fromYDelta="0"
+ android:toYDelta="-100%"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="517" />
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/overlay_task_fragment_open_from_bottom.xml b/core/res/res/anim/overlay_task_fragment_open_from_bottom.xml
new file mode 100644
index 000000000000..1d1223f8ead3
--- /dev/null
+++ b/core/res/res/anim/overlay_task_fragment_open_from_bottom.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate
+ android:fromYDelta="100%"
+ android:toYDelta="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="517" />
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/overlay_task_fragment_open_from_left.xml b/core/res/res/anim/overlay_task_fragment_open_from_left.xml
new file mode 100644
index 000000000000..5e5e080c5fee
--- /dev/null
+++ b/core/res/res/anim/overlay_task_fragment_open_from_left.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate
+ android:fromXDelta="-100%"
+ android:toXDelta="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="517" />
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/overlay_task_fragment_open_from_right.xml b/core/res/res/anim/overlay_task_fragment_open_from_right.xml
new file mode 100644
index 000000000000..5674ff3199bc
--- /dev/null
+++ b/core/res/res/anim/overlay_task_fragment_open_from_right.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate
+ android:fromXDelta="100%"
+ android:toXDelta="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="517" />
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/overlay_task_fragment_open_from_top.xml b/core/res/res/anim/overlay_task_fragment_open_from_top.xml
new file mode 100644
index 000000000000..2e3dd0a61031
--- /dev/null
+++ b/core/res/res/anim/overlay_task_fragment_open_from_top.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate
+ android:fromYDelta="-100%"
+ android:toYDelta="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="517" />
+</set> \ No newline at end of file
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index e44c7272bc1e..565d584875ac 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -62,7 +62,7 @@
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
- android:layout_toStartOf="@id/expand_button"
+ android:layout_toStartOf="@id/notification_buttons_column"
android:layout_alignWithParentIfMissing="true"
android:clipChildren="false"
android:gravity="center_vertical"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fa93e763c45b..6b71f97e3f17 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -6508,17 +6508,17 @@ ul.</string>
<!-- Fingerprint dangling notification title -->
<string name="fingerprint_dangling_notification_title">Set up Fingerprint Unlock again</string>
<!-- Fingerprint dangling notification content for only 1 fingerprint deleted -->
- <string name="fingerprint_dangling_notification_msg_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted</string>
+ <string name="fingerprint_dangling_notification_msg_1"><xliff:g id="fingerprint">%s</xliff:g> can no longer be recognized.</string>
<!-- Fingerprint dangling notification content for more than 1 fingerprints deleted -->
- <string name="fingerprint_dangling_notification_msg_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> weren\'t working well and were deleted</string>
+ <string name="fingerprint_dangling_notification_msg_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> can no longer be recognized.</string>
<!-- Fingerprint dangling notification content for only 1 fingerprint deleted and no fingerprint left-->
- <string name="fingerprint_dangling_notification_msg_all_deleted_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with fingerprint.</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1"><xliff:g id="fingerprint">%s</xliff:g> can no longer be recognized. Set up Fingerprint Unlock again.</string>
<!-- Fingerprint dangling notification content for more than 1 fingerprints deleted and no fingerprint left -->
- <string name="fingerprint_dangling_notification_msg_all_deleted_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> weren\'t working well and were deleted. Set them up again to unlock your phone with your fingerprint.</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> can no longer be recognized. Set up Fingerprint Unlock again.</string>
<!-- Face dangling notification title -->
<string name="face_dangling_notification_title">Set up Face Unlock again</string>
<!-- Face dangling notification content -->
- <string name="face_dangling_notification_msg">Your face model wasn\'t working well and was deleted. Set it up again to unlock your phone with face.</string>
+ <string name="face_dangling_notification_msg">Your face model can no longer be recognized. Set up Face Unlock again.</string>
<!-- Biometric dangling notification "set up" action button -->
<string name="biometric_dangling_notification_action_set_up">Set up</string>
<!-- Biometric dangling notification "Not now" action button -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bdcf13c24798..7d50d227ee13 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1753,6 +1753,15 @@
<java-symbol type="anim" name="task_fragment_clear_top_close_exit" />
<java-symbol type="anim" name="task_fragment_clear_top_open_enter" />
<java-symbol type="anim" name="task_fragment_clear_top_open_exit" />
+ <java-symbol type="anim" name="overlay_task_fragment_open_from_left" />
+ <java-symbol type="anim" name="overlay_task_fragment_open_from_top" />
+ <java-symbol type="anim" name="overlay_task_fragment_open_from_right" />
+ <java-symbol type="anim" name="overlay_task_fragment_open_from_bottom" />
+ <java-symbol type="anim" name="overlay_task_fragment_change" />
+ <java-symbol type="anim" name="overlay_task_fragment_close_to_left" />
+ <java-symbol type="anim" name="overlay_task_fragment_close_to_top" />
+ <java-symbol type="anim" name="overlay_task_fragment_close_to_right" />
+ <java-symbol type="anim" name="overlay_task_fragment_close_to_bottom" />
<java-symbol type="array" name="config_autoRotationTiltTolerance" />
<java-symbol type="array" name="config_longPressVibePattern" />
diff --git a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
index 58e5be2b823d..4d9b591c0990 100644
--- a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
+++ b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
@@ -34,6 +34,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
+import android.app.WindowConfiguration;
import android.content.Context;
import android.graphics.Insets;
import android.platform.test.annotations.Presubmit;
@@ -102,6 +103,8 @@ public class ImeBackAnimationControllerTest {
mViewRoot.setOnContentApplyWindowInsetsListener(
mock(Window.OnContentApplyWindowInsetsListener.class));
mBackAnimationController = new ImeBackAnimationController(mViewRoot, mInsetsController);
+ mViewRoot.mContext.getResources().getConfiguration().windowConfiguration
+ .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
when(mWindowInsetsAnimationController.getHiddenStateInsets()).thenReturn(Insets.NONE);
when(mWindowInsetsAnimationController.getShownStateInsets()).thenReturn(IME_INSETS);
@@ -156,8 +159,28 @@ public class ImeBackAnimationControllerTest {
mBackAnimationController.onBackProgressed(new BackEvent(100f, 0f, 0.5f, EDGE_LEFT));
// commit back gesture
mBackAnimationController.onBackInvoked();
- // verify that InsetsController#hide is called
- verify(mInsetsController, times(1)).hide(ime());
+ // verify that InputMethodManager#notifyImeHidden is called (which is the case whenever
+ // getInputMethodManager is called from ImeBackAnimationController)
+ verify(mViewRootInsetsControllerHost, times(1)).getInputMethodManager();
+ // verify that ImeBackAnimationController does not take control over IME insets
+ verify(mInsetsController, never()).controlWindowInsetsAnimation(anyInt(), any(), any(),
+ anyBoolean(), anyLong(), any(), anyInt(), anyBoolean());
+ }
+
+ @Test
+ public void testMultiWindowModeNotPlayingAnim() {
+ // setup ViewRoot with WINDOWING_MODE_MULTI_WINDOW
+ mViewRoot.mContext.getResources().getConfiguration().windowConfiguration.setWindowingMode(
+ WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
+ // start back gesture
+ mBackAnimationController.onBackStarted(new BackEvent(0f, 0f, 0f, EDGE_LEFT));
+ // progress back gesture
+ mBackAnimationController.onBackProgressed(new BackEvent(100f, 0f, 0.5f, EDGE_LEFT));
+ // commit back gesture
+ mBackAnimationController.onBackInvoked();
+ // verify that InputMethodManager#notifyImeHidden is called (which is the case whenever
+ // getInputMethodManager is called from ImeBackAnimationController)
+ verify(mViewRootInsetsControllerHost, times(1)).getInputMethodManager();
// verify that ImeBackAnimationController does not take control over IME insets
verify(mInsetsController, never()).controlWindowInsetsAnimation(anyInt(), any(), any(),
anyBoolean(), anyLong(), any(), anyInt(), anyBoolean());
@@ -277,9 +300,9 @@ public class ImeBackAnimationControllerTest {
// commit back gesture
mBackAnimationController.onBackInvoked();
-
- // verify that InsetsController#hide is called
- verify(mInsetsController, times(1)).hide(ime());
+ // verify that InputMethodManager#notifyImeHidden is called (which is the case whenever
+ // getInputMethodManager is called from ImeBackAnimationController)
+ verify(mViewRootInsetsControllerHost, times(1)).getInputMethodManager();
});
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index d0e49d8c403f..eb1fc23d6b00 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -20,8 +20,10 @@ import static android.content.pm.PackageManager.MATCH_ALL;
import static androidx.window.extensions.embedding.DividerPresenter.getBoundsOffsetForDivider;
import static androidx.window.extensions.embedding.SplitAttributesHelper.isReversedLayout;
+import static androidx.window.extensions.embedding.SplitController.TAG;
import static androidx.window.extensions.embedding.WindowAttributes.DIM_AREA_ON_TASK;
+import android.annotation.AnimRes;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.WindowConfiguration;
@@ -31,9 +33,11 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
+import android.util.Log;
import android.util.Pair;
import android.util.Size;
import android.view.View;
@@ -56,6 +60,7 @@ import androidx.window.extensions.layout.FoldingFeature;
import androidx.window.extensions.layout.WindowLayoutComponentImpl;
import androidx.window.extensions.layout.WindowLayoutInfo;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.window.flags.Flags;
@@ -125,6 +130,16 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
static final int RESULT_EXPAND_FAILED_NO_TF_INFO = 2;
/**
+ * The key of {@link ActivityStack} alignment relative to its parent container.
+ * <p>
+ * See {@link ContainerPosition} for possible values.
+ * <p>
+ * Note that this constants must align with the definition in WM Jetpack library.
+ */
+ private static final String KEY_ACTIVITY_STACK_ALIGNMENT =
+ "androidx.window.embedding.ActivityStackAlignment";
+
+ /**
* Result of {@link #expandSplitContainerIfNeeded(WindowContainerTransaction, SplitContainer,
* Activity, Activity, Intent)}
*/
@@ -649,14 +664,114 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
// TODO(b/243518738): Update to resizeTaskFragment after we migrate WCT#setRelativeBounds
// and WCT#setWindowingMode to take fragmentToken.
resizeTaskFragmentIfRegistered(wct, container, relativeBounds);
- int windowingMode = container.getTaskContainer().getWindowingModeForTaskFragment(
- relativeBounds);
+ final TaskContainer taskContainer = container.getTaskContainer();
+ final int windowingMode = taskContainer.getWindowingModeForTaskFragment(relativeBounds);
updateTaskFragmentWindowingModeIfRegistered(wct, container, windowingMode);
- // Always use default animation for standalone ActivityStack.
- updateAnimationParams(wct, fragmentToken, TaskFragmentAnimationParams.DEFAULT);
+ if (container.isOverlay() && isOverlayTransitionSupported()) {
+ // Use the overlay transition for the overlay container if it's supported.
+ final TaskFragmentAnimationParams params = createOverlayAnimationParams(relativeBounds,
+ taskContainer.getBounds(), container);
+ updateAnimationParams(wct, fragmentToken, params);
+ } else {
+ // Otherwise, fallabck to use the default animation params.
+ updateAnimationParams(wct, fragmentToken, TaskFragmentAnimationParams.DEFAULT);
+ }
setTaskFragmentDimOnTask(wct, fragmentToken, dimOnTask);
}
+ private static boolean isOverlayTransitionSupported() {
+ return Flags.moveAnimationOptionsToChange()
+ && Flags.activityEmbeddingOverlayPresentationFlag();
+ }
+
+ @NonNull
+ private static TaskFragmentAnimationParams createOverlayAnimationParams(
+ @NonNull Rect relativeBounds, @NonNull Rect parentContainerBounds,
+ @NonNull TaskFragmentContainer container) {
+ if (relativeBounds.isEmpty()) {
+ return TaskFragmentAnimationParams.DEFAULT;
+ }
+
+ final int positionFromOptions = container.getLaunchOptions()
+ .getInt(KEY_ACTIVITY_STACK_ALIGNMENT , -1);
+ final int position = positionFromOptions != -1 ? positionFromOptions
+ // Fallback to calculate from bounds if the info can't be retrieved from options.
+ : getOverlayPosition(relativeBounds, parentContainerBounds);
+
+ return new TaskFragmentAnimationParams.Builder()
+ .setOpenAnimationResId(getOpenAnimationResourcesId(position))
+ .setChangeAnimationResId(R.anim.overlay_task_fragment_change)
+ .setCloseAnimationResId(getCloseAnimationResourcesId(position))
+ .build();
+ }
+
+ @VisibleForTesting
+ @ContainerPosition
+ static int getOverlayPosition(
+ @NonNull Rect relativeBounds, @NonNull Rect parentContainerBounds) {
+ final Rect relativeParentBounds = new Rect(parentContainerBounds);
+ relativeParentBounds.offsetTo(0, 0);
+ final int leftMatch = (relativeParentBounds.left == relativeBounds.left) ? 1 : 0;
+ final int topMatch = (relativeParentBounds.top == relativeBounds.top) ? 1 : 0;
+ final int rightMatch = (relativeParentBounds.right == relativeBounds.right) ? 1 : 0;
+ final int bottomMatch = (relativeParentBounds.bottom == relativeBounds.bottom) ? 1 : 0;
+
+ // Flag format: {left|top|right|bottom}. Note that overlay container could be shrunk and
+ // centered, which makes only one of overlay container edge matches the parent container.
+ final int directionFlag = (leftMatch << 3) + (topMatch << 2) + (rightMatch << 1)
+ + bottomMatch;
+
+ final int position = switch (directionFlag) {
+ // Only the left edge match or only the right edge not match: should be on the left of
+ // the parent container.
+ case 0b1000, 0b1101 -> CONTAINER_POSITION_LEFT;
+ // Only the top edge match or only the bottom edge not match: should be on the top of
+ // the parent container.
+ case 0b0100, 0b1110 -> CONTAINER_POSITION_TOP;
+ // Only the right edge match or only the left edge not match: should be on the right of
+ // the parent container.
+ case 0b0010, 0b0111 -> CONTAINER_POSITION_RIGHT;
+ // Only the bottom edge match or only the top edge not match: should be on the bottom of
+ // the parent container.
+ case 0b0001, 0b1011 -> CONTAINER_POSITION_BOTTOM;
+ default -> {
+ Log.w(TAG, "Unsupported position:" + Integer.toBinaryString(directionFlag)
+ + " fallback to treat it as right. Relative parent bounds: "
+ + relativeParentBounds + ", relative overlay bounds:" + relativeBounds);
+ yield CONTAINER_POSITION_RIGHT;
+ }
+ };
+ return position;
+ }
+
+ @AnimRes
+ private static int getOpenAnimationResourcesId(@ContainerPosition int position) {
+ return switch (position) {
+ case CONTAINER_POSITION_LEFT -> R.anim.overlay_task_fragment_open_from_left;
+ case CONTAINER_POSITION_TOP -> R.anim.overlay_task_fragment_open_from_top;
+ case CONTAINER_POSITION_RIGHT -> R.anim.overlay_task_fragment_open_from_right;
+ case CONTAINER_POSITION_BOTTOM -> R.anim.overlay_task_fragment_open_from_bottom;
+ default -> {
+ Log.w(TAG, "Unknown position:" + position);
+ yield Resources.ID_NULL;
+ }
+ };
+ }
+
+ @AnimRes
+ private static int getCloseAnimationResourcesId(@ContainerPosition int position) {
+ return switch (position) {
+ case CONTAINER_POSITION_LEFT -> R.anim.overlay_task_fragment_close_to_left;
+ case CONTAINER_POSITION_TOP -> R.anim.overlay_task_fragment_close_to_top;
+ case CONTAINER_POSITION_RIGHT -> R.anim.overlay_task_fragment_close_to_right;
+ case CONTAINER_POSITION_BOTTOM -> R.anim.overlay_task_fragment_close_to_bottom;
+ default -> {
+ Log.w(TAG, "Unknown position:" + position);
+ yield Resources.ID_NULL;
+ }
+ };
+ }
+
/**
* Returns the expanded bounds if the {@code relBounds} violate minimum dimension or are not
* fully covered by the task bounds. Otherwise, returns {@code relBounds}.
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index 7a0b9a0ece6b..325750243744 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -30,6 +30,11 @@ import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSpli
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitPlaceholderRuleBuilder;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTfContainer;
+import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_BOTTOM;
+import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_LEFT;
+import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT;
+import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_TOP;
+import static androidx.window.extensions.embedding.SplitPresenter.getOverlayPosition;
import static androidx.window.extensions.embedding.SplitPresenter.sanitizeBounds;
import static androidx.window.extensions.embedding.WindowAttributes.DIM_AREA_ON_TASK;
@@ -666,8 +671,8 @@ public class OverlayPresentationTest {
attributes.getRelativeBounds());
verify(mSplitPresenter).updateTaskFragmentWindowingModeIfRegistered(mTransaction, container,
WINDOWING_MODE_MULTI_WINDOW);
- verify(mSplitPresenter).updateAnimationParams(mTransaction, token,
- TaskFragmentAnimationParams.DEFAULT);
+ verify(mSplitPresenter).updateAnimationParams(eq(mTransaction), eq(token),
+ any(TaskFragmentAnimationParams.class));
verify(mSplitPresenter).setTaskFragmentIsolatedNavigation(mTransaction, container, true);
verify(mSplitPresenter, never()).setTaskFragmentPinned(any(),
any(TaskFragmentContainer.class), anyBoolean());
@@ -691,8 +696,8 @@ public class OverlayPresentationTest {
attributes.getRelativeBounds());
verify(mSplitPresenter).updateTaskFragmentWindowingModeIfRegistered(mTransaction,
container, WINDOWING_MODE_MULTI_WINDOW);
- verify(mSplitPresenter).updateAnimationParams(mTransaction, token,
- TaskFragmentAnimationParams.DEFAULT);
+ verify(mSplitPresenter).updateAnimationParams(eq(mTransaction), eq(token),
+ any(TaskFragmentAnimationParams.class));
verify(mSplitPresenter, never()).setTaskFragmentIsolatedNavigation(any(),
any(TaskFragmentContainer.class), anyBoolean());
verify(mSplitPresenter).setTaskFragmentPinned(mTransaction, container, true);
@@ -870,6 +875,59 @@ public class OverlayPresentationTest {
eq(overlayContainer.getTaskFragmentToken()), eq(activityToken));
}
+ // TODO(b/243518738): Rewrite with TestParameter.
+ @Test
+ public void testGetOverlayPosition() {
+ assertWithMessage("It must be position left for left overlay.")
+ .that(getOverlayPosition(new Rect(
+ TASK_BOUNDS.left,
+ TASK_BOUNDS.top,
+ TASK_BOUNDS.right / 2,
+ TASK_BOUNDS.bottom), TASK_BOUNDS)).isEqualTo(CONTAINER_POSITION_LEFT);
+ assertWithMessage("It must be position left for shrunk left overlay.")
+ .that(getOverlayPosition(new Rect(
+ TASK_BOUNDS.left,
+ TASK_BOUNDS.top + 20,
+ TASK_BOUNDS.right / 2,
+ TASK_BOUNDS.bottom - 20), TASK_BOUNDS)).isEqualTo(CONTAINER_POSITION_LEFT);
+ assertWithMessage("It must be position left for top overlay.")
+ .that(getOverlayPosition(new Rect(
+ TASK_BOUNDS.left,
+ TASK_BOUNDS.top,
+ TASK_BOUNDS.right,
+ TASK_BOUNDS.bottom / 2), TASK_BOUNDS)).isEqualTo(CONTAINER_POSITION_TOP);
+ assertWithMessage("It must be position left for shrunk top overlay.")
+ .that(getOverlayPosition(new Rect(
+ TASK_BOUNDS.left + 20,
+ TASK_BOUNDS.top,
+ TASK_BOUNDS.right - 20,
+ TASK_BOUNDS.bottom / 2), TASK_BOUNDS)).isEqualTo(CONTAINER_POSITION_TOP);
+ assertWithMessage("It must be position left for right overlay.")
+ .that(getOverlayPosition(new Rect(
+ TASK_BOUNDS.right / 2,
+ TASK_BOUNDS.top,
+ TASK_BOUNDS.right,
+ TASK_BOUNDS.bottom), TASK_BOUNDS)).isEqualTo(CONTAINER_POSITION_RIGHT);
+ assertWithMessage("It must be position left for shrunk right overlay.")
+ .that(getOverlayPosition(new Rect(
+ TASK_BOUNDS.right / 2,
+ TASK_BOUNDS.top + 20,
+ TASK_BOUNDS.right,
+ TASK_BOUNDS.bottom - 20), TASK_BOUNDS)).isEqualTo(CONTAINER_POSITION_RIGHT);
+ assertWithMessage("It must be position left for bottom overlay.")
+ .that(getOverlayPosition(new Rect(
+ TASK_BOUNDS.left,
+ TASK_BOUNDS.bottom / 2,
+ TASK_BOUNDS.right,
+ TASK_BOUNDS.bottom), TASK_BOUNDS)).isEqualTo(CONTAINER_POSITION_BOTTOM);
+ assertWithMessage("It must be position left for shrunk bottom overlay.")
+ .that(getOverlayPosition(new Rect(
+ TASK_BOUNDS.left + 20,
+ TASK_BOUNDS.bottom / 20,
+ TASK_BOUNDS.right - 20,
+ TASK_BOUNDS.bottom), TASK_BOUNDS)).isEqualTo(CONTAINER_POSITION_BOTTOM);
+ }
+
/**
* A simplified version of {@link SplitController#createOrUpdateOverlayTaskFragmentIfNeeded}
*/
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 25d3067a34bc..1e6824196687 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -88,7 +88,7 @@ genrule {
],
tools: ["protologtool"],
cmd: "$(location protologtool) transform-protolog-calls " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
"--loggroups-jar $(location :wm_shell_protolog-groups) " +
"--viewer-config-file-path /system_ext/etc/wmshell.protolog.pb " +
@@ -107,7 +107,7 @@ genrule {
],
tools: ["protologtool"],
cmd: "$(location protologtool) generate-viewer-config " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
"--loggroups-jar $(location :wm_shell_protolog-groups) " +
"--viewer-config-type json " +
@@ -124,7 +124,7 @@ genrule {
],
tools: ["protologtool"],
cmd: "$(location protologtool) generate-viewer-config " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
"--loggroups-jar $(location :wm_shell_protolog-groups) " +
"--viewer-config-type proto " +
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS b/libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS
new file mode 100644
index 000000000000..dc11241fb76b
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS
@@ -0,0 +1,4 @@
+atsjenk@google.com
+liranb@google.com
+madym@google.com
+mpodolian@google.com \ No newline at end of file
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png
index eb2888199ddf..027b28e7ace7 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png
index eb2888199ddf..027b28e7ace7 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
index 9e1440d5716b..ae60d8bc2596 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
@@ -27,7 +27,7 @@ import android.view.WindowManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.R
import com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT
import com.android.wm.shell.common.bubbles.BubbleBarLocation
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
index 327e2059557c..5e673338bad3 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
@@ -32,7 +32,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.logging.testing.UiEventLoggerFake
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.launcher3.icons.BubbleIconFactory
import com.android.wm.shell.Flags
import com.android.wm.shell.R
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
index ace2c131050c..935d12916f56 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
@@ -27,7 +27,7 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.R
import com.android.wm.shell.bubbles.BubblePositioner
import com.android.wm.shell.bubbles.DeviceConfig
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
index 4876f327a650..92084e403846 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
@@ -16,9 +16,13 @@
package com.android.wm.shell.shared;
+import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES;
+
import android.annotation.NonNull;
import android.content.Context;
import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.Log;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -29,6 +33,8 @@ import com.android.window.flags.Flags;
*/
public class DesktopModeStatus {
+ private static final String TAG = "DesktopModeStatus";
+
/**
* Flag to indicate whether task resizing is veiled.
*/
@@ -98,11 +104,12 @@ public class DesktopModeStatus {
"persist.wm.debug.desktop_max_task_limit", DEFAULT_MAX_TASK_LIMIT);
/**
- * Return {@code true} if desktop windowing is enabled. Only to be used for testing. Callers
- * should use {@link #canEnterDesktopMode(Context)} to query the state of desktop windowing.
+ * Return {@code true} if desktop windowing flag is enabled. Only to be used for testing.
+ * Callers should use {@link #canEnterDesktopMode(Context)} to query the state of desktop
+ * windowing.
*/
@VisibleForTesting
- public static boolean isEnabled() {
+ public static boolean isDesktopModeFlagEnabled() {
return Flags.enableDesktopWindowingMode();
}
@@ -120,7 +127,7 @@ public class DesktopModeStatus {
*/
public static boolean useWindowShadow(boolean isFocusedWindow) {
return USE_WINDOW_SHADOWS
- || (USE_WINDOW_SHADOWS_FOCUSED_WINDOW && isFocusedWindow);
+ || (USE_WINDOW_SHADOWS_FOCUSED_WINDOW && isFocusedWindow);
}
/**
@@ -154,10 +161,36 @@ public class DesktopModeStatus {
}
/**
+ * Return {@code true} if desktop mode dev option should be shown on current device
+ */
+ public static boolean canShowDesktopModeDevOption(@NonNull Context context) {
+ return isDeviceEligibleForDesktopMode(context) && Flags.showDesktopWindowingDevOption();
+ }
+
+ /** Returns if desktop mode dev option should be enabled if there is no user override. */
+ public static boolean shouldDevOptionBeEnabledByDefault() {
+ return isDesktopModeFlagEnabled();
+ }
+
+ /**
* Return {@code true} if desktop mode is enabled and can be entered on the current device.
*/
public static boolean canEnterDesktopMode(@NonNull Context context) {
- return (!enforceDeviceRestrictions() || isDesktopModeSupported(context)) && isEnabled();
+ if (!isDeviceEligibleForDesktopMode(context)) return false;
+
+ // If dev option has ever been manually toggled by the user, return its value
+ // TODO(b/348193756) : Move the logic for DW override based on toggle overides to a common
+ // infrastructure and add caching for the computation
+ int defaultOverrideState = -1;
+ int toggleState = Settings.Global.getInt(context.getContentResolver(),
+ DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, defaultOverrideState);
+ if (toggleState != defaultOverrideState) {
+ Log.d(TAG, "Using Desktop mode dev option overridden state");
+ return toggleState != 0;
+ }
+
+ // Return Desktop windowing flag value
+ return isDesktopModeFlagEnabled();
}
/**
@@ -181,4 +214,11 @@ public class DesktopModeStatus {
return DESKTOP_DENSITY_OVERRIDE >= DESKTOP_DENSITY_MIN
&& DESKTOP_DENSITY_OVERRIDE <= DESKTOP_DENSITY_MAX;
}
+
+ /**
+ * Return {@code true} if desktop mode is unrestricted and is supported in the device.
+ */
+ private static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) {
+ return !enforceDeviceRestrictions() || isDesktopModeSupported(context);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
index ef9bf008b294..514307fed4f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
@@ -19,7 +19,7 @@ package com.android.wm.shell;
import com.android.internal.protolog.LegacyProtoLogImpl;
import com.android.internal.protolog.common.ILogger;
import com.android.internal.protolog.common.IProtoLog;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
index 2e5448a9e8d5..b9bf136837a6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
@@ -29,7 +29,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.sysui.ShellInit;
import java.io.PrintWriter;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
index 5143d419597b..9f01316d5b5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
@@ -38,7 +38,7 @@ import android.window.SystemPerformanceHinter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.sysui.ShellInit;
import java.io.PrintWriter;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 3ded7d246499..ebdea1bba942 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -52,7 +52,7 @@ import android.window.TaskAppearedInfo;
import android.window.TaskOrganizer;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
@@ -124,6 +124,15 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
/**
+ * Limited scope callback to notify when a task is removed from the system. This signal is
+ * not synchronized with anything (or any transition), and should not be used in cases where
+ * that is necessary.
+ */
+ public interface TaskVanishedListener {
+ default void onTaskVanished(RunningTaskInfo taskInfo) {}
+ }
+
+ /**
* Callbacks for events on a task with a locus id.
*/
public interface LocusIdListener {
@@ -167,6 +176,9 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
private final ArraySet<FocusListener> mFocusListeners = new ArraySet<>();
+ // Listeners that should be notified when a task is removed
+ private final ArraySet<TaskVanishedListener> mTaskVanishedListeners = new ArraySet<>();
+
private final Object mLock = new Object();
private StartingWindowController mStartingWindow;
@@ -409,7 +421,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
/**
- * Removes listener.
+ * Removes a locus id listener.
*/
public void removeLocusIdListener(LocusIdListener listener) {
synchronized (mLock) {
@@ -430,7 +442,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
/**
- * Removes listener.
+ * Removes a focus listener.
*/
public void removeFocusListener(FocusListener listener) {
synchronized (mLock) {
@@ -439,6 +451,24 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
/**
+ * Adds a listener to be notified when a task vanishes.
+ */
+ public void addTaskVanishedListener(TaskVanishedListener listener) {
+ synchronized (mLock) {
+ mTaskVanishedListeners.add(listener);
+ }
+ }
+
+ /**
+ * Removes a task-vanished listener.
+ */
+ public void removeTaskVanishedListener(TaskVanishedListener listener) {
+ synchronized (mLock) {
+ mTaskVanishedListeners.remove(listener);
+ }
+ }
+
+ /**
* Returns a surface which can be used to attach overlays to the home root task
*/
@NonNull
@@ -614,6 +644,9 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
t.apply();
ProtoLog.v(WM_SHELL_TASK_ORG, "Removing overlay surface");
}
+ for (TaskVanishedListener l : mTaskVanishedListeners) {
+ l.onTaskVanished(taskInfo);
+ }
if (!ENABLE_SHELL_TRANSITIONS && (appearedInfo.getLeash() != null)) {
// Preemptively clean up the leash only if shell transitions are not enabled
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 5a42817e839b..d270d2b4ccf1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -265,7 +265,7 @@ class ActivityEmbeddingAnimationRunner {
for (TransitionInfo.Change change : openingChanges) {
final Animation animation =
animationProvider.get(info, change, openingWholeScreenBounds);
- if (animation.getDuration() == 0) {
+ if (shouldUseJumpCutForAnimation(animation)) {
continue;
}
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
@@ -290,7 +290,7 @@ class ActivityEmbeddingAnimationRunner {
}
final Animation animation =
animationProvider.get(info, change, closingWholeScreenBounds);
- if (animation.getDuration() == 0) {
+ if (shouldUseJumpCutForAnimation(animation)) {
continue;
}
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
@@ -444,8 +444,16 @@ class ActivityEmbeddingAnimationRunner {
calculateParentBounds(change, boundsAnimationChange, parentBounds);
// There are two animations in the array. The first one is for the start leash
// (snapshot), and the second one is for the end leash (TaskFragment).
- final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change,
- parentBounds);
+ final Animation[] animations =
+ mAnimationSpec.createChangeBoundsChangeAnimations(info, change, parentBounds);
+ // Jump cut if either animation has zero for duration.
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ for (Animation animation : animations) {
+ if (shouldUseJumpCutForAnimation(animation)) {
+ return new ArrayList<>();
+ }
+ }
+ }
// Keep track as we might need to add background color for the animation.
// Although there may be multiple change animation, record one of them is sufficient
// because the background color will be added to the root leash for the whole animation.
@@ -492,12 +500,19 @@ class ActivityEmbeddingAnimationRunner {
// window without bounds change.
animation = ActivityEmbeddingAnimationSpec.createNoopAnimation(change);
} else if (TransitionUtil.isClosingType(change.getMode())) {
- animation = mAnimationSpec.createChangeBoundsCloseAnimation(change, parentBounds);
+ animation =
+ mAnimationSpec.createChangeBoundsCloseAnimation(info, change, parentBounds);
shouldShowBackgroundColor = false;
} else {
- animation = mAnimationSpec.createChangeBoundsOpenAnimation(change, parentBounds);
+ animation =
+ mAnimationSpec.createChangeBoundsOpenAnimation(info, change, parentBounds);
shouldShowBackgroundColor = false;
}
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ if (shouldUseJumpCutForAnimation(animation)) {
+ return new ArrayList<>();
+ }
+ }
adapters.add(new ActivityEmbeddingAnimationAdapter(animation, change,
TransitionUtil.getRootFor(change, info)));
}
@@ -640,6 +655,12 @@ class ActivityEmbeddingAnimationRunner {
return true;
}
+ /** Whether or not to use jump cut based on the animation. */
+ @VisibleForTesting
+ static boolean shouldUseJumpCutForAnimation(@NonNull Animation animation) {
+ return animation.getDuration() == 0;
+ }
+
/** Updates the changes to end states in {@code startTransaction} for jump cut animation. */
private void prepareForJumpCut(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index 8d49614b021b..f49b90d08a75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -46,7 +46,6 @@ import com.android.window.flags.Flags;
import com.android.wm.shell.shared.TransitionUtil;
/** Animation spec for ActivityEmbedding transition. */
-// TODO(b/206557124): provide an easier way to customize animation
class ActivityEmbeddingAnimationSpec {
private static final String TAG = "ActivityEmbeddingAnimSpec";
@@ -95,8 +94,14 @@ class ActivityEmbeddingAnimationSpec {
/** Animation for window that is opening in a change transition. */
@NonNull
- Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo.Change change,
- @NonNull Rect parentBounds) {
+ Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo info,
+ @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ final Animation customAnimation = loadCustomAnimation(info, change);
+ if (customAnimation != null) {
+ return customAnimation;
+ }
+ }
// Use end bounds for opening.
final Rect bounds = change.getEndAbsBounds();
final int startLeft;
@@ -123,8 +128,14 @@ class ActivityEmbeddingAnimationSpec {
/** Animation for window that is closing in a change transition. */
@NonNull
- Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo.Change change,
- @NonNull Rect parentBounds) {
+ Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo info,
+ @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ final Animation customAnimation = loadCustomAnimation(info, change);
+ if (customAnimation != null) {
+ return customAnimation;
+ }
+ }
// Use start bounds for closing.
final Rect bounds = change.getStartAbsBounds();
final int endTop;
@@ -155,8 +166,17 @@ class ActivityEmbeddingAnimationSpec {
* the second one is for the end leash.
*/
@NonNull
- Animation[] createChangeBoundsChangeAnimations(@NonNull TransitionInfo.Change change,
- @NonNull Rect parentBounds) {
+ Animation[] createChangeBoundsChangeAnimations(@NonNull TransitionInfo info,
+ @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ // TODO(b/293658614): Support more complicated animations that may need more than a noop
+ // animation as the start leash.
+ final Animation noopAnimation = createNoopAnimation(change);
+ final Animation customAnimation = loadCustomAnimation(info, change);
+ if (customAnimation != null) {
+ return new Animation[]{noopAnimation, customAnimation};
+ }
+ }
// Both start bounds and end bounds are in screen coordinates. We will post translate
// to the local coordinates in ActivityEmbeddingAnimationAdapter#onAnimationUpdate
final Rect startBounds = change.getStartAbsBounds();
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 7041ea307b0f..ece02711070e 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
@@ -59,7 +59,7 @@ import android.window.IBackAnimationRunner;
import android.window.IOnBackInvokedCallback;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
import com.android.wm.shell.R;
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 c9d3dbdcae05..4f04c5c28412 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
@@ -48,7 +48,7 @@ import com.android.internal.dynamicanimation.animation.SpringForce
import com.android.internal.jank.Cuj
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.policy.SystemBarUtils
-import com.android.internal.protolog.common.ProtoLog
+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
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 381914a58cf2..103a65422504 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
@@ -49,7 +49,7 @@ import android.window.IOnBackInvokedCallback;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.SystemBarUtils;
-import com.android.internal.protolog.common.ProtoLog;
+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.annotations.ShellMainThread;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
index c738ce542f8a..e266e2cd7eea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
@@ -28,7 +28,7 @@ import android.window.BackMotionEvent
import android.window.BackNavigationInfo
import com.android.internal.R
import com.android.internal.policy.TransitionAnimation
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.protolog.ShellProtoLogGroup
import com.android.wm.shell.shared.annotations.ShellMainThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 2aefc64a3ebb..7dbbb04e4406 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -48,7 +48,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
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 c853301519e9..e36f6e6c04c5 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
@@ -84,7 +84,7 @@ import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.CollectionUtils;
import com.android.launcher3.icons.BubbleIconFactory;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 761e02598460..4e6c517b9194 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -35,7 +35,7 @@ import android.view.View;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubbles.DismissReason;
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 c7ccd50af550..f7a5c271a729 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
@@ -67,7 +67,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.protolog.common.ProtoLog;
+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;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index 18e04d14c71b..bf98ef82b475 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -42,7 +42,7 @@ import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ContrastColorUtil;
import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 2382545ab324..0cf187bd9c0f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -29,7 +29,7 @@ import android.view.WindowManager;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.R;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
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 09bec8c37b9a..f93f19d5d1eb 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
@@ -78,7 +78,7 @@ import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
index 0b66bcb6930e..c79d9c4942bf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
@@ -35,7 +35,7 @@ import android.view.ViewGroup;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.taskview.TaskView;
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
index 137568458e3c..9429c9e71b3b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
@@ -29,7 +29,7 @@ import android.view.InputMonitor;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
index b7107f09b17f..d4f53ab353ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
@@ -28,7 +28,7 @@ import android.view.ViewConfiguration;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* Handles {@link MotionEvent}s for bubbles that begin in the nav bar area
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 aa4129a14dbc..fbef6b5e4a99 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
@@ -38,7 +38,7 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.internal.protolog.common.ProtoLog;
+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;
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 e261d92bda5c..f7923924789e 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
@@ -28,7 +28,7 @@ import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.transition.LegacyTransitions;
import java.util.ArrayList;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
index 43c92cab6a68..43f9cb984322 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
@@ -32,7 +32,7 @@ import android.util.ArraySet;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java
index 58007b50350b..8e026f04ac31 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java
@@ -27,7 +27,7 @@ import android.util.DisplayMetrics;
import android.util.Size;
import android.view.Gravity;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
index 7ceaaea3962f..64a1b0c804da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
@@ -32,7 +32,7 @@ import android.util.ArraySet;
import android.util.Size;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipPerfHintController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipPerfHintController.java
index c421dec025f2..b9c698e5d8b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipPerfHintController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipPerfHintController.java
@@ -26,7 +26,7 @@ import android.window.SystemPerformanceHinter.HighPerfSession;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.shared.annotations.ShellMainThread;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
index 3e9366fd6459..dcf84d927ad3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
@@ -30,7 +30,7 @@ import android.util.Log
import android.util.Pair
import android.util.TypedValue
import android.window.TaskSnapshot
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.Flags
import com.android.wm.shell.protolog.ShellProtoLogGroup
import kotlin.math.abs
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 2234041b8c9d..3ad60e7031e5 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
@@ -54,7 +54,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+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;
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 8ced76fd23af..d3c349f9c866 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
@@ -59,7 +59,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+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;
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 43cdcca19c3d..4ea41d5256f9 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
@@ -646,6 +646,7 @@ public abstract class WMShellModule {
ShellInit shellInit,
ShellController shellController,
ShellCommandHandler shellCommandHandler,
+ ShellTaskOrganizer shellTaskOrganizer,
DisplayController displayController,
UiEventLogger uiEventLogger,
IconProvider iconProvider,
@@ -653,8 +654,8 @@ public abstract class WMShellModule {
Transitions transitions,
@ShellMainThread ShellExecutor mainExecutor) {
return new DragAndDropController(context, shellInit, shellController, shellCommandHandler,
- displayController, uiEventLogger, iconProvider, globalDragListener, transitions,
- mainExecutor);
+ shellTaskOrganizer, displayController, uiEventLogger, iconProvider,
+ globalDragListener, transitions, mainExecutor);
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index e71056043d5c..a67dee3a4a8d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -35,7 +35,7 @@ import androidx.core.util.plus
import androidx.core.util.putAll
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceIdSequence
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
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 c374eb8e8f03..b3c3a3dcf272 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
@@ -59,9 +59,10 @@ import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
@@ -85,6 +86,7 @@ import java.util.function.Function;
public class DragAndDropController implements RemoteCallable<DragAndDropController>,
GlobalDragListener.GlobalDragListenerCallback,
DisplayController.OnDisplaysChangedListener,
+ ShellTaskOrganizer.TaskVanishedListener,
View.OnDragListener, ComponentCallbacks2 {
private static final String TAG = DragAndDropController.class.getSimpleName();
@@ -92,6 +94,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
private final Context mContext;
private final ShellController mShellController;
private final ShellCommandHandler mShellCommandHandler;
+ private final ShellTaskOrganizer mShellTaskOrganizer;
private final DisplayController mDisplayController;
private final DragAndDropEventLogger mLogger;
private final IconProvider mIconProvider;
@@ -133,6 +136,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
ShellInit shellInit,
ShellController shellController,
ShellCommandHandler shellCommandHandler,
+ ShellTaskOrganizer shellTaskOrganizer,
DisplayController displayController,
UiEventLogger uiEventLogger,
IconProvider iconProvider,
@@ -142,6 +146,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
mContext = context;
mShellController = shellController;
mShellCommandHandler = shellCommandHandler;
+ mShellTaskOrganizer = shellTaskOrganizer;
mDisplayController = displayController;
mLogger = new DragAndDropEventLogger(uiEventLogger);
mIconProvider = iconProvider;
@@ -163,6 +168,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
}, 0);
mShellController.addExternalInterface(KEY_EXTRA_SHELL_DRAG_AND_DROP,
this::createExternalInterface, this);
+ mShellTaskOrganizer.addTaskVanishedListener(this);
mShellCommandHandler.addDumpCallback(this::dump, this);
mGlobalDragListener.setListener(this);
}
@@ -281,6 +287,34 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
}
@Override
+ public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ if (taskInfo.baseIntent == null) {
+ // Invalid info
+ return;
+ }
+ // Find the active drag
+ PerDisplay pd = null;
+ for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+ final PerDisplay iPd = mDisplayDropTargets.valueAt(i);
+ if (iPd.isHandlingDrag) {
+ pd = iPd;
+ break;
+ }
+ }
+ if (pd == null || !pd.isHandlingDrag) {
+ // Not currently dragging
+ return;
+ }
+
+ // Update the drag session
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
+ "Handling vanished task: id=%d component=%s", taskInfo.taskId,
+ taskInfo.baseIntent.getComponent());
+ pd.dragSession.updateRunningTask();
+ pd.dragLayout.updateSession(pd.dragSession);
+ }
+
+ @Override
public boolean onDrag(View target, DragEvent event) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
"Drag event: action=%s x=%f y=%f xOffset=%f yOffset=%f",
@@ -313,11 +347,10 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
Slog.w(TAG, "Unexpected drag start during an active drag");
return false;
}
- // TODO(b/290391688): Also update the session data with task stack changes
pd.dragSession = new DragSession(ActivityTaskManager.getInstance(),
mDisplayController.getDisplayLayout(displayId), event.getClipData(),
event.getDragFlags());
- pd.dragSession.update();
+ pd.dragSession.initialize();
pd.activeDragCount++;
pd.dragLayout.prepare(pd.dragSession, mLogger.logStart(pd.dragSession));
setDropTargetWindowVisibility(pd, View.VISIBLE);
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 a42ca1905ee7..9c7476d1a1b0 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
@@ -66,7 +66,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+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;
@@ -84,7 +84,10 @@ public class DragAndDropPolicy {
private static final String TAG = DragAndDropPolicy.class.getSimpleName();
private final Context mContext;
- private final Starter mStarter;
+ // Used only for launching a fullscreen task (or as a fallback if there is no split starter)
+ private final Starter mFullscreenStarter;
+ // Used for launching tasks into splitscreen
+ private final Starter mSplitscreenStarter;
private final SplitScreenController mSplitScreen;
private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
private final RectF mDisallowHitRegion = new RectF();
@@ -97,10 +100,12 @@ public class DragAndDropPolicy {
}
@VisibleForTesting
- DragAndDropPolicy(Context context, SplitScreenController splitScreen, Starter starter) {
+ DragAndDropPolicy(Context context, SplitScreenController splitScreen,
+ Starter fullscreenStarter) {
mContext = context;
mSplitScreen = splitScreen;
- mStarter = mSplitScreen != null ? mSplitScreen : starter;
+ mFullscreenStarter = fullscreenStarter;
+ mSplitscreenStarter = splitScreen;
}
/**
@@ -245,17 +250,20 @@ public class DragAndDropPolicy {
mSplitScreen.onDroppedToSplit(position, mLoggerSessionId);
}
+ final Starter starter = target.type == TYPE_FULLSCREEN
+ ? mFullscreenStarter
+ : mSplitscreenStarter;
if (mSession.appData != null) {
- launchApp(mSession, position);
+ launchApp(mSession, starter, position);
} else {
- launchIntent(mSession, position);
+ launchIntent(mSession, starter, position);
}
}
/**
* Launches an app provided by SysUI.
*/
- private void launchApp(DragSession session, @SplitPosition int position) {
+ private void launchApp(DragSession session, Starter starter, @SplitPosition int position) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching app data at position=%d",
position);
final ClipDescription description = session.getClipDescription();
@@ -275,11 +283,11 @@ public class DragAndDropPolicy {
if (isTask) {
final int taskId = session.appData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
- mStarter.startTask(taskId, position, opts);
+ starter.startTask(taskId, position, opts);
} else if (isShortcut) {
final String packageName = session.appData.getStringExtra(EXTRA_PACKAGE_NAME);
final String id = session.appData.getStringExtra(EXTRA_SHORTCUT_ID);
- mStarter.startShortcut(packageName, id, position, opts, user);
+ starter.startShortcut(packageName, id, position, opts, user);
} else {
final PendingIntent launchIntent =
session.appData.getParcelableExtra(EXTRA_PENDING_INTENT);
@@ -288,7 +296,7 @@ public class DragAndDropPolicy {
Log.e(TAG, "Expected app intent's EXTRA_USER to match pending intent user");
}
}
- mStarter.startIntent(launchIntent, user.getIdentifier(), null /* fillIntent */,
+ starter.startIntent(launchIntent, user.getIdentifier(), null /* fillIntent */,
position, opts);
}
}
@@ -296,7 +304,7 @@ public class DragAndDropPolicy {
/**
* Launches an intent sender provided by an application.
*/
- private void launchIntent(DragSession session, @SplitPosition int position) {
+ private void launchIntent(DragSession session, Starter starter, @SplitPosition int position) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching intent at position=%d",
position);
final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic();
@@ -309,7 +317,7 @@ public class DragAndDropPolicy {
| FLAG_ACTIVITY_MULTIPLE_TASK);
final Bundle opts = baseActivityOpts.toBundle();
- mStarter.startIntent(session.launchableIntent,
+ starter.startIntent(session.launchableIntent,
session.launchableIntent.getCreatorUserHandle().getIdentifier(),
null /* fillIntent */, position, opts);
}
@@ -420,7 +428,7 @@ public class DragAndDropPolicy {
@Override
public String toString() {
- return "Target {hit=" + hitRegion + " draw=" + drawRegion + "}";
+ return "Target {type=" + type + " hit=" + hitRegion + " draw=" + drawRegion + "}";
}
}
}
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 4bb10dfdf8c6..910175ef3023 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
@@ -20,7 +20,6 @@ import static android.app.StatusBarManager.DISABLE_NONE;
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.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -42,6 +41,7 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
@@ -55,7 +55,7 @@ import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+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;
@@ -102,6 +102,8 @@ public class DragLayout extends LinearLayout
private boolean mIsShowing;
private boolean mHasDropped;
private DragSession mSession;
+ // The last position that was handled by the drag layout
+ private final Point mLastPosition = new Point();
@SuppressLint("WrongConstant")
public DragLayout(Context context, SplitScreenController splitScreenController,
@@ -265,6 +267,15 @@ public class DragLayout extends LinearLayout
*/
public void prepare(DragSession session, InstanceId loggerSessionId) {
mPolicy.start(session, loggerSessionId);
+ updateSession(session);
+ }
+
+ /**
+ * Updates the drag layout based on the diven drag session.
+ */
+ public void updateSession(DragSession session) {
+ // Note: The policy currently just keeps a reference to the session
+ boolean updatingExistingSession = mSession != null;
mSession = session;
mHasDropped = false;
mCurrentTarget = null;
@@ -312,6 +323,11 @@ public class DragLayout extends LinearLayout
updateDropZoneSizes(topOrLeftBounds, bottomOrRightBounds);
}
requestLayout();
+ if (updatingExistingSession) {
+ // Update targets if we are already currently dragging
+ recomputeDropTargets();
+ update(mLastPosition.x, mLastPosition.y);
+ }
}
private void updateDropZoneSizesForSingleTask() {
@@ -359,6 +375,9 @@ public class DragLayout extends LinearLayout
mDropZoneView2.setLayoutParams(dropZoneView2);
}
+ /**
+ * Shows the drag layout.
+ */
public void show() {
mIsShowing = true;
recomputeDropTargets();
@@ -384,13 +403,19 @@ public class DragLayout extends LinearLayout
* Updates the visible drop target as the user drags.
*/
public void update(DragEvent event) {
+ update((int) event.getX(), (int) event.getY());
+ }
+
+ /**
+ * Updates the visible drop target as the user drags to the given coordinates.
+ */
+ private void update(int x, int y) {
if (mHasDropped) {
return;
}
// Find containing region, if the same as mCurrentRegion, then skip, otherwise, animate the
// visibility of the current region
- DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(
- (int) event.getX(), (int) event.getY());
+ DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(x, y);
if (mCurrentTarget != target) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
if (target == null) {
@@ -429,6 +454,7 @@ public class DragLayout extends LinearLayout
}
mCurrentTarget = target;
}
+ mLastPosition.set(x, y);
}
/**
@@ -436,6 +462,7 @@ public class DragLayout extends LinearLayout
*/
public void hide(DragEvent event, Runnable hideCompleteCallback) {
mIsShowing = false;
+ mLastPosition.set(-1, -1);
animateSplitContainers(false, () -> {
if (hideCompleteCallback != null) {
hideCompleteCallback.run();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
index 0addd432aff0..3bedef21184e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
@@ -30,7 +30,9 @@ import android.content.pm.ActivityInfo;
import androidx.annotation.Nullable;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.List;
@@ -79,17 +81,27 @@ public class DragSession {
}
/**
- * Updates the session data based on the current state of the system.
+ * Updates the running task for this drag session.
*/
- void update() {
- List<ActivityManager.RunningTaskInfo> tasks =
+ void updateRunningTask() {
+ final List<ActivityManager.RunningTaskInfo> tasks =
mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
if (!tasks.isEmpty()) {
final ActivityManager.RunningTaskInfo task = tasks.get(0);
runningTaskInfo = task;
runningTaskWinMode = task.getWindowingMode();
runningTaskActType = task.getActivityType();
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
+ "Running task: id=%d component=%s", task.taskId,
+ task.baseIntent != null ? task.baseIntent.getComponent() : "null");
}
+ }
+
+ /**
+ * Updates the session data based on the current state of the system at the start of the drag.
+ */
+ void initialize() {
+ updateRunningTask();
activityInfo = mInitialDragData.getItemAt(0).getActivityInfo();
// TODO: This should technically check & respect config_supportsNonResizableMultiWindow
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 724a130ef52d..b6b49a87484e 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
@@ -19,6 +19,7 @@ package com.android.wm.shell.draganddrop;
import static com.android.wm.shell.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;
@@ -37,13 +38,16 @@ import android.widget.ImageView;
import androidx.annotation.Nullable;
import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
/**
* Renders a drop zone area for items being dragged.
*/
public class DropZoneView extends FrameLayout {
+ private static final boolean DEBUG_LAYOUT = false;
private static final float SPLASHSCREEN_ALPHA = 0.90f;
private static final float HIGHLIGHT_ALPHA = 1f;
private static final int MARGIN_ANIMATION_ENTER_DURATION = 400;
@@ -77,6 +81,7 @@ public class DropZoneView extends FrameLayout {
private int mHighlightColor;
private ObjectAnimator mBackgroundAnimator;
+ private int mTargetBackgroundColor;
private ObjectAnimator mMarginAnimator;
private float mMarginPercent;
@@ -181,6 +186,9 @@ public class DropZoneView extends FrameLayout {
/** Animates between highlight and splashscreen depending on current state. */
public void animateSwitch() {
+ if (DEBUG_LAYOUT) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "animateSwitch");
+ }
mShowingHighlight = !mShowingHighlight;
mShowingSplash = !mShowingHighlight;
final int newColor = mShowingHighlight ? mHighlightColor : mSplashScreenColor;
@@ -190,6 +198,10 @@ public class DropZoneView extends FrameLayout {
/** Animates the highlight indicating the zone is hovered on or not. */
public void setShowingHighlight(boolean showingHighlight) {
+ if (DEBUG_LAYOUT) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "setShowingHighlight: showing=%b",
+ showingHighlight);
+ }
mShowingHighlight = showingHighlight;
mShowingSplash = !mShowingHighlight;
final int newColor = mShowingHighlight ? mHighlightColor : mSplashScreenColor;
@@ -199,6 +211,10 @@ public class DropZoneView extends FrameLayout {
/** Animates the margins around the drop zone to show or hide. */
public void setShowingMargin(boolean visible) {
+ if (DEBUG_LAYOUT) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "setShowingMargin: visible=%b",
+ visible);
+ }
if (mShowingMargin != visible) {
mShowingMargin = visible;
animateMarginToState();
@@ -212,6 +228,15 @@ public class DropZoneView extends FrameLayout {
}
private void animateBackground(int startColor, int endColor) {
+ if (DEBUG_LAYOUT) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
+ "animateBackground: start=%s end=%s",
+ Integer.toHexString(startColor), Integer.toHexString(endColor));
+ }
+ if (endColor == mTargetBackgroundColor) {
+ // Already at, or animating to, that background color
+ return;
+ }
if (mBackgroundAnimator != null) {
mBackgroundAnimator.cancel();
}
@@ -223,6 +248,7 @@ public class DropZoneView extends FrameLayout {
mBackgroundAnimator.setInterpolator(FAST_OUT_SLOW_IN);
}
mBackgroundAnimator.start();
+ mTargetBackgroundColor = endColor;
}
private void animateSplashScreenIcon() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/GlobalDragListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/GlobalDragListener.kt
index 31214eba8dd0..ffcfe6447e2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/GlobalDragListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/GlobalDragListener.kt
@@ -25,7 +25,7 @@ import android.view.IWindowManager
import android.window.IGlobalDragListener
import android.window.IUnhandledDragCallback
import androidx.annotation.VisibleForTesting
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.protolog.ShellProtoLogGroup
import java.util.function.Consumer
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 b48aee5ccd5e..1641668a98a1 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
@@ -25,7 +25,7 @@ import android.content.Context;
import android.util.SparseArray;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index 2626e7380163..d2ceb67030fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -27,7 +27,7 @@ import android.view.SurfaceControl;
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index cd478e5bd567..333c75f92ffc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -49,7 +49,7 @@ import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
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 0a3c15b6057f..dc449d1aaf74 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
@@ -37,7 +37,7 @@ import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.internal.protolog.common.ProtoLog;
+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;
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 3fae37014fba..789f7068c0a9 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
@@ -73,7 +73,7 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+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;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index f3a8fbf85754..e5633de2a3a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -63,7 +63,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index a7c47f92eb14..ccbe94c4c780 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -41,7 +41,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 0169e8c40f45..c7369a3cd347 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -32,7 +32,7 @@ import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.pip.PipBoundsState;
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 448d4f527d16..d1d82755d12c 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
@@ -59,7 +59,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
index f6cab485fa2a..d1978c30eecb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -28,7 +28,7 @@ import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputEvent;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
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 15342be0e8b7..c18964240f98 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
@@ -59,7 +59,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-import com.android.internal.protolog.common.ProtoLog;
+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;
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 f5bd006b4621..df3803d54d9d 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
@@ -34,7 +34,7 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.common.FloatingContentCoordinator;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index d8ac8e948a97..9c4e723efc23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -48,7 +48,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
index 5d858fa9aa3f..cb82db630715 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
@@ -23,7 +23,7 @@ import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
index 6b890c49b713..50d22ad00b11 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
@@ -33,7 +33,7 @@ import android.app.RemoteAction;
import android.content.Context;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.common.pip.PipUtils;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java
index 0221db836dda..eb7a10cc9dfb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java
@@ -28,7 +28,7 @@ import android.widget.FrameLayout;
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index 72c0cd71f198..188c35ff3562 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -33,7 +33,7 @@ import android.view.Gravity;
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
index 8a215b4b2e25..1afb470c5e9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
@@ -26,7 +26,7 @@ import android.graphics.Rect;
import android.os.Handler;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index b6a7c56527bd..0ed5079b7fba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -39,7 +39,7 @@ import android.view.Gravity;
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
index 977aad4a898a..327ceef00e6a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
@@ -27,7 +27,7 @@ import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.TvWindowMenuActionButton;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 6b5bdd2299e1..e74870d4d139 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -37,7 +37,7 @@ import android.window.SurfaceSyncGroup;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+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.pip.PipMenuController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java
index adc03cf5c4d7..eabf1b0b3063 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java
@@ -39,7 +39,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import java.util.Arrays;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index 4a767ef2a113..c7704f0b4eed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -50,7 +50,7 @@ import android.widget.ImageView;
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.widget.LinearLayoutManager;
import com.android.internal.widget.RecyclerView;
import com.android.wm.shell.R;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
index 54e162bba2f3..ce5079227b61 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
@@ -33,7 +33,7 @@ import android.os.Bundle;
import android.text.TextUtils;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ImageUtils;
import com.android.wm.shell.R;
import com.android.wm.shell.common.pip.PipMediaController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
index ca0d61f8fc9b..7a0e6694cb51 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
@@ -62,7 +62,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
index 6e36a32ac931..9cfe1620a2ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
@@ -32,7 +32,7 @@ import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.pip.PipBoundsState;
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 fc0d36d13b2e..68202ef642c4 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
@@ -36,7 +36,7 @@ import androidx.annotation.BinderThread;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.Preconditions;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java
index b757b00f16dd..ffda56d89276 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java
@@ -28,7 +28,7 @@ import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputEvent;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
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 42b8e9f5a3ad..c54e4cd90f57 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
@@ -59,7 +59,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-import com.android.internal.protolog.common.ProtoLog;
+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;
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 495cd0075494..cec246923e2c 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
@@ -35,7 +35,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.common.FloatingContentCoordinator;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 9c1e321a1273..4f62192eaf5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -33,7 +33,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipUtils;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index 56a465a4889a..a9f3b54006d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -51,7 +51,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchState.java
index d093f1e5ccc1..bb8d4ee9c80f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchState.java
@@ -23,7 +23,7 @@ import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
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 ad298dcc253e..814eaae1ea74 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
@@ -43,7 +43,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
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 c67cf1d85918..e46625debcc6 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
@@ -63,7 +63,7 @@ import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index 64e26dbd70be..1cbb8bbe5f75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -23,7 +23,7 @@ import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index f5fbae55960a..27fd309c09b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -24,7 +24,7 @@ import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
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 dd219d32bbaa..b4941a5b49b5 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
@@ -73,7 +73,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
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 0541a0287179..b3dab8527617 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
@@ -46,7 +46,7 @@ import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+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;
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 45eff4a24898..d9e97766e4fe 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
@@ -119,7 +119,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
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 0f3d6cade95a..1076eca60369 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
@@ -45,7 +45,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
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 1d8a8d506c5c..e0f63940663a 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
@@ -36,7 +36,7 @@ import android.view.LayoutInflater;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import com.android.internal.protolog.common.ProtoLog;
+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;
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 2b12a22f907d..90eb22f369df 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
@@ -74,7 +74,7 @@ import com.android.internal.graphics.palette.Palette;
import com.android.internal.graphics.palette.Quantizer;
import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
import com.android.internal.policy.PhoneWindow;
-import com.android.internal.protolog.common.ProtoLog;
+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;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
index e552e6cdacf3..08211ab5df9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
@@ -53,7 +53,7 @@ import android.window.SplashScreenView;
import android.window.StartingWindowInfo;
import android.window.StartingWindowRemovalInfo;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ContrastColorUtil;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
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 3353c7bd81c2..97a695f34cf7 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
@@ -43,7 +43,7 @@ import android.window.StartingWindowRemovalInfo;
import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+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;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 8fc54edcbd4b..6e084d6e05a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -48,7 +48,7 @@ import android.window.SnapshotDrawerUtils;
import android.window.StartingWindowInfo;
import android.window.TaskSnapshot;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.view.BaseIWindow;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
index 72fc8686f648..2036d9c13f0c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
@@ -35,7 +35,7 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_WINDOWLESS;
import android.window.StartingWindowInfo;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java
index 2e6ddc363906..aa9f15c37531 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java
@@ -18,7 +18,7 @@ package com.android.wm.shell.sysui;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_INIT;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
import java.util.Arrays;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
index 5ced1fb41a41..0202b6cf3eab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
@@ -40,7 +40,7 @@ import android.view.SurfaceControlRegistry;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
import com.android.wm.shell.common.ExternalInterfaceBinder;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
index 2e2f569a52b8..3a680097554f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
@@ -25,7 +25,7 @@ import android.view.SurfaceControl;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import java.util.ArrayList;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 8ee1efa90a30..4f4b8097cfac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -39,7 +39,7 @@ import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.activityembedding.ActivityEmbeddingController;
import com.android.wm.shell.common.split.SplitScreenUtils;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
index c33fb80fdefc..c8921d256d7f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
@@ -28,7 +28,7 @@ import android.os.IBinder;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.activityembedding.ActivityEmbeddingController;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
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 9db153f2a5c5..73b32a24246a 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
@@ -103,7 +103,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.common.DisplayController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
index 89b0e25b306b..978b8da2eb6d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
@@ -28,7 +28,7 @@ import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.IWindowContainerTransactionCallback;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* Utilities and interfaces for transition-like usage on top of the legacy app-transition and
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 e8b01b5880fb..8cc7f212af25 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
@@ -35,7 +35,7 @@ import android.annotation.Nullable;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -184,7 +184,8 @@ public class MixedTransitionHelper {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
TransitionInfo.Change change = info.getChanges().get(i);
- if (change == pipChange || !isOpeningMode(change.getMode())) {
+ if (change == pipChange || !isOpeningMode(change.getMode()) ||
+ change.getTaskInfo() == null) {
// Ignore the change/task that's going into Pip or not opening
continue;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 69c41675e989..c5dc668582bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -30,7 +30,7 @@ import android.window.TransitionRequestInfo;
import android.window.WindowAnimationState;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
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 9fc6702562bb..391c5fe3473c 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
@@ -30,7 +30,7 @@ import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index d6860464d055..6013a1ea1d9d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -39,7 +39,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.BinderThread;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.TransitionUtil;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index 2047b5a88604..a5f071af6973 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -54,7 +54,7 @@ import android.window.TransitionInfo;
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.TransitionUtil;
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 f6e38dac859c..ec6802da85f6 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
@@ -75,7 +75,7 @@ import androidx.annotation.BinderThread;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
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 7c2ba455c0c9..88bfebf9331e 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
@@ -33,7 +33,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.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/util/KtProtoLog.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
index 564e716c7378..ee6c81a3fa04 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
@@ -18,10 +18,10 @@ package com.android.wm.shell.util
import android.util.Log
import com.android.internal.protolog.common.IProtoLogGroup
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
/**
- * Log messages using an API similar to [com.android.internal.protolog.common.ProtoLog]. Useful for
+ * Log messages using an API similar to [com.android.internal.protolog.ProtoLog]. Useful for
* logging from Kotlin classes as ProtoLog does not have support for Kotlin.
*
* All messages are logged to logcat if logging is enabled for that [IProtoLogGroup].
@@ -29,42 +29,42 @@ import com.android.internal.protolog.common.ProtoLog
// TODO(b/168581922): remove once ProtoLog adds support for Kotlin
class KtProtoLog {
companion object {
- /** @see [com.android.internal.protolog.common.ProtoLog.d] */
+ /** @see [com.android.internal.protolog.ProtoLog.d] */
fun d(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.d(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.v] */
+ /** @see [com.android.internal.protolog.ProtoLog.v] */
fun v(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.v(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.i] */
+ /** @see [com.android.internal.protolog.ProtoLog.i] */
fun i(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.i(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.w] */
+ /** @see [com.android.internal.protolog.ProtoLog.w] */
fun w(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.w(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.e] */
+ /** @see [com.android.internal.protolog.ProtoLog.e] */
fun e(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.e(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.wtf] */
+ /** @see [com.android.internal.protolog.ProtoLog.wtf] */
fun wtf(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.wtf(group.tag, String.format(messageString, *args))
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS
new file mode 100644
index 000000000000..482aaab6bc74
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS
@@ -0,0 +1 @@
+per-file KtProtolog.kt = file:platform/development:/tools/winscope/OWNERS
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 180e4f999726..a05dbf844db0 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
@@ -73,7 +73,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.Cuj;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index d902444d4b15..a3616f65f3b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -55,7 +55,7 @@ import android.view.ViewConfiguration;
import android.view.WindowManagerGlobal;
import android.window.InputTransferToken;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index f9b4108bc8c2..8303317d39fc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -687,6 +687,25 @@ public class ShellTaskOrganizerTests extends ShellTestCase {
verify(mRecentTasksController).onTaskRunningInfoChanged(task2);
}
+ @Test
+ public void testTaskVanishedCallback() {
+ RunningTaskInfo task1 = createTaskInfo(/* taskId= */ 1, WINDOWING_MODE_FULLSCREEN);
+ mOrganizer.onTaskAppeared(task1, /* leash= */ null);
+
+ RunningTaskInfo[] vanishedTasks = new RunningTaskInfo[1];
+ ShellTaskOrganizer.TaskVanishedListener listener =
+ new ShellTaskOrganizer.TaskVanishedListener() {
+ @Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ vanishedTasks[0] = taskInfo;
+ }
+ };
+ mOrganizer.addTaskVanishedListener(listener);
+ mOrganizer.onTaskVanished(task1);
+
+ assertEquals(vanishedTasks[0], task1);
+ }
+
private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
index 51a20ee9d090..a2df22c5468f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
@@ -26,7 +26,7 @@ import android.testing.TestableContext;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import org.junit.After;
import org.junit.Before;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
index 731f75bf9f5d..55b6bd278f20 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
@@ -21,10 +21,12 @@ import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationRunner.calculateParentBounds;
+import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationRunner.shouldUseJumpCutForAnimation;
import static com.android.wm.shell.transition.Transitions.TRANSIT_TASK_FRAGMENT_DRAG_RESIZE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@@ -40,6 +42,8 @@ import android.graphics.Rect;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
import android.window.TransitionInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -281,6 +285,18 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim
actualParentBounds);
}
+ @Test
+ public void testShouldUseJumpCutForAnimation() {
+ final Animation noopAnimation = new AlphaAnimation(0f, 1f);
+ assertTrue("Animation without duration should use jump cut.",
+ shouldUseJumpCutForAnimation(noopAnimation));
+
+ final Animation alphaAnimation = new AlphaAnimation(0f, 1f);
+ alphaAnimation.setDuration(100);
+ assertFalse("Animation with duration should not use jump cut.",
+ shouldUseJumpCutForAnimation(alphaAnimation));
+ }
+
@NonNull
private static TransitionInfo.Change prepareChangeForParentBoundsCalculationTest(
@NonNull Point endRelOffset, @NonNull Rect endAbsBounds, @NonNull Point endParentSize) {
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 0e53e10cde08..5f36e9a5e7b3 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
@@ -193,7 +193,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
.strictness(Strictness.LENIENT)
.spyStatic(DesktopModeStatus::class.java)
.startMocking()
- whenever(DesktopModeStatus.isEnabled()).thenReturn(true)
+ whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(true)
doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
shellInit = spy(ShellInit(testExecutor))
@@ -264,7 +264,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Test
fun instantiate_flagOff_doNotAddInitCallback() {
- whenever(DesktopModeStatus.isEnabled()).thenReturn(false)
+ whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(false)
clearInvocations(shellInit)
createController()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
index a64ebd301c00..840126421c08 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
@@ -76,6 +76,8 @@ public class DragAndDropControllerTest extends ShellTestCase {
@Mock
private ShellCommandHandler mShellCommandHandler;
@Mock
+ private ShellTaskOrganizer mShellTaskOrganizer;
+ @Mock
private DisplayController mDisplayController;
@Mock
private UiEventLogger mUiEventLogger;
@@ -96,8 +98,8 @@ public class DragAndDropControllerTest extends ShellTestCase {
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mController = new DragAndDropController(mContext, mShellInit, mShellController,
- mShellCommandHandler, mDisplayController, mUiEventLogger, mIconProvider,
- mGlobalDragListener, mTransitions, mMainExecutor);
+ mShellCommandHandler, mShellTaskOrganizer, mDisplayController, mUiEventLogger,
+ mIconProvider, mGlobalDragListener, mTransitions, mMainExecutor);
mController.onInit();
}
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 6e72e8df8d62..582fb91559e5 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
@@ -65,8 +65,6 @@ import android.content.res.Resources;
import android.graphics.Insets;
import android.os.RemoteException;
import android.view.DisplayInfo;
-import android.view.DragEvent;
-import android.view.View;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -76,7 +74,6 @@ import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
import org.junit.After;
import org.junit.Before;
@@ -106,6 +103,8 @@ public class DragAndDropPolicyTest extends ShellTestCase {
// Both the split-screen and start interface.
@Mock
private SplitScreenController mSplitScreenStarter;
+ @Mock
+ private DragAndDropPolicy.Starter mFullscreenStarter;
@Mock
private InstanceId mLoggerSessionId;
@@ -151,7 +150,7 @@ public class DragAndDropPolicyTest extends ShellTestCase {
mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
mInsets = Insets.of(0, 0, 0, 0);
- mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mSplitScreenStarter));
+ mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mFullscreenStarter));
mActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
mLaunchableIntentPendingIntent = mock(PendingIntent.class);
when(mLaunchableIntentPendingIntent.getCreatorUserHandle())
@@ -285,13 +284,13 @@ public class DragAndDropPolicyTest extends ShellTestCase {
setRunningTask(mHomeTask);
DragSession dragSession = new DragSession(mActivityTaskManager,
mLandscapeDisplayLayout, data, 0 /* dragFlags */);
- dragSession.update();
+ dragSession.initialize();
mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN));
- verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
+ verify(mFullscreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_UNDEFINED), any());
}
@@ -300,7 +299,7 @@ public class DragAndDropPolicyTest extends ShellTestCase {
setRunningTask(mFullscreenAppTask);
DragSession dragSession = new DragSession(mActivityTaskManager,
mLandscapeDisplayLayout, data, 0 /* dragFlags */);
- dragSession.update();
+ dragSession.initialize();
mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
@@ -320,7 +319,7 @@ public class DragAndDropPolicyTest extends ShellTestCase {
setRunningTask(mFullscreenAppTask);
DragSession dragSession = new DragSession(mActivityTaskManager,
mPortraitDisplayLayout, data, 0 /* dragFlags */);
- dragSession.update();
+ dragSession.initialize();
mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
@@ -340,7 +339,7 @@ public class DragAndDropPolicyTest extends ShellTestCase {
setRunningTask(mFullscreenAppTask);
DragSession dragSession = new DragSession(mActivityTaskManager,
mLandscapeDisplayLayout, mActivityClipData, 0 /* dragFlags */);
- dragSession.update();
+ dragSession.initialize();
mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = mPolicy.getTargets(mInsets);
for (Target t : targets) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index 86aded76c0f3..ac5aeec3adc8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -27,6 +27,9 @@ import android.platform.test.flag.junit.SetFlagsRule
import android.testing.AndroidTestingRunner
import android.view.Display
import android.window.WindowContainerToken
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.common.DisplayController
@@ -37,6 +40,7 @@ import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertTrue
+import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -45,6 +49,7 @@ import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import org.mockito.quality.Strictness
/**
* Tests for [DragPositioningCallbackUtility].
@@ -82,9 +87,13 @@ class DragPositioningCallbackUtilityTest {
@Rule
val setFlagsRule = SetFlagsRule()
+ private lateinit var mockitoSession: StaticMockitoSession
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+ mockitoSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
+ .spyStatic(DesktopModeStatus::class.java).startMocking()
whenever(taskToken.asBinder()).thenReturn(taskBinder)
whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
@@ -105,6 +114,11 @@ class DragPositioningCallbackUtilityTest {
whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
}
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
+ }
+
@Test
fun testChangeBoundsDoesNotChangeHeightWhenLessThanMin() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
@@ -252,7 +266,7 @@ class DragPositioningCallbackUtilityTest {
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeLessThanMin_shouldNotChangeBounds() {
- whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true)
+ doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) }
initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1)
val startingPoint =
PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat())
@@ -275,7 +289,7 @@ class DragPositioningCallbackUtilityTest {
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeAllowedSize_shouldChangeBounds() {
- whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true)
+ doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) }
initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1)
val startingPoint =
PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat())
@@ -361,7 +375,7 @@ class DragPositioningCallbackUtilityTest {
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
fun testChangeBoundsInDesktopMode_windowSizeExceedsStableBounds_shouldBeLimitedToDisplaySize() {
- whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true)
+ doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) }
val startingPoint =
PointF(OFF_CENTER_STARTING_BOUNDS.right.toFloat(),
OFF_CENTER_STARTING_BOUNDS.bottom.toFloat())
diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
index 1325fc161b77..028c97ec51f7 100644
--- a/media/tests/MediaFrameworkTest/Android.bp
+++ b/media/tests/MediaFrameworkTest/Android.bp
@@ -24,6 +24,7 @@ android_test {
"flag-junit",
"testng",
"truth",
+ "collector-device-lib-platform",
],
jni_libs: [
"libdexmakerjvmtiagent",
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
index 2e9b7b421a7b..a23df64f3582 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
@@ -97,6 +97,7 @@ class InstallRepository(private val context: Context) {
private set
private var callingUid = Process.INVALID_UID
private var originatingUid = Process.INVALID_UID
+ private var originatingUidFromSessionInfo = Process.INVALID_UID
private var callingPackage: String? = null
private var sessionStager: SessionStager? = null
private lateinit var intent: Intent
@@ -136,17 +137,25 @@ class InstallRepository(private val context: Context) {
callingPackage = callerInfo.packageName
- if (sessionId != SessionInfo.INVALID_ID) {
- val sessionInfo: SessionInfo? = packageInstaller.getSessionInfo(sessionId)
- callingPackage = sessionInfo?.getInstallerPackageName()
- callingAttributionTag = sessionInfo?.getInstallerAttributionTag()
- }
-
// Uid of the source package, coming from ActivityManager
callingUid = callerInfo.uid
if (callingUid == Process.INVALID_UID) {
Log.e(LOG_TAG, "Could not determine the launching uid.")
}
+
+ originatingUidFromSessionInfo = callingUid
+ val sessionInfo: SessionInfo? =
+ if (sessionId != SessionInfo.INVALID_ID)
+ packageInstaller.getSessionInfo(sessionId)
+ else null
+ if (sessionInfo != null) {
+ callingPackage = sessionInfo.installerPackageName
+ callingAttributionTag = sessionInfo.installerAttributionTag
+ if (sessionInfo.originatingUid != Process.INVALID_UID) {
+ originatingUidFromSessionInfo = sessionInfo.originatingUid
+ }
+ }
+
val sourceInfo: ApplicationInfo? = getSourceInfo(callingPackage)
// Uid of the source package, with a preference to uid from ApplicationInfo
originatingUid = sourceInfo?.uid ?: callingUid
@@ -651,7 +660,12 @@ class InstallRepository(private val context: Context) {
private fun getUpdateMessage(pkgInfo: PackageInfo, userActionReason: Int): String? {
if (isAppUpdating(pkgInfo)) {
val existingUpdateOwnerLabel = getExistingUpdateOwnerLabel(pkgInfo)
- val requestedUpdateOwnerLabel = getApplicationLabel(callingPackage)
+
+ val originatingPackageNameFromSessionInfo =
+ getPackageNameForUid(context, originatingUidFromSessionInfo, callingPackage)
+ val requestedUpdateOwnerLabel =
+ getApplicationLabel(originatingPackageNameFromSessionInfo)
+
if (!TextUtils.isEmpty(existingUpdateOwnerLabel)
&& userActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP
) {
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 4ac3e671a378..8666584e0972 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -64,13 +64,6 @@ flag {
}
flag {
- name: "allow_all_widgets_on_lockscreen_by_default"
- namespace: "systemui"
- description: "Allow all widgets on the lock screen by default."
- bug: "328261690"
-}
-
-flag {
name: "enable_determining_advanced_details_header_with_metadata"
namespace: "pixel_cross_device_control"
description: "Use metadata instead of device type to determine whether a bluetooth device should use advanced details header."
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 27c386e52c8c..cfd74d4b9f42 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1010,10 +1010,10 @@
<!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] -->
<string name="force_resizable_activities_summary">Make all activities resizable for multi-window, regardless of manifest values.</string>
- <!-- UI debug setting: enable freeform window support [CHAR LIMIT=50] -->
- <string name="enable_freeform_support">Enable freeform windows</string>
- <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
- <string name="enable_freeform_support_summary">Enable support for experimental freeform windows.</string>
+ <!-- UI debug setting: enable legacy freeform window support [CHAR LIMIT=50] -->
+ <string name="enable_freeform_support">Enable freeform windows (legacy)</string>
+ <!-- UI debug setting: enable legacy freeform window support summary [CHAR LIMIT=150] -->
+ <string name="enable_freeform_support_summary">Enable support for experimental legacy freeform windows.</string>
<!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
<string name="local_backup_password_title">Desktop backup password</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
index 727c61ca1ae0..a7e04640d069 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
@@ -498,7 +498,7 @@ open class WifiUtils {
): Job =
coroutineScope.launch {
val wifiManager = context.getSystemService(WifiManager::class.java) ?: return@launch
- if (wifiManager.queryWepAllowed()) {
+ if (wifiManager.isWepSupported == true && wifiManager.queryWepAllowed()) {
onAllowed()
} else {
val intent = Intent(Intent.ACTION_MAIN).apply {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index d54236e60dd7..54f0d7a4d853 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1189,6 +1189,8 @@ public class SettingsProvider extends ContentProvider {
synchronized (mLock) {
if (getSyncDisabledModeConfigLocked() != SYNC_DISABLED_MODE_NONE) {
+ Slog.v(LOG_TAG, "did not write settings for prefix '"
+ + prefix + "' because sync is disabled");
return SET_ALL_RESULT_DISABLED;
}
final int key = makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 05eb0449495f..861c405b1542 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -203,6 +203,12 @@ final class SettingsState {
private static final String NULL_VALUE = "null";
+ // TOBO(b/312444587): remove after Test Mission 2.
+ // Bulk sync names
+ private static final String BULK_SYNC_MARKER = "aconfigd_marker/bulk_synced";
+ private static final String BULK_SYNC_TRIGGER_COUNTER =
+ "core_experiments_team_internal/BulkSyncTriggerCounterFlag__bulk_sync_trigger_counter";
+
private static final ArraySet<String> sSystemPackages = new ArraySet<>();
private final Object mWriteLock = new Object();
@@ -409,8 +415,7 @@ final class SettingsState {
}
}
// TOBO(b/312444587): remove the comparison logic after Test Mission 2.
- if (mSettings.get("aconfigd_marker/bulk_synced").value.equals("true")
- && requests == null) {
+ if (requests == null) {
Map<String, AconfigdFlagInfo> aconfigdFlagMap =
AconfigdJavaUtils.listFlagsValueInNewStorage(localSocket);
compareFlagValueInNewStorage(
@@ -534,7 +539,7 @@ final class SettingsState {
return null;
}
AconfigdFlagInfo flag = flagInfoDefault.get(fullFlagName);
- if (flag == null) {
+ if (flag == null || !namespace.equals(flag.getNamespace())) {
return null;
}
@@ -553,15 +558,33 @@ final class SettingsState {
public ProtoOutputStream handleBulkSyncToNewStorage(
Map<String, AconfigdFlagInfo> aconfigFlagMap) {
// get marker or add marker if it does not exist
- final String bulkSyncMarkerName = new String("aconfigd_marker/bulk_synced");
- Setting markerSetting = mSettings.get(bulkSyncMarkerName);
+ Setting markerSetting = mSettings.get(BULK_SYNC_MARKER);
+ int localCounter = 0;
if (markerSetting == null) {
- markerSetting = new Setting(bulkSyncMarkerName, "false", false, "aconfig", "aconfig");
- mSettings.put(bulkSyncMarkerName, markerSetting);
+ markerSetting = new Setting(BULK_SYNC_MARKER, "0", false, "aconfig", "aconfig");
+ mSettings.put(BULK_SYNC_MARKER, markerSetting);
+ }
+ try {
+ localCounter = Integer.parseInt(markerSetting.value);
+ } catch(NumberFormatException e) {
+ // reset local counter
+ markerSetting.value = "0";
}
if (enableAconfigStorageDaemon()) {
- if (markerSetting.value.equals("true")) {
+ Setting bulkSyncCounter = mSettings.get(BULK_SYNC_TRIGGER_COUNTER);
+ int serverCounter = 0;
+ if (bulkSyncCounter != null) {
+ try {
+ serverCounter = Integer.parseInt(bulkSyncCounter.value);
+ } catch (NumberFormatException e) {
+ // reset the local value of server counter
+ bulkSyncCounter.value = "0";
+ }
+ }
+
+ boolean shouldSync = localCounter < serverCounter;
+ if (!shouldSync) {
// CASE 1, flag is on, bulk sync marker true, nothing to do
return null;
} else {
@@ -600,20 +623,12 @@ final class SettingsState {
}
// mark sync has been done
- markerSetting.value = "true";
+ markerSetting.value = String.valueOf(serverCounter);
scheduleWriteIfNeededLocked();
return requests;
}
} else {
- if (markerSetting.value.equals("true")) {
- // CASE 3, flag is off, bulk sync marker true, clear the marker
- markerSetting.value = "false";
- scheduleWriteIfNeededLocked();
- return null;
- } else {
- // CASE 4, flag is off, bulk sync marker false, nothing to do
- return null;
- }
+ return null;
}
}
@@ -692,6 +707,7 @@ final class SettingsState {
.setFlagName(flag.getName())
.setDefaultFlagValue(flagValue)
.setIsReadWrite(isReadWrite)
+ .setNamespace(flag.getNamespace())
.build());
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 5f8e933e0652..411decd8476a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -177,6 +177,7 @@ public class SettingsBackupTest {
Settings.Global.DESK_UNDOCK_SOUND,
Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
+ Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
Settings.Global.DEVELOPMENT_FORCE_RTL,
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 94aeb9b8dcc4..4b4ced3c0753 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -151,12 +151,14 @@ public class SettingsStateTest {
.setFlagName("flag1")
.setDefaultFlagValue("false")
.setIsReadWrite(true)
+ .setNamespace("test_namespace")
.build();
AconfigdFlagInfo flag2 = AconfigdFlagInfo.newBuilder()
.setPackageName("com.android.flags")
.setFlagName("flag2")
.setDefaultFlagValue("true")
.setIsReadWrite(false)
+ .setNamespace("test_namespace")
.build();
Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>();
@@ -1018,12 +1020,17 @@ public class SettingsStateTest {
.setFlagName("flag1")
.setDefaultFlagValue("false")
.setIsReadWrite(true)
+ .setNamespace("test_namespace")
.build();
flagInfoDefault.put(flag1.getFullFlagName(), flag1);
- // server override
+ // not the right namespace
+ assertNull(
+ settingsState.getFlagOverrideToSync(
+ "some_namespace/com.android.flags.flag1", "true", flagInfoDefault));
+ // server override
settingsState.getFlagOverrideToSync(
"test_namespace/com.android.flags.flag1", "true", flagInfoDefault);
assertEquals("com.android.flags", flag1.getPackageName());
@@ -1079,21 +1086,45 @@ public class SettingsStateTest {
.setIsReadWrite(false)
.build());
+ String bulkSyncMarker = "aconfigd_marker/bulk_synced";
+ String bulkSyncCounter =
+ "core_experiments_team_internal/" +
+ "BulkSyncTriggerCounterFlag__bulk_sync_trigger_counter";
+
synchronized (lock) {
- settingsState.insertSettingLocked(
- "aconfigd_marker/bulk_synced", "false", null, false, "aconfig");
+ settingsState.insertSettingLocked(bulkSyncMarker, "0", null, false, "aconfig");
+ settingsState.insertSettingLocked(bulkSyncCounter, "1", null, false,
+ "com.google.android.platform.core_experiments_team_internal");
// first bulk sync
ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags);
assertTrue(requests != null);
String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("true", value);
+ assertEquals("1", value);
// send time should no longer bulk sync
requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertTrue(requests == null);
+ assertNull(requests);
+ value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
+ assertEquals("1", value);
+
+ // won't sync if the marker is string
+ settingsState.insertSettingLocked(bulkSyncMarker, "true", null, false, "aconfig");
+ settingsState.insertSettingLocked(bulkSyncCounter, "0", null, false,
+ "com.google.android.platform.core_experiments_team_internal");
+ requests = settingsState.handleBulkSyncToNewStorage(flags);
+ assertNull(requests);
value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("true", value);
+ assertEquals("0", value);
+
+ // won't sync if the marker and counter value are the same
+ settingsState.insertSettingLocked(bulkSyncMarker, "1", null, false, "aconfig");
+ settingsState.insertSettingLocked(bulkSyncCounter, "1", null, false,
+ "com.google.android.platform.core_experiments_team_internal");
+ requests = settingsState.handleBulkSyncToNewStorage(flags);
+ assertNull(requests);
+ value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
+ assertEquals("1", value);
}
}
@@ -1107,21 +1138,34 @@ public class SettingsStateTest {
SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
Map<String, AconfigdFlagInfo> flags = new HashMap<>();
+ String bulkSyncMarker = "aconfigd_marker/bulk_synced";
+ String bulkSyncCounter =
+ "core_experiments_team_internal/" +
+ "BulkSyncTriggerCounterFlag__bulk_sync_trigger_counter";
synchronized (lock) {
settingsState.insertSettingLocked("aconfigd_marker/bulk_synced",
"true", null, false, "aconfig");
// when aconfigd is off, should change the marker to false
ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertTrue(requests == null);
+ assertNull(requests);
String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("false", value);
+ assertEquals("0", value);
// marker started with false value, after call, it should remain false
requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertTrue(requests == null);
+ assertNull(requests);
value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("false", value);
+ assertEquals("0", value);
+
+ // won't sync
+ settingsState.insertSettingLocked(bulkSyncMarker, "0", null, false, "aconfig");
+ settingsState.insertSettingLocked(bulkSyncCounter, "1", null, false,
+ "com.google.android.platform.core_experiments_team_internal");
+ requests = settingsState.handleBulkSyncToNewStorage(flags);
+ assertNull(requests);
+ value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
+ assertEquals("0", value);
}
}
@@ -1164,6 +1208,7 @@ public class SettingsStateTest {
.setFlagName("flag1")
.setDefaultFlagValue("false")
.setIsReadWrite(true)
+ .setNamespace("test_namespace")
.build();
flagInfoDefault.put(flag1.getFullFlagName(), flag1);
@@ -1186,6 +1231,7 @@ public class SettingsStateTest {
.setFlagName("flag2")
.setDefaultFlagValue("false")
.setIsReadWrite(true)
+ .setNamespace("test_namespace")
.build();
flagInfoDefault.put(flag2.getFullFlagName(), flag2);
synchronized (lock) {
@@ -1207,6 +1253,7 @@ public class SettingsStateTest {
.setFlagName("flag3")
.setDefaultFlagValue("false")
.setIsReadWrite(false)
+ .setNamespace("test_namespace")
.build();
flagInfoDefault.put(flag3.getFullFlagName(), flag3);
synchronized (lock) {
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 0731616b81bf..f5153e1aa8b3 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1122,3 +1122,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "translucent_occluding_activity_fix"
+ namespace: "systemui"
+ description: "Fixes occlusion animation for transluent activities"
+ bug: "303010980"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index b6e4e9b13a1c..c14ee6208176 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -22,6 +22,7 @@ import android.app.PendingIntent
import android.app.TaskInfo
import android.app.WindowConfiguration
import android.content.ComponentName
+import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Rect
import android.graphics.RectF
@@ -53,6 +54,7 @@ import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.systemui.Flags.activityTransitionUseLargestWindow
+import com.android.systemui.Flags.translucentOccludingActivityFix
import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
import com.android.wm.shell.shared.IShellTransitions
import com.android.wm.shell.shared.ShellTransitions
@@ -991,7 +993,12 @@ constructor(
controller.createAnimatorState()
}
val windowBackgroundColor =
- window.taskInfo?.let { callback.getBackgroundColor(it) } ?: window.backgroundColor
+ if (translucentOccludingActivityFix() && window.isTranslucent) {
+ Color.TRANSPARENT
+ } else {
+ window.taskInfo?.let { callback.getBackgroundColor(it) }
+ ?: window.backgroundColor
+ }
// TODO(b/184121838): We should somehow get the top and bottom radius of the window
// instead of recomputing isExpandingFullyAbove here.
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 22566e70f409..9c9e6c69de1c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -34,6 +34,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.observableTransitionState
import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
@@ -56,7 +58,6 @@ import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
* must have entries in this map.
* @param modifier A modifier.
*/
-@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun SceneContainer(
viewModel: SceneContainerViewModel,
@@ -66,8 +67,6 @@ fun SceneContainer(
) {
val coroutineScope = rememberCoroutineScope()
val currentSceneKey: SceneKey by viewModel.currentScene.collectAsStateWithLifecycle()
- val currentDestinations by
- viewModel.currentDestinationScenes(coroutineScope).collectAsStateWithLifecycle()
val state: MutableSceneTransitionLayoutState = remember {
MutableSceneTransitionLayoutState(
initialScene = currentSceneKey,
@@ -88,20 +87,19 @@ fun SceneContainer(
onDispose { viewModel.setTransitionState(null) }
}
+ val userActionsBySceneKey: Map<SceneKey, Map<UserAction, UserActionResult>> =
+ sceneByKey.values.associate { scene ->
+ val userActions by scene.destinationScenes.collectAsStateWithLifecycle(emptyMap())
+ val resolvedUserActions = viewModel.resolveSceneFamilies(userActions)
+ scene.key to resolvedUserActions
+ }
+
Box(
modifier = Modifier.fillMaxSize(),
) {
SceneTransitionLayout(state = state, modifier = modifier.fillMaxSize()) {
sceneByKey.forEach { (sceneKey, composableScene) ->
- scene(
- key = sceneKey,
- userActions =
- if (sceneKey == currentSceneKey) {
- currentDestinations
- } else {
- viewModel.resolveSceneFamilies(composableScene.destinationScenes.value)
- },
- ) {
+ scene(key = sceneKey, userActions = checkNotNull(userActionsBySceneKey[sceneKey])) {
with(composableScene) {
this@scene.Content(
modifier = Modifier.element(sceneKey.rootElementKey).fillMaxSize(),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index fa79ea01cf51..54e0725957e6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -1284,6 +1284,41 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
+ public void onAodDownAndDownTouchReceived() throws RemoteException {
+ final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
+ 0L);
+ final TouchProcessorResult processorResultDown =
+ new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
+ -1 /* pointerId */, touchData);
+
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+
+ // WHEN fingerprint is requested because of AOD interrupt
+ // GIVEN there's been an AoD interrupt
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
+ mScreenObserver.onScreenTurnedOn();
+ mUdfpsController.onAodInterrupt(0, 0, 0, 0);
+ mFgExecutor.runAllReady();
+
+ // and an ACTION_DOWN is received and touch is within sensor
+ when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+ processorResultDown);
+ MotionEvent firstDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, firstDownEvent);
+ mBiometricExecutor.runAllReady();
+ firstDownEvent.recycle();
+
+ // THEN the touch is only processed once
+ verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(),
+ anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
+ anyBoolean());
+ }
+
+ @Test
public void onTouch_pilferPointerWhenAltBouncerShowing()
throws RemoteException {
final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
index fe683e07a93d..dcc9c7aacdf0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
@@ -47,6 +47,7 @@ import org.mockito.Mockito.verify
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnableFlags(Flags.FLAG_COMMUNAL_HUB)
@RunWith(AndroidJUnit4::class)
class CommunalDreamStartableTest : SysuiTestCase() {
private val kosmos = testKosmos()
@@ -76,7 +77,7 @@ class CommunalDreamStartableTest : SysuiTestCase() {
testScope.runTest {
keyguardRepository.setDreaming(false)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
runCurrent()
verify(dreamManager, never()).startDream()
@@ -92,7 +93,7 @@ class CommunalDreamStartableTest : SysuiTestCase() {
testScope.runTest {
keyguardRepository.setDreaming(false)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
runCurrent()
verify(dreamManager, never()).startDream()
@@ -118,7 +119,7 @@ class CommunalDreamStartableTest : SysuiTestCase() {
keyguardRepository.setDreaming(false)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
// Not eligible to dream
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(false)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(false)
transition(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB)
verify(dreamManager, never()).startDream()
@@ -129,7 +130,7 @@ class CommunalDreamStartableTest : SysuiTestCase() {
testScope.runTest {
keyguardRepository.setDreaming(true)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
transition(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB)
verify(dreamManager, never()).startDream()
@@ -140,7 +141,7 @@ class CommunalDreamStartableTest : SysuiTestCase() {
testScope.runTest {
keyguardRepository.setDreaming(true)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
// Verify we do not trigger dreaming for any other state besides glanceable hub
for (state in KeyguardState.entries) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
index fb2b33d70c47..da40f640d5fa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
@@ -20,7 +20,6 @@ import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
import android.app.admin.devicePolicyManager
-import android.appwidget.AppWidgetProviderInfo
import android.content.Intent
import android.content.pm.UserInfo
import android.os.UserManager.USER_TYPE_PROFILE_MANAGED
@@ -29,7 +28,6 @@ import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.settingslib.flags.Flags.FLAG_ALLOW_ALL_WIDGETS_ON_LOCKSCREEN_BY_DEFAULT
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.broadcastDispatcher
@@ -183,42 +181,6 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() {
)
}
- @EnableFlags(FLAG_COMMUNAL_HUB)
- @Test
- fun hubShowsWidgetCategoriesSetByUser() =
- testScope.runTest {
- kosmos.fakeSettings.putIntForUser(
- CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING,
- AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
- PRIMARY_USER.id
- )
- val setting by collectLastValue(underTest.getWidgetCategories(PRIMARY_USER))
- assertThat(setting?.categories)
- .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN)
- }
-
- @EnableFlags(FLAG_COMMUNAL_HUB)
- @DisableFlags(FLAG_ALLOW_ALL_WIDGETS_ON_LOCKSCREEN_BY_DEFAULT)
- @Test
- fun hubShowsKeyguardWidgetsByDefault() =
- testScope.runTest {
- val setting by collectLastValue(underTest.getWidgetCategories(PRIMARY_USER))
- assertThat(setting?.categories)
- .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
- }
-
- @EnableFlags(FLAG_COMMUNAL_HUB, FLAG_ALLOW_ALL_WIDGETS_ON_LOCKSCREEN_BY_DEFAULT)
- @Test
- fun hubShowsAllWidgetsByDefaultWhenFlagEnabled() =
- testScope.runTest {
- val setting by collectLastValue(underTest.getWidgetCategories(PRIMARY_USER))
- assertThat(setting?.categories)
- .isEqualTo(
- AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD +
- AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
- )
- }
-
@Test
fun backgroundType_defaultValue() =
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index d951cca89f64..7b26db50814e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -36,7 +36,6 @@ import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.broadcastDispatcher
-import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl
import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository
import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
@@ -81,7 +80,6 @@ import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -915,14 +913,6 @@ class CommunalInteractorTest : SysuiTestCase() {
)
runCurrent()
- // Keyguard widgets are allowed.
- kosmos.fakeSettings.putIntForUser(
- CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING,
- AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
- mainUser.id
- )
- runCurrent()
-
// When work profile is paused.
whenever(userManager.isQuietModeEnabled(eq(UserHandle.of(USER_INFO_WORK.id))))
.thenReturn(true)
@@ -956,93 +946,6 @@ class CommunalInteractorTest : SysuiTestCase() {
}
@Test
- fun widgetContent_containsDisabledWidgets_whenCategoryNotAllowed() =
- testScope.runTest {
- // Communal available, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
-
- val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
- userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
- userRepository.setSelectedUserInfo(MAIN_USER_INFO)
- runCurrent()
-
- // Widgets available.
- val widget1 =
- createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN)
- val widget2 =
- createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
- val widget3 =
- createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX)
- val widgets = listOf(widget1, widget2, widget3)
- widgetRepository.setCommunalWidgets(widgets)
-
- val widgetContent by collectLastValue(underTest.widgetContent)
- kosmos.fakeSettings.putIntForUser(
- CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING,
- AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
- mainUser.id
- )
-
- // Only the keyguard widget is enabled.
- assertThat(widgetContent).hasSize(3)
- assertThat(widgetContent!!.get(0))
- .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java)
- assertThat(widgetContent!!.get(1))
- .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java)
- assertThat(widgetContent!!.get(2))
- .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java)
- }
-
- @Test
- fun widgetContent_allEnabled_whenCategoryAllowed() =
- testScope.runTest {
- // Communal available, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
-
- val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
- userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
- userRepository.setSelectedUserInfo(MAIN_USER_INFO)
- runCurrent()
-
- // Widgets available.
- val widget1 =
- createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN)
- val widget2 =
- createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
- val widget3 =
- createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
- val widgets = listOf(widget1, widget2, widget3)
- widgetRepository.setCommunalWidgets(widgets)
-
- val widgetContent by collectLastValue(underTest.widgetContent)
- kosmos.fakeSettings.putIntForUser(
- CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING,
- AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD or
- AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
- mainUser.id
- )
-
- // All widgets are enabled.
- assertThat(widgetContent).hasSize(3)
- widgetContent!!.forEach { model ->
- assertThat(model)
- .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java)
- }
- }
-
- @Test
fun filterWidgets_whenDisallowedByDevicePolicyForWorkProfile() =
testScope.runTest {
// Keyguard showing, and tutorial completed.
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 7b7d03b2024a..70448955eff0 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
@@ -72,6 +72,7 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
/* animationController = */ notNull(),
/* fillInIntent = */ refEq(fillInIntent),
/* extraOptions = */ refEq(activityOptions.toBundle()),
+ /* customMessage */ isNull(),
)
}
@@ -93,6 +94,7 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
/* animationController = */ isNull(),
/* fillInIntent = */ refEq(fillInIntent),
/* extraOptions = */ refEq(activityOptions.toBundle()),
+ /* customMessage */ isNull(),
)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
index 9ce2e0f87499..c33e2a49ef5d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
@@ -92,7 +92,8 @@ class QSTileViewModelTest : SysuiTestCase() {
runCurrent()
assertThat(states()).isNotEmpty()
- assertThat(states().first().label).isEqualTo(testTileData)
+ assertThat(states().last()).isNotNull()
+ assertThat(states().last()!!.label).isEqualTo(testTileData)
verify(qsTileLogger).logInitialRequest(eq(tileConfig.tileSpec))
}
@@ -196,6 +197,7 @@ class QSTileViewModelTest : SysuiTestCase() {
qsTileLogger,
FakeSystemClock(),
testCoroutineDispatcher,
+ testCoroutineDispatcher,
scope.backgroundScope,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
index 6066d24c2214..7955f2fc1335 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
@@ -256,6 +256,7 @@ class QSTileViewModelUserInputTest : SysuiTestCase() {
qsTileLogger,
FakeSystemClock(),
testCoroutineDispatcher,
+ testCoroutineDispatcher,
scope.backgroundScope,
)
}
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 cb4d96fa735f..39b366226987 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -133,7 +133,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
sceneInteractor = sceneInteractor,
falsingInteractor = kosmos.falsingInteractor,
powerInteractor = kosmos.powerInteractor,
- scenes = kosmos.scenes,
)
.apply { setTransitionState(transitionState) }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index 5c30379ea2fb..ea95aab4a1c4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -28,10 +28,8 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.fakeScenes
import com.android.systemui.scene.sceneContainerConfig
import com.android.systemui.scene.sceneKeys
-import com.android.systemui.scene.scenes
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.testKosmos
@@ -66,7 +64,6 @@ class SceneContainerViewModelTest : SysuiTestCase() {
sceneInteractor = sceneInteractor,
falsingInteractor = kosmos.falsingInteractor,
powerInteractor = kosmos.powerInteractor,
- scenes = kosmos.scenes,
)
}
@@ -217,23 +214,4 @@ class SceneContainerViewModelTest : SysuiTestCase() {
assertThat(isVisible).isFalse()
}
-
- @Test
- fun currentDestinationScenes_onlyTheCurrentSceneIsCollected() =
- testScope.runTest {
- val unused by collectLastValue(underTest.currentDestinationScenes(backgroundScope))
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- kosmos.fakeScenes.forEach { scene ->
- fakeSceneDataSource.changeScene(toScene = scene.key)
- runCurrent()
- assertThat(currentScene).isEqualTo(scene.key)
-
- assertThat(scene.isDestinationScenesBeingCollected).isTrue()
- kosmos.fakeScenes
- .filter { it.key != scene.key }
- .forEach { otherScene ->
- assertThat(otherScene.isDestinationScenesBeingCollected).isFalse()
- }
- }
- }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt
index 5887f90036ec..ccd78ee82169 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt
@@ -154,6 +154,25 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
}
@Test
+ fun startPendingIntentDismissingKeyguard_withCustomMessage_dismissWithAction() {
+ val pendingIntent = mock(PendingIntent::class.java)
+ `when`(pendingIntent.isActivity).thenReturn(true)
+ `when`(keyguardStateController.isShowing).thenReturn(true)
+ `when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ val customMessage = "Custom unlock reason"
+
+ underTest.startPendingIntentDismissingKeyguard(
+ intent = pendingIntent,
+ dismissShade = true,
+ customMessage = customMessage
+ )
+ mainExecutor.runAllReady()
+
+ verify(statusBarKeyguardViewManager)
+ .dismissWithAction(any(), eq(null), anyBoolean(), eq(customMessage))
+ }
+
+ @Test
fun startPendingIntentMaybeDismissingKeyguard_keyguardShowing_showOverLs_launchAnimator() {
val pendingIntent = mock(PendingIntent::class.java)
val parent = FrameLayout(context)
@@ -466,6 +485,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
animationController: ActivityTransitionAnimator.Controller?,
fillInIntent: Intent? = null,
extraOptions: Bundle? = null,
+ customMessage: String? = null,
) {
underTest.startPendingIntentDismissingKeyguard(
intent = intent,
@@ -475,6 +495,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
showOverLockscreen = true,
fillInIntent = fillInIntent,
extraOptions = extraOptions,
+ customMessage = customMessage,
)
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 7cf56aa5c40e..abb721ab0dd8 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -84,14 +84,17 @@ public interface ActivityStarter {
* Similar to {@link #startPendingIntentMaybeDismissingKeyguard(PendingIntent, Runnable,
* ActivityTransitionAnimator.Controller)}, but also specifies a fill-in intent and extra
* option that could be used to populate the pending intent and launch the activity. This also
- * allows the caller to avoid dismissing the shade.
+ * allows the caller to avoid dismissing the shade. An optional custom message can be set as
+ * the unlock reason in the alternate bouncer.
*/
void startPendingIntentMaybeDismissingKeyguard(PendingIntent intent,
boolean dismissShade,
@Nullable Runnable intentSentUiThreadCallback,
@Nullable ActivityTransitionAnimator.Controller animationController,
@Nullable Intent fillInIntent,
- @Nullable Bundle extraOptions);
+ @Nullable Bundle extraOptions,
+ @Nullable String customMessage
+ );
/**
* The intent flag can be specified in startActivity().
@@ -134,14 +137,20 @@ public interface ActivityStarter {
void dismissKeyguardThenExecute(OnDismissAction action, @Nullable Runnable cancel,
boolean afterKeyguardGone);
- /** Authenticates if needed and dismisses keyguard to execute an action. */
+ /**
+ * Authenticates if needed and dismisses keyguard to execute an action.
+ *
+ * TODO(b/348431835) Display the custom message in the new alternate bouncer, when the
+ * device_entry_udfps_refactor flag is enabled.
+ */
void dismissKeyguardThenExecute(OnDismissAction action, @Nullable Runnable cancel,
boolean afterKeyguardGone, @Nullable String customMessage);
/** Starts an activity and dismisses keyguard. */
void startActivityDismissingKeyguard(Intent intent,
boolean onlyProvisioned,
- boolean dismissShade);
+ boolean dismissShade,
+ @Nullable String customMessage);
/** Starts an activity and dismisses keyguard. */
void startActivityDismissingKeyguard(Intent intent,
diff --git a/packages/SystemUI/res/color/connected_network_primary_color.xml b/packages/SystemUI/res/color/connected_network_primary_color.xml
new file mode 100644
index 000000000000..f173c8dd5473
--- /dev/null
+++ b/packages/SystemUI/res/color/connected_network_primary_color.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/materialColorOnPrimaryContainer" />
+</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml
index 250188b892f4..fab2d8db859f 100644
--- a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml
+++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml
@@ -16,10 +16,11 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
- <solid android:color="@color/settingslib_state_on_color"/>
+ <solid android:color="?androidprv:attr/materialColorPrimaryContainer"/>
<corners android:radius="@dimen/settingslib_switch_bar_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml
index 5566ea3f62fc..e316a93c1c3d 100644
--- a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml
+++ b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml
@@ -15,7 +15,8 @@
limitations under the License.
-->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<item
android:top="@dimen/settingslib_switch_thumb_margin"
android:bottom="@dimen/settingslib_switch_thumb_margin">
@@ -23,7 +24,7 @@
<size
android:height="@dimen/settingslib_switch_thumb_size"
android:width="@dimen/settingslib_switch_thumb_size"/>
- <solid android:color="@color/settingslib_state_on_color"/>
+ <solid android:color="?androidprv:attr/materialColorOnPrimary"/>
</shape>
</item>
</layer-list>
diff --git a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml
index 1d9dacd6c0f9..e2e64684f9c3 100644
--- a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml
+++ b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml
@@ -16,11 +16,12 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle"
android:width="@dimen/settingslib_switch_track_width"
android:height="@dimen/settingslib_switch_track_height">
<padding android:left="@dimen/settingslib_switch_thumb_margin"
android:right="@dimen/settingslib_switch_thumb_margin"/>
- <solid android:color="@color/settingslib_track_on_color"/>
+ <solid android:color="?androidprv:attr/materialColorPrimary"/>
<corners android:radius="@dimen/settingslib_switch_track_radius"/>
</shape>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index d377e0196e98..21f1cfbe4c9e 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -104,10 +104,6 @@
<color name="people_tile_background">@color/material_dynamic_secondary20</color>
- <!-- Internet Dialog -->
- <color name="connected_network_primary_color">@color/material_dynamic_primary80</color>
- <color name="connected_network_secondary_color">@color/material_dynamic_secondary80</color>
-
<!-- Keyboard shortcut helper dialog -->
<color name="ksh_key_item_color">@*android:color/system_on_surface_variant_dark</color>
</resources>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 546bf1c3ac95..e9dd039f38c2 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -60,18 +60,6 @@
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
</style>
- <style name="TextAppearance.InternetDialog.Active">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textSize">16sp</item>
- <item name="android:textColor">@color/material_dynamic_primary80</item>
- <item name="android:textDirection">locale</item>
- </style>
-
- <style name="TextAppearance.InternetDialog.Secondary.Active">
- <item name="android:textSize">14sp</item>
- <item name="android:textColor">@color/material_dynamic_secondary80</item>
- </style>
-
<style name="ShortcutHelperTheme" parent="@style/ShortcutHelperThemeCommon">
<item name="android:windowLightNavigationBar">false</item>
</style>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index b3d3021028e1..0350cd7dab98 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -236,11 +236,8 @@
<!-- Internet Dialog -->
<!-- Material next state on color-->
<color name="settingslib_state_on_color">@color/settingslib_state_on</color>
- <!-- Material next track on color-->
- <color name="settingslib_track_on_color">@color/settingslib_track_on</color>
<!-- Material next track off color-->
<color name="settingslib_track_off_color">@color/settingslib_track_off</color>
- <color name="connected_network_primary_color">#191C18</color>
<color name="connected_network_secondary_color">#41493D</color>
<color name="dream_overlay_camera_mic_off_dot_color">#FCBE03</color>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 177ba598add7..212dae279387 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -233,6 +233,7 @@
<item type="id" name="smart_space_barrier_bottom" />
<item type="id" name="small_clock_guideline_top" />
<item type="id" name="weather_clock_date_and_icons_barrier_bottom" />
+ <item type="id" name="weather_clock_bc_smartspace_bottom" />
<item type="id" name="accessibility_actions_view" />
<!-- Privacy dialog -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ff43c9bc276e..e92b942635f2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1193,6 +1193,8 @@
<string name="popup_on_dismiss_cta_tile_text">Long press to customize widgets</string>
<!-- Text for the button to configure widgets after long press. [CHAR LIMIT=50] -->
<string name="button_to_configure_widgets_text">Customize widgets</string>
+ <!-- Text for unlock reason on the bouncer before customizing widgets. [CHAR LIMIT=NONE] -->
+ <string name="unlock_reason_to_customize_widgets">Unlock to customize widgets</string>
<!-- Description for the App icon of disabled widget. [CHAR LIMIT=NONE] -->
<string name="icon_description_for_disabled_widget">App icon for disabled widget</string>
<!-- Description for the App icon of a package that is currently being installed. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 73b7586f1210..7475eb2eceaa 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1315,7 +1315,7 @@
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
- <style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault">
+ <style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
</style>
@@ -1358,6 +1358,7 @@
<style name="InternetDialog.NetworkTitle.Active">
<item name="android:textAppearance">@style/TextAppearance.InternetDialog.Active</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item>
</style>
<style name="InternetDialog.NetworkSummary">
@@ -1370,18 +1371,19 @@
<style name="InternetDialog.NetworkSummary.Active">
<item name="android:textAppearance">@style/TextAppearance.InternetDialog.Secondary.Active
</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item>
</style>
<style name="TextAppearance.InternetDialog">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:textSize">16sp</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
<item name="android:textDirection">locale</item>
</style>
<style name="TextAppearance.InternetDialog.Secondary">
<item name="android:textSize">14sp</item>
- <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
</style>
<style name="TextAppearance.InternetDialog.Active"/>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 4b0740288844..56de5a3ed88a 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -38,7 +38,7 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dump.DumpManager;
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 9d573d3919b9..4a28d8b05661 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -469,6 +469,7 @@ class MenuViewLayer extends FrameLayout implements
private void onSpringAnimationsEndAction() {
if (mShouldShowDockTooltip) {
+ mEduTooltipView.ifPresent(this::removeTooltip);
mEduTooltipView = Optional.of(new MenuEduTooltipView(mContext, mMenuViewAppearance));
mEduTooltipView.ifPresent(view -> addTooltipView(view,
getContext().getText(R.string.accessibility_floating_button_docking_tooltip),
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index ad142a86fa03..9d3c6a49a616 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -558,7 +558,12 @@ public class UdfpsController implements DozeReceiver, Dumpable {
Log.w(TAG, "onTouch down received without a preceding up");
}
mActivePointerId = MotionEvent.INVALID_POINTER_ID;
- mOnFingerDown = false;
+
+ // It's possible on some devices to get duplicate touches from both doze and the
+ // normal touch listener. Don't reset the down in this case to avoid duplicate downs
+ if (!mIsAodInterruptActive) {
+ mOnFingerDown = false;
+ }
} else if (!DeviceEntryUdfpsRefactor.isEnabled()) {
if ((mLockscreenShadeTransitionController.getQSDragProgress() != 0f
&& !mAlternateBouncerInteractor.isVisibleState())
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt
index 5cd15f278f00..75f0badfc7cb 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt
@@ -17,7 +17,6 @@
package com.android.systemui.communal.data.model
import android.appwidget.AppWidgetProviderInfo
-import com.android.settingslib.flags.Flags.allowAllWidgetsOnLockscreenByDefault
/**
* The widget categories to display on communal hub (where categories is a bitfield with values that
@@ -31,9 +30,7 @@ value class CommunalWidgetCategories(val categories: Int = defaultCategories) {
val defaultCategories: Int
get() {
return AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD or
- if (allowAllWidgetsOnLockscreenByDefault())
- AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
- else 0
+ AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
index 1c47e507c972..2940a95fdc33 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
@@ -24,7 +24,6 @@ import android.provider.Settings
import com.android.systemui.Flags.communalHub
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.communal.data.model.CommunalEnabledState
-import com.android.systemui.communal.data.model.CommunalWidgetCategories
import com.android.systemui.communal.data.model.DisabledReason
import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_DEVICE_POLICY
import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_FLAG
@@ -52,12 +51,6 @@ interface CommunalSettingsRepository {
/** A [CommunalEnabledState] for the specified user. */
fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState>
- /**
- * A flow that reports the widget categories to show on the hub as selected by the user in
- * Settings.
- */
- fun getWidgetCategories(user: UserInfo): Flow<CommunalWidgetCategories>
-
/** Keyguard widgets enabled state by Device Policy Manager for the specified user. */
fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean>
@@ -104,22 +97,6 @@ constructor(
.flowOn(bgDispatcher)
}
- override fun getWidgetCategories(user: UserInfo): Flow<CommunalWidgetCategories> =
- secureSettings
- .observerFlow(userId = user.id, names = arrayOf(GLANCEABLE_HUB_CONTENT_SETTING))
- // Force an update
- .onStart { emit(Unit) }
- .map {
- CommunalWidgetCategories(
- secureSettings.getIntForUser(
- GLANCEABLE_HUB_CONTENT_SETTING,
- CommunalWidgetCategories.defaultCategories,
- user.id
- )
- )
- }
- .flowOn(bgDispatcher)
-
override fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> =
broadcastDispatcher
.broadcastFlow(
@@ -159,7 +136,6 @@ constructor(
}
companion object {
- const val GLANCEABLE_HUB_CONTENT_SETTING = "glanceable_hub_content_setting"
const val GLANCEABLE_HUB_BACKGROUND_SETTING = "glanceable_hub_background"
private const val ENABLED_SETTING_DEFAULT = 1
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 9f3ade9cd425..f5255ac4d545 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -392,26 +392,17 @@ constructor(
allowedForWorkProfile ->
filterWidgetsAllowedByDevicePolicy(widgets, allowedForWorkProfile)
},
- communalSettingsInteractor.communalWidgetCategories,
updateOnWorkProfileBroadcastReceived,
- ) { widgets, allowedCategories, _ ->
+ ) { widgets, _ ->
widgets.map { widget ->
when (widget) {
is CommunalWidgetContentModel.Available -> {
- if (widget.providerInfo.widgetCategory and allowedCategories != 0) {
- // At least one category this widget specified is allowed, so show it
- WidgetContent.Widget(
- appWidgetId = widget.appWidgetId,
- providerInfo = widget.providerInfo,
- appWidgetHost = appWidgetHost,
- inQuietMode = isQuietModeEnabled(widget.providerInfo.profile)
- )
- } else {
- WidgetContent.DisabledWidget(
- appWidgetId = widget.appWidgetId,
- providerInfo = widget.providerInfo,
- )
- }
+ WidgetContent.Widget(
+ appWidgetId = widget.appWidgetId,
+ providerInfo = widget.providerInfo,
+ appWidgetHost = appWidgetHost,
+ inQuietMode = isQuietModeEnabled(widget.providerInfo.profile)
+ )
}
is CommunalWidgetContentModel.Pending -> {
WidgetContent.PendingWidget(
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
index f043d58543fc..47b75c458d20 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
@@ -19,7 +19,6 @@ package com.android.systemui.communal.domain.interactor
import android.content.pm.UserInfo
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.communal.data.model.CommunalEnabledState
-import com.android.systemui.communal.data.model.CommunalWidgetCategories
import com.android.systemui.communal.data.repository.CommunalSettingsRepository
import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.dagger.SysUISingleton
@@ -70,18 +69,6 @@ constructor(
// Start this eagerly since the value is accessed synchronously in many places.
.stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false)
- /** What widget categories to show on the hub. */
- val communalWidgetCategories: StateFlow<Int> =
- userInteractor.selectedUserInfo
- .flatMapLatest { user -> repository.getWidgetCategories(user) }
- .map { categories -> categories.categories }
- .stateIn(
- scope = bgScope,
- // Start this eagerly since the value can be accessed synchronously.
- started = SharingStarted.Eagerly,
- initialValue = CommunalWidgetCategories.defaultCategories
- )
-
/** The type of background to use for the hub. Used to experiment with different backgrounds */
val communalBackground: Flow<CommunalBackgroundType> =
userInteractor.selectedUserInfo
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 9185384e79a3..fab243575670 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -25,6 +25,7 @@ import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import com.android.internal.logging.UiEventLogger
import com.android.systemui.Flags.enableWidgetPickerSizeFilter
+import com.android.systemui.communal.data.model.CommunalWidgetCategories
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalPrefsInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
@@ -183,7 +184,7 @@ constructor(
}
putExtra(
AppWidgetManager.EXTRA_CATEGORY_FILTER,
- communalSettingsInteractor.communalWidgetCategories.value
+ CommunalWidgetCategories.defaultCategories
)
putExtra(EXTRA_UI_SURFACE_KEY, EXTRA_UI_SURFACE_VALUE)
putParcelableArrayListExtra(EXTRA_ADDED_APP_WIDGETS_KEY, excludeList)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt
index 76be0055c44b..af87f09d3c89 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt
@@ -22,6 +22,7 @@ import com.android.systemui.communal.widgets.EditWidgetsActivity.Companion.EXTRA
import com.android.systemui.communal.widgets.EditWidgetsActivity.Companion.EXTRA_PRESELECTED_KEY
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
import javax.inject.Inject
interface EditWidgetsActivityStarter {
@@ -48,6 +49,7 @@ constructor(
},
/* onlyProvisioned = */ true,
/* dismissShade = */ true,
+ applicationContext.resources.getString(R.string.unlock_reason_to_customize_widgets),
)
}
}
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 cbc6c977e3e6..72f9180c51d2 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
@@ -34,10 +34,11 @@ constructor(
private val activityStarter: ActivityStarter,
) : RemoteViews.InteractionHandler {
- private val delegate = InteractionHandlerDelegate(
- findViewToAnimate = { view -> view is CommunalAppWidgetHostView },
- intentStarter = this::startIntent,
- )
+ private val delegate =
+ InteractionHandlerDelegate(
+ findViewToAnimate = { view -> view is CommunalAppWidgetHostView },
+ intentStarter = this::startIntent,
+ )
override fun onInteraction(
view: View,
@@ -45,7 +46,6 @@ constructor(
response: RemoteViews.RemoteResponse
): Boolean = delegate.onInteraction(view, pendingIntent, response)
-
private fun startIntent(
pendingIntent: PendingIntent,
fillInIntent: Intent,
@@ -59,6 +59,8 @@ constructor(
controller,
fillInIntent,
extraOptions.toBundle(),
+ // TODO(b/325110448): UX to provide copy
+ /* customMessage = */ null,
)
return true
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 140434040ca7..af7ecf66d107 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -29,6 +29,7 @@ import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.statusbar.notification.collection.SortBySectionTimeFlag
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor
@@ -62,6 +63,9 @@ class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, ha
// CommunalHub dependencies
communalHub dependsOn MigrateClocksToBlueprint.token
+
+ // DualShade dependencies
+ DualShade.token dependsOn SceneContainerFlag.getMainAconfigFlag()
}
private inline val politeNotifications
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 73347ada371c..1ea5d1c00561 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -42,6 +42,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
import static com.android.systemui.Flags.refactorGetCurrentUser;
+import static com.android.systemui.Flags.translucentOccludingActivityFix;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
import android.animation.Animator;
@@ -1036,6 +1037,17 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
(int) (fullWidth - initialWidth) /* left */,
fullWidth /* right */,
mWindowCornerRadius, mWindowCornerRadius);
+ } else if (translucentOccludingActivityFix()
+ && mOccludingRemoteAnimationTarget != null
+ && mOccludingRemoteAnimationTarget.isTranslucent) {
+ // Animating in a transparent window looks really weird. Just let it be
+ // fullscreen and the app can do an internal animation if it wants to.
+ return new TransitionAnimator.State(
+ 0,
+ fullHeight,
+ 0,
+ fullWidth,
+ 0f, 0f);
} else {
final float initialHeight = fullHeight / 2f;
final float initialWidth = fullWidth / 2f;
@@ -1399,6 +1411,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private final Lazy<DreamViewModel> mDreamViewModel;
private final Lazy<CommunalTransitionViewModel> mCommunalTransitionViewModel;
private RemoteAnimationTarget mRemoteAnimationTarget;
+
+ /**
+ * The most recent RemoteAnimationTarget provided for an occluding activity animation.
+ */
+ private RemoteAnimationTarget mOccludingRemoteAnimationTarget;
private boolean mShowCommunalWhenUnoccluding = false;
private final Lazy<WindowManagerLockscreenVisibilityManager> mWmLockscreenVisibilityManager;
@@ -3941,6 +3958,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+ // Save mRemoteAnimationTarget for reference in the animation controller. Needs to be
+ // called prior to super.onAnimationStart() since that's the call that eventually asks
+ // the animation controller to configure the animation state.
+ if (apps.length > 0) {
+ mOccludingRemoteAnimationTarget = apps[0];
+ }
+
super.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback);
mInteractionJankMonitor.begin(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 4f75e6fb717a..22ab82b383a7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -249,7 +249,7 @@ constructor(
val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
/** Keyguard can be clipped at the top as the shade is dragged */
- val topClippingBounds: Flow<Int?> =
+ val topClippingBounds: Flow<Int?> by lazy {
combineTransform(
keyguardTransitionInteractor
.transitionValue(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
@@ -263,6 +263,7 @@ constructor(
}
}
.distinctUntilChanged()
+ }
/** Last point that [KeyguardRootView] view was tapped */
val lastRootViewTapPosition: Flow<Point?> = repository.lastRootViewTapPosition.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
index f2821a0f49d2..e0633807db88 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
@@ -37,6 +37,10 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.clocks.AodClockBurnInModel
import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.util.ui.value
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
object KeyguardClockViewBinder {
@@ -99,15 +103,20 @@ object KeyguardClockViewBinder {
launch {
if (!MigrateClocksToBlueprint.isEnabled) return@launch
- viewModel.isAodIconsVisible.collect {
- viewModel.currentClock.value?.let {
- if (
- viewModel.isLargeClockVisible.value && it.config.useCustomClockScene
- ) {
- blueprintInteractor.refreshBlueprint(Type.DefaultTransition)
+ combine(
+ viewModel.hasAodIcons,
+ rootViewModel.isNotifIconContainerVisible.map { it.value }
+ ) { hasIcon, isVisible ->
+ hasIcon && isVisible
+ }
+ .distinctUntilChanged()
+ .collect { _ ->
+ viewModel.currentClock.value?.let {
+ if (it.config.useCustomClockScene) {
+ blueprintInteractor.refreshBlueprint(Type.DefaultTransition)
+ }
}
}
- }
}
launch {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index 34a1da54c123..0637bba9f1de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -45,6 +45,7 @@ import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockFaceLayout
import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
+import com.android.systemui.util.ui.value
import dagger.Lazy
import javax.inject.Inject
@@ -70,6 +71,7 @@ constructor(
private val rootViewModel: KeyguardRootViewModel,
) : KeyguardSection() {
override fun addViews(constraintLayout: ConstraintLayout) {}
+
override fun bindData(constraintLayout: ConstraintLayout) {
if (!MigrateClocksToBlueprint.isEnabled) {
return
@@ -121,35 +123,39 @@ constructor(
private fun getTargetClockFace(clock: ClockController): ClockFaceLayout =
if (keyguardClockViewModel.isLargeClockVisible.value) clock.largeClock.layout
else clock.smallClock.layout
+
private fun getNonTargetClockFace(clock: ClockController): ClockFaceLayout =
if (keyguardClockViewModel.isLargeClockVisible.value) clock.smallClock.layout
else clock.largeClock.layout
fun constrainWeatherClockDateIconsBarrier(constraints: ConstraintSet) {
constraints.apply {
- if (keyguardClockViewModel.isAodIconsVisible.value) {
+ createBarrier(
+ R.id.weather_clock_bc_smartspace_bottom,
+ Barrier.BOTTOM,
+ getDimen(ENHANCED_SMARTSPACE_HEIGHT),
+ (custR.id.weather_clock_time)
+ )
+ if (
+ rootViewModel.isNotifIconContainerVisible.value.value &&
+ keyguardClockViewModel.hasAodIcons.value
+ ) {
createBarrier(
R.id.weather_clock_date_and_icons_barrier_bottom,
Barrier.BOTTOM,
0,
- *intArrayOf(sharedR.id.bc_smartspace_view, R.id.aod_notification_icon_container)
+ *intArrayOf(
+ R.id.aod_notification_icon_container,
+ R.id.weather_clock_bc_smartspace_bottom
+ )
)
} else {
- if (smartspaceViewModel.bcSmartspaceVisibility.value == VISIBLE) {
- createBarrier(
- R.id.weather_clock_date_and_icons_barrier_bottom,
- Barrier.BOTTOM,
- 0,
- (sharedR.id.bc_smartspace_view)
- )
- } else {
- createBarrier(
- R.id.weather_clock_date_and_icons_barrier_bottom,
- Barrier.BOTTOM,
- getDimen(ENHANCED_SMARTSPACE_HEIGHT),
- (R.id.lockscreen_clock_view)
- )
- }
+ createBarrier(
+ R.id.weather_clock_date_and_icons_barrier_bottom,
+ Barrier.BOTTOM,
+ 0,
+ *intArrayOf(R.id.weather_clock_bc_smartspace_bottom)
+ )
}
}
}
@@ -198,6 +204,7 @@ constructor(
companion object {
private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height"
private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height"
+
fun getDimen(context: Context, name: String): Int {
val res = context.packageManager.getResourcesForApplication(context.packageName)
val id = res.getIdentifier(name, "dimen", context.packageName)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index f5c521a3d8c7..573b75e623fb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -31,7 +31,6 @@ import com.android.systemui.keyguard.shared.model.ClockSizeSetting
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
-import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
import javax.inject.Inject
@@ -50,7 +49,6 @@ constructor(
keyguardClockInteractor: KeyguardClockInteractor,
@Application private val applicationScope: CoroutineScope,
aodNotificationIconViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
- notifsKeyguardInteractor: NotificationsKeyguardInteractor,
@get:VisibleForTesting val shadeInteractor: ShadeInteractor,
private val systemBarUtils: SystemBarUtilsProxy,
configurationInteractor: ConfigurationInteractor,
@@ -90,14 +88,13 @@ constructor(
currentClock?.let { clock ->
val face = if (isLargeClock) clock.largeClock else clock.smallClock
face.config.hasCustomWeatherDataDisplay
- }
- ?: false
+ } ?: false
}
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = currentClock.value?.largeClock?.config?.hasCustomWeatherDataDisplay
- ?: false
+ initialValue =
+ currentClock.value?.largeClock?.config?.hasCustomWeatherDataDisplay ?: false
)
val clockShouldBeCentered: StateFlow<Boolean> =
@@ -109,15 +106,14 @@ constructor(
// To translate elements below smartspace in weather clock to avoid overlapping between date
// element in weather clock and aod icons
- val isAodIconsVisible: StateFlow<Boolean> = combine(aodNotificationIconViewModel.icons.map {
- it.visibleIcons.isNotEmpty()
- }, notifsKeyguardInteractor.areNotificationsFullyHidden) { hasIcons, visible ->
- hasIcons && visible
- }.stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false
- )
+ val hasAodIcons: StateFlow<Boolean> =
+ aodNotificationIconViewModel.icons
+ .map { it.visibleIcons.isNotEmpty() }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false
+ )
val currentClockLayout: StateFlow<ClockLayout> =
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index e7c2a454e16c..bda006915c94 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -17,6 +17,7 @@
package com.android.systemui.media;
import android.annotation.Nullable;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -123,9 +124,13 @@ public class RingtonePlayer implements CoreStartable {
boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig)
throws RemoteException {
if (LOGD) {
- Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
- + Binder.getCallingUid() + ")");
+ Log.d(TAG, "play(token=" + token + ", uri=" + uri
+ + ", uid=" + Binder.getCallingUid()
+ + ") uriUserId=" + ContentProvider.getUserIdFromUri(uri)
+ + " callingUserId=" + Binder.getCallingUserHandle().getIdentifier());
}
+ enforceUriUserId(uri);
+
Client client;
synchronized (mClients) {
client = mClients.get(token);
@@ -207,6 +212,7 @@ public class RingtonePlayer implements CoreStartable {
@Override
public String getTitle(Uri uri) {
+ enforceUriUserId(uri);
final UserHandle user = Binder.getCallingUserHandle();
return Ringtone.getTitle(getContextForUser(user), uri,
false /*followSettingsUri*/, false /*allowRemote*/);
@@ -239,6 +245,25 @@ public class RingtonePlayer implements CoreStartable {
}
throw new SecurityException("Uri is not ringtone, alarm, or notification: " + uri);
}
+
+ /**
+ * Must be called from the Binder calling thread.
+ * Ensures caller is from the same userId as the content they're trying to access.
+ * @param uri the URI to check
+ * @throws SecurityException when non-system call or userId in uri differs from the
+ * caller's userId
+ */
+ private void enforceUriUserId(Uri uri) throws SecurityException {
+ final int uriUserId = ContentProvider.getUserIdFromUri(uri);
+ final int callerUserId = Binder.getCallingUserHandle().getIdentifier();
+ // for a non-system call, verify the URI to play belongs to the same user as the caller
+ if (UserHandle.isApp(Binder.getCallingUid()) && uriUserId != callerUserId) {
+ throw new SecurityException("Illegal access to uri=" + uri
+ + " content associated with user=" + uriUserId
+ + ", request originates from user=" + callerUserId);
+ }
+ }
+
};
private Context getContextForUser(UserHandle user) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
index 846c596a238d..69a157f19ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
@@ -585,7 +585,8 @@ public class MediaControlPanel {
/* intentSentUiThreadCallback = */ null,
buildLaunchAnimatorController(mMediaViewHolder.getPlayer()),
/* fillIntent = */ null,
- /* extraOptions = */ null);
+ /* extraOptions = */ null,
+ /* customMessage */ null);
} else {
try {
ActivityOptions opts = ActivityOptions.makeBasic();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
index 4c210804b0c0..8c75cf001441 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.base.viewmodel
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
@@ -61,6 +62,7 @@ sealed interface QSTileViewModelFactory<T> {
private val qsTileConfigProvider: QSTileConfigProvider,
private val systemClock: SystemClock,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ @UiBackground private val uiBackgroundDispatcher: CoroutineDispatcher,
private val customTileComponentBuilder: CustomTileComponent.Builder,
) : QSTileViewModelFactory<CustomTileDataModel> {
@@ -86,6 +88,7 @@ sealed interface QSTileViewModelFactory<T> {
qsTileLogger,
systemClock,
backgroundDispatcher,
+ uiBackgroundDispatcher,
component.coroutineScope(),
)
}
@@ -106,6 +109,7 @@ sealed interface QSTileViewModelFactory<T> {
private val qsTileConfigProvider: QSTileConfigProvider,
private val systemClock: SystemClock,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ @UiBackground private val uiBackgroundDispatcher: CoroutineDispatcher,
private val coroutineScopeFactory: QSTileCoroutineScopeFactory,
) : QSTileViewModelFactory<T> {
@@ -136,6 +140,7 @@ sealed interface QSTileViewModelFactory<T> {
qsTileLogger,
systemClock,
backgroundDispatcher,
+ uiBackgroundDispatcher,
coroutineScopeFactory.create(),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
index 8782524cf250..9e84f01c6bc4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
@@ -40,6 +40,7 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -59,7 +60,9 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/**
* Provides a hassle-free way to implement new tiles according to current System UI architecture
@@ -81,6 +84,7 @@ class QSTileViewModelImpl<DATA_TYPE>(
private val qsTileLogger: QSTileLogger,
private val systemClock: SystemClock,
private val backgroundDispatcher: CoroutineDispatcher,
+ uiBackgroundDispatcher: CoroutineDispatcher,
private val tileScope: CoroutineScope,
) : QSTileViewModel, Dumpable {
@@ -93,18 +97,16 @@ class QSTileViewModelImpl<DATA_TYPE>(
private val tileData: SharedFlow<DATA_TYPE> = createTileDataFlow()
- override val state: SharedFlow<QSTileState> =
+ override val state: StateFlow<QSTileState?> =
tileData
.map { data ->
- mapper().map(config, data).also { state ->
- qsTileLogger.logStateUpdate(spec, state, data)
- }
+ withContext(uiBackgroundDispatcher) { mapper().map(config, data) }
+ .also { state -> qsTileLogger.logStateUpdate(spec, state, data) }
}
- .flowOn(backgroundDispatcher)
- .shareIn(
+ .stateIn(
tileScope,
SharingStarted.WhileSubscribed(),
- replay = 1,
+ null,
)
override val isAvailable: StateFlow<Boolean> =
users
@@ -147,26 +149,26 @@ class QSTileViewModelImpl<DATA_TYPE>(
private fun createTileDataFlow(): SharedFlow<DATA_TYPE> =
users
- .flatMapLatest { user ->
- val updateTriggers =
- merge(
- userInputFlow(user),
- forceUpdates
- .map { DataUpdateTrigger.ForceUpdate }
- .onEach { qsTileLogger.logForceUpdate(spec) },
- )
- .onStart {
- emit(DataUpdateTrigger.InitialRequest)
- qsTileLogger.logInitialRequest(spec)
- }
- .shareIn(tileScope, SharingStarted.WhileSubscribed())
- tileDataInteractor()
- .tileData(user, updateTriggers)
- // combine makes sure updateTriggers is always listened even if
- // tileDataInteractor#tileData doesn't flatMapLatest on it
- .combine(updateTriggers) { data, _ -> data }
- .cancellable()
- .flowOn(backgroundDispatcher)
+ .transformLatest { user ->
+ coroutineScope {
+ val updateTriggers: Flow<DataUpdateTrigger> =
+ merge(
+ userInputFlow(user),
+ forceUpdates
+ .map { DataUpdateTrigger.ForceUpdate }
+ .onEach { qsTileLogger.logForceUpdate(spec) },
+ )
+ .onStart { qsTileLogger.logInitialRequest(spec) }
+ .stateIn(this, SharingStarted.Eagerly, DataUpdateTrigger.InitialRequest)
+ tileDataInteractor()
+ .tileData(user, updateTriggers)
+ // combine makes sure updateTriggers is always listened even if
+ // tileDataInteractor#tileData doesn't transformLatest on it
+ .combine(updateTriggers) { data, _ -> data }
+ .cancellable()
+ .flowOn(backgroundDispatcher)
+ .collect { emit(it) }
+ }
}
.distinctUntilChanged()
.shareIn(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt
index 1e8ce588b4e0..233e913a27aa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt
@@ -30,11 +30,9 @@ import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.stateIn
/** Observes one qr scanner state changes providing the [QRCodeScannerTileModel]. */
class QRCodeScannerTileDataInteractor
@@ -66,11 +64,6 @@ constructor(
}
.onStart { emit(generateModel()) }
.flowOn(bgCoroutineContext)
- .stateIn(
- scope,
- SharingStarted.WhileSubscribed(),
- QRCodeScannerTileModel.TemporarilyUnavailable
- )
override fun availability(user: UserHandle): Flow<Boolean> =
flowOf(qrController.isCameraAvailable)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
index ae6c0143f603..30247c41200f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
@@ -54,18 +54,21 @@ data class QSTileState(
resources: Resources,
theme: Theme,
config: QSTileUIConfig,
- build: Builder.() -> Unit
+ builder: Builder.() -> Unit
): QSTileState {
val iconDrawable = resources.getDrawable(config.iconRes, theme)
return build(
{ Icon.Loaded(iconDrawable, null) },
resources.getString(config.labelRes),
- build,
+ builder,
)
}
- fun build(icon: () -> Icon?, label: CharSequence, build: Builder.() -> Unit): QSTileState =
- Builder(icon, label).apply(build).build()
+ fun build(
+ icon: () -> Icon?,
+ label: CharSequence,
+ builder: Builder.() -> Unit
+ ): QSTileState = Builder(icon, label).apply { builder() }.build()
}
enum class ActivationState(val legacyState: Int) {
@@ -107,7 +110,9 @@ data class QSTileState(
sealed interface SideViewIcon {
data class Custom(val icon: Icon) : SideViewIcon
+
data object Chevron : SideViewIcon
+
data object None : SideViewIcon
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt
index 226e2fa0549f..b1b0001b6361 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt
@@ -17,7 +17,6 @@
package com.android.systemui.qs.tiles.viewmodel
import android.os.UserHandle
-import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
/**
@@ -31,7 +30,7 @@ import kotlinx.coroutines.flow.StateFlow
interface QSTileViewModel {
/** State of the tile to be shown by the view. */
- val state: SharedFlow<QSTileState>
+ val state: StateFlow<QSTileState?>
val config: QSTileConfig
@@ -62,9 +61,7 @@ interface QSTileViewModel {
}
/**
- * Returns the immediate state of the tile or null if the state haven't been collected yet. Favor
- * reactive consumption over the [currentState], because there is no guarantee that current value
- * would be available at any time.
+ * Returns the immediate state of the tile or null if the state haven't been collected yet.
*/
val QSTileViewModel.currentState: QSTileState?
- get() = state.replayCache.lastOrNull()
+ get() = state.value
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
index 7be13e08f972..ba0a8d694a14 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
@@ -38,6 +38,7 @@ import java.util.function.Supplier
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collectIndexed
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
@@ -168,6 +169,7 @@ constructor(
if (listeningClients.size == 1) {
stateJob =
qsTileViewModel.state
+ .filterNotNull()
.map { mapState(context, it, qsTileViewModel.config) }
.onEach { legacyState ->
synchronized(callbacks) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt
index 64f1fd3d6416..00b7e61eb1c6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt
@@ -17,12 +17,11 @@
package com.android.systemui.qs.tiles.viewmodel
import android.os.UserHandle
-import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
object StubQSTileViewModel : QSTileViewModel {
- override val state: SharedFlow<QSTileState>
+ override val state: StateFlow<QSTileState?>
get() = error("Don't call stubs")
override val config: QSTileConfig
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 23faf7d52fed..4b82e0f96560 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -62,6 +62,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
@@ -177,7 +178,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private boolean mBound;
private boolean mIsEnabled;
- private boolean mIsNonPrimaryUser;
+ private boolean mIsSystemOrVisibleBgUser;
private int mCurrentBoundedUserId = -1;
private boolean mInputFocusTransferStarted;
private float mInputFocusTransferStartY;
@@ -629,6 +630,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
SysUiState sysUiState,
Provider<SceneInteractor> sceneInteractor,
UserTracker userTracker,
+ UserManager userManager,
WakefulnessLifecycle wakefulnessLifecycle,
UiEventLogger uiEventLogger,
DisplayTracker displayTracker,
@@ -639,10 +641,18 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder,
BroadcastDispatcher broadcastDispatcher
) {
- // b/241601880: This component shouldn't be running for a non-primary user
- mIsNonPrimaryUser = !Process.myUserHandle().equals(UserHandle.SYSTEM);
- if (mIsNonPrimaryUser) {
- Log.wtf(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable());
+ // b/241601880: This component should only be running for primary users or
+ // secondaryUsers when visibleBackgroundUsers are supported.
+ boolean isSystemUser = Process.myUserHandle().equals(UserHandle.SYSTEM);
+ boolean isVisibleBackgroundUser =
+ userManager.isVisibleBackgroundUsersSupported() && !userManager.isUserForeground();
+ if (!isSystemUser && isVisibleBackgroundUser) {
+ Log.d(TAG_OPS, "Initialization for visibleBackgroundUser");
+ }
+ mIsSystemOrVisibleBgUser = isSystemUser || isVisibleBackgroundUser;
+ if (!mIsSystemOrVisibleBgUser) {
+ Log.wtf(TAG_OPS, "Unexpected initialization for non-system foreground user",
+ new Throwable());
}
mContext = context;
@@ -833,11 +843,12 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
private void internalConnectToCurrentUser(String reason) {
- if (mIsNonPrimaryUser) {
+ if (!mIsSystemOrVisibleBgUser) {
// This should not happen, but if any per-user SysUI component has a dependency on OPS,
// then this could get triggered
- Log.w(TAG_OPS, "Skipping connection to overview service due to non-primary user "
- + "caller");
+ Log.w(TAG_OPS,
+ "Skipping connection to overview service due to non-system foreground user "
+ + "caller");
return;
}
disconnectFromLauncherService(reason);
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 25a9e9e6f9f2..ef011945b5c8 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -167,6 +167,10 @@ constructor(
initialValue = isVisibleInternal()
)
+ /** Whether there's an ongoing remotely-initiated user interaction. */
+ val isRemoteUserInteractionOngoing: StateFlow<Boolean> =
+ repository.isRemoteUserInteractionOngoing
+
/**
* The amount of transition into or out of the given [scene].
*
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 d380251d8b7e..a28222e9cea0 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
@@ -26,17 +26,12 @@ import com.android.systemui.classifier.domain.interactor.FalsingInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
/** Models UI state for the scene container. */
@SysUISingleton
@@ -46,7 +41,6 @@ constructor(
private val sceneInteractor: SceneInteractor,
private val falsingInteractor: FalsingInteractor,
private val powerInteractor: PowerInteractor,
- scenes: Set<@JvmSuppressWildcards Scene>,
) {
/**
* Keys of all scenes in the container.
@@ -62,25 +56,6 @@ constructor(
/** Whether the container is visible. */
val isVisible: StateFlow<Boolean> = sceneInteractor.isVisible
- private val destinationScenesBySceneKey =
- scenes.associate { scene ->
- scene.key to scene.destinationScenes.flatMapLatestConflated { replaceSceneFamilies(it) }
- }
-
- fun currentDestinationScenes(
- scope: CoroutineScope,
- ): StateFlow<Map<UserAction, UserActionResult>> {
- return currentScene
- .flatMapLatestConflated { currentSceneKey ->
- checkNotNull(destinationScenesBySceneKey[currentSceneKey])
- }
- .stateIn(
- scope = scope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = emptyMap(),
- )
- }
-
/**
* Binds the given flow so the system remembers it.
*
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 16d10abb7d99..6b4e44fed0cd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1095,7 +1095,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
initBottomArea();
mWakeUpCoordinator.setStackScroller(mNotificationStackScrollLayoutController);
- mPulseExpansionHandler.setUp(mNotificationStackScrollLayoutController);
mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index ce321dcc03fd..5065baa04623 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -119,7 +119,7 @@ constructor(
if (delayed) {
scope.launch {
delay(125)
- animateCollapseShadeInternal()
+ withContext(mainDispatcher) { animateCollapseShadeInternal() }
}
} else {
animateCollapseShadeInternal()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
index 3f4bcba288b7..354d379d2ea2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
@@ -32,6 +32,8 @@ import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.transition.ScrimShadeTransitionController
+import com.android.systemui.statusbar.PulseExpansionHandler
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.policy.SplitShadeStateController
import javax.inject.Inject
import javax.inject.Provider
@@ -56,6 +58,8 @@ constructor(
private val sceneInteractorProvider: Provider<SceneInteractor>,
private val panelExpansionInteractorProvider: Provider<PanelExpansionInteractor>,
private val shadeExpansionStateManager: ShadeExpansionStateManager,
+ private val pulseExpansionHandler: PulseExpansionHandler,
+ private val nsslc: NotificationStackScrollLayoutController,
) : CoreStartable {
override fun start() {
@@ -63,6 +67,7 @@ constructor(
hydrateShadeExpansionStateManager()
logTouchesTo(touchLog)
scrimShadeTransitionController.init()
+ pulseExpansionHandler.setUp(nsslc)
}
private fun hydrateShadeExpansionStateManager() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 2f3fc729464e..c1eb8bcfa493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -1276,7 +1276,7 @@ public class KeyguardIndicationController {
mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull;
mPowerPluggedInWireless = status.isPluggedInWireless() && isChargingOrFull;
mPowerPluggedInDock = status.isPluggedInDock() && isChargingOrFull;
- mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
+ mPowerPluggedIn = isPowerPluggedIn(status, isChargingOrFull);
mPowerCharged = status.isCharged();
mChargingWattage = status.maxChargingWattage;
mChargingSpeed = status.getChargingSpeed(mContext);
@@ -1562,6 +1562,11 @@ public class KeyguardIndicationController {
return status.isBatteryDefender();
}
+ /** Return true if the device has power plugged in. */
+ protected boolean isPowerPluggedIn(BatteryStatus status, boolean isChargingOrFull) {
+ return status.isPluggedIn() && isChargingOrFull;
+ }
+
private boolean isCurrentUser(int userId) {
return getCurrentUser() == userId;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index fae0a4681493..97266c57ba09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -126,6 +126,7 @@ constructor(
animationController: ActivityTransitionAnimator.Controller?,
fillInIntent: Intent?,
extraOptions: Bundle?,
+ customMessage: String?,
) {
activityStarterInternal.startPendingIntentDismissingKeyguard(
intent = intent,
@@ -135,6 +136,7 @@ constructor(
dismissShade = dismissShade,
fillInIntent = fillInIntent,
extraOptions = extraOptions,
+ customMessage = customMessage,
)
}
@@ -319,11 +321,13 @@ constructor(
intent: Intent,
onlyProvisioned: Boolean,
dismissShade: Boolean,
+ customMessage: String?,
) {
activityStarterInternal.startActivityDismissingKeyguard(
intent = intent,
onlyProvisioned = onlyProvisioned,
dismissShade = dismissShade,
+ customMessage = customMessage,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt
index cff9f5edad08..93ce6e8561ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt
@@ -42,6 +42,7 @@ interface ActivityStarterInternal {
skipLockscreenChecks: Boolean = false,
fillInIntent: Intent? = null,
extraOptions: Bundle? = null,
+ customMessage: String? = null,
)
/** Starts an activity after dismissing keyguard. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt
index dbb95e602e43..ae98e1d60589 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt
@@ -42,7 +42,8 @@ class ActivityStarterInternalImpl @Inject constructor() : ActivityStarterInterna
showOverLockscreen: Boolean,
skipLockscreenChecks: Boolean,
fillInIntent: Intent?,
- extraOptions: Bundle?
+ extraOptions: Bundle?,
+ customMessage: String?,
) {
TODO("Not yet implemented b/308819693")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 28117e9c9f93..491db307ae63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1329,7 +1329,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
.putExtra(Intent.EXTRA_TEXT, message.toString()),
"Share rejected touch report")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
- true /* onlyProvisioned */, true /* dismissShade */);
+ true /* onlyProvisioned */,
+ true /* dismissShade */,
+ null /* customMessage */);
});
}
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 e96326a945b4..bcb613fe2b8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
@@ -232,6 +232,7 @@ constructor(
skipLockscreenChecks: Boolean,
fillInIntent: Intent?,
extraOptions: Bundle?,
+ customMessage: String?,
) {
val animationController =
if (associatedView is ExpandableNotificationRow) {
@@ -340,6 +341,7 @@ constructor(
afterKeyguardGone = willLaunchResolverActivity,
dismissShade = collapse,
willAnimateOnKeyguard = animate,
+ customMessage = customMessage,
)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 02187844d6da..45aee5b8c22f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -29,6 +29,7 @@ import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import android.view.WindowInsets;
+import androidx.annotation.VisibleForTesting;
import com.android.compose.animation.scene.ObservableTransitionState;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.Dumpable;
@@ -69,6 +70,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
private boolean mIsStatusBarExpanded = false;
private boolean mIsIdleOnGone = true;
+ private boolean mIsRemoteUserInteractionOngoing = false;
private boolean mShouldAdjustInsets = false;
private View mNotificationShadeWindowView;
private View mNotificationPanelView;
@@ -133,6 +135,9 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
javaAdapter.alwaysCollectFlow(
sceneInteractor.get().getTransitionState(),
this::onSceneChanged);
+ javaAdapter.alwaysCollectFlow(
+ sceneInteractor.get().isRemoteUserInteractionOngoing(),
+ this::onRemoteUserInteractionOngoingChanged);
} else {
javaAdapter.alwaysCollectFlow(
shadeInteractor.isAnyExpanded(),
@@ -179,6 +184,13 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
}
}
+ private void onRemoteUserInteractionOngoingChanged(Boolean ongoing) {
+ if (ongoing != mIsRemoteUserInteractionOngoing) {
+ mIsRemoteUserInteractionOngoing = ongoing;
+ updateTouchableRegion();
+ }
+ }
+
/**
* Calculates the touch region needed for heads up notifications, taking into consideration
* any existing display cutouts (notch)
@@ -276,13 +288,15 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
* Helper to let us know when calculating the region is not needed because we know the entire
* screen needs to be touchable.
*/
- private boolean shouldMakeEntireScreenTouchable() {
+ @VisibleForTesting
+ boolean shouldMakeEntireScreenTouchable() {
// The touchable region is always the full area when expanded, whether we're showing the
// shade or the bouncer. It's also fully touchable when the screen off animation is playing
// since we don't want stray touches to go through the light reveal scrim to whatever is
// underneath.
return mIsStatusBarExpanded
- || (SceneContainerFlag.isEnabled() && !mIsIdleOnGone)
+ || (SceneContainerFlag.isEnabled()
+ && (!mIsIdleOnGone || mIsRemoteUserInteractionOngoing))
|| mPrimaryBouncerInteractor.isShowing().getValue()
|| mAlternateBouncerInteractor.isVisibleState()
|| mUnlockedScreenOffAnimationController.isAnimationPlaying();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 3d8090d70faa..aced0be4cc46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -14,6 +14,8 @@
package com.android.systemui.statusbar.phone.fragment;
+import static com.android.systemui.statusbar.phone.fragment.StatusBarVisibilityModel.createHiddenModel;
+
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.Fragment;
@@ -46,6 +48,7 @@ import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
@@ -205,6 +208,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private boolean mTransitionFromLockscreenToDreamStarted = false;
/**
+ * True if the current scene allows the home status bar (aka this status bar) to be shown, and
+ * false if the current scene should never show the home status bar. Only used if the scene
+ * container is enabled.
+ */
+ private boolean mHomeStatusBarAllowedByScene = true;
+
+ /**
* True if there's an active ongoing activity that should be showing a chip and false otherwise.
*/
private boolean mHasOngoingActivity;
@@ -522,6 +532,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mHasOngoingActivity = hasOngoingActivity;
updateStatusBarVisibilities(/* animate= */ true);
}
+
+ @Override
+ public void onIsHomeStatusBarAllowedBySceneChanged(
+ boolean isHomeStatusBarAllowedByScene) {
+ mHomeStatusBarAllowedByScene = isHomeStatusBarAllowedByScene;
+ updateStatusBarVisibilities(/* animate= */ true);
+ }
};
@Override
@@ -580,17 +597,22 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
boolean headsUpVisible =
mStatusBarFragmentComponent.getHeadsUpAppearanceController().shouldBeVisible();
- if (!mKeyguardStateController.isLaunchTransitionFadingAway()
- && !mKeyguardStateController.isKeyguardFadingAway()
- && shouldHideStatusBar()
- && !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD
- && headsUpVisible)) {
- // Hide everything
- return new StatusBarVisibilityModel(
- /* showClock= */ false,
- /* showNotificationIcons= */ false,
- /* showOngoingActivityChip= */ false,
- /* showSystemInfo= */ false);
+ if (SceneContainerFlag.isEnabled()) {
+ // With the scene container, only use the value calculated by the view model to
+ // determine if the status bar needs hiding.
+ if (!mHomeStatusBarAllowedByScene) {
+ return createHiddenModel();
+ }
+ } else {
+ // Without the scene container, use our old, mildly-hacky logic to determine if the
+ // status bar needs hiding.
+ if (!mKeyguardStateController.isLaunchTransitionFadingAway()
+ && !mKeyguardStateController.isKeyguardFadingAway()
+ && shouldHideStatusBar()
+ && !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+ && headsUpVisible)) {
+ return createHiddenModel();
+ }
}
boolean showClock = externalModel.getShowClock() && !headsUpVisible;
@@ -698,7 +720,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
private void hideEndSideContent(boolean animate) {
- if (!animate) {
+ if (!animate || !mAnimationsEnabled) {
mEndSideAlphaController.setAlpha(/*alpha*/ 0f, SOURCE_OTHER);
} else {
mEndSideAlphaController.animateToAlpha(/*alpha*/ 0f, SOURCE_OTHER, FADE_OUT_DURATION,
@@ -707,7 +729,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
private void showEndSideContent(boolean animate) {
- if (!animate) {
+ if (!animate || !mAnimationsEnabled) {
mEndSideAlphaController.setAlpha(1f, SOURCE_OTHER);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
index fe24faece1d3..9255e6323d31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
@@ -36,6 +36,17 @@ data class StatusBarVisibilityModel(
return createModelFromFlags(DISABLE_NONE, DISABLE2_NONE)
}
+ /** Creates a model that hides every piece of the status bar. */
+ @JvmStatic
+ fun createHiddenModel(): StatusBarVisibilityModel {
+ return StatusBarVisibilityModel(
+ showClock = false,
+ showNotificationIcons = false,
+ showOngoingActivityChip = false,
+ showSystemInfo = false,
+ )
+ }
+
/**
* Given a set of disabled flags, converts them into the correct visibility statuses.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index 944965950dce..62bd8ad4317c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -349,6 +349,7 @@ class MobileConnectionRepositoryImpl(
false
}
}
+ .flowOn(bgDispatcher)
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val carrierId =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index de36e407da84..ae1898bc479c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -30,6 +30,7 @@ import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.chips.ui.binder.ChipChronometerBinder
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
@@ -136,6 +137,14 @@ class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBa
}
}
}
+
+ if (SceneContainerFlag.isEnabled) {
+ launch {
+ viewModel.isHomeStatusBarAllowedByScene.collect {
+ listener.onIsHomeStatusBarAllowedBySceneChanged(it)
+ }
+ }
+ }
}
}
}
@@ -259,4 +268,10 @@ interface StatusBarVisibilityChangeListener {
/** Called when the status of the ongoing activity chip (active or not active) has changed. */
fun onOngoingActivityStatusChanged(hasOngoingActivity: Boolean)
+
+ /**
+ * Called when the scene state has changed such that the home status bar is newly allowed or no
+ * longer allowed. See [CollapsedStatusBarViewModel.isHomeStatusBarAllowedByScene].
+ */
+ fun onIsHomeStatusBarAllowedBySceneChanged(isHomeStatusBarAllowedByScene: Boolean)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
index 95d924889301..d6c3834c1bf1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
@@ -24,6 +24,9 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
@@ -65,6 +68,12 @@ interface CollapsedStatusBarViewModel {
val ongoingActivityChip: StateFlow<OngoingActivityChipModel>
/**
+ * True if the current scene can show the home status bar (aka this status bar), and false if
+ * the current scene should never show the home status bar.
+ */
+ val isHomeStatusBarAllowedByScene: StateFlow<Boolean>
+
+ /**
* Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where
* status bar and navigation icons dim. In this mode, a notification dot appears where the
* notification icons would appear if they would be shown outside of this mode.
@@ -83,6 +92,8 @@ constructor(
private val lightsOutInteractor: LightsOutInteractor,
private val notificationsInteractor: ActiveNotificationsInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ sceneInteractor: SceneInteractor,
+ sceneContainerOcclusionInteractor: SceneContainerOcclusionInteractor,
ongoingActivityChipsViewModel: OngoingActivityChipsViewModel,
@Application coroutineScope: CoroutineScope,
) : CollapsedStatusBarViewModel {
@@ -99,6 +110,20 @@ constructor(
override val ongoingActivityChip = ongoingActivityChipsViewModel.chip
+ override val isHomeStatusBarAllowedByScene: StateFlow<Boolean> =
+ combine(
+ sceneInteractor.currentScene,
+ sceneContainerOcclusionInteractor.invisibleDueToOcclusion,
+ ) { currentScene, isOccluded ->
+ // All scenes have their own status bars, so we should only show the home status bar
+ // if we're not in a scene. The one exception: If the scene is occluded, then the
+ // occluding app needs to show the status bar. (Fullscreen apps actually won't show
+ // the status bar but that's handled with the rest of our fullscreen app logic,
+ // which lives elsewhere.)
+ currentScene == Scenes.Gone || isOccluded
+ }
+ .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), initialValue = false)
+
override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> =
if (NotificationsLiveDataStoreRefactor.isUnexpectedlyInLegacyMode()) {
emptyFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
index d10554f9c254..b836016eb2ef 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -20,13 +20,16 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Tracing
+import com.android.systemui.dagger.qualifiers.UiBackground
import dagger.Module
import dagger.Provides
+import java.util.concurrent.Executor
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.newFixedThreadPoolContext
import kotlinx.coroutines.plus
@@ -83,4 +86,25 @@ class SysUICoroutinesModule {
): CoroutineContext {
return bgCoroutineDispatcher + tracingCoroutineContext
}
+
+ /** Coroutine dispatcher for background operations on for UI. */
+ @Provides
+ @SysUISingleton
+ @UiBackground
+ @Deprecated(
+ "Use @UiBackground CoroutineContext instead",
+ ReplaceWith("uiBgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+ )
+ fun uiBgDispatcher(@UiBackground uiBgExecutor: Executor): CoroutineDispatcher =
+ uiBgExecutor.asCoroutineDispatcher()
+
+ @Provides
+ @UiBackground
+ @SysUISingleton
+ fun uiBgCoroutineContext(
+ @Tracing tracingCoroutineContext: CoroutineContext,
+ @UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher,
+ ): CoroutineContext {
+ return uiBgCoroutineDispatcher + tracingCoroutineContext
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index cb61534b2255..8457bdb2d0ff 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -51,7 +51,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.flags.FeatureFlags;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
index 64c162f3d983..639b53bfb95b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
@@ -46,6 +46,7 @@ import android.view.WindowMetrics;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleCoroutineScope;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
@@ -159,7 +160,9 @@ public class TouchMonitorTest extends SysuiTestCase {
ArgumentCaptor<LifecycleObserver> observerCaptor =
ArgumentCaptor.forClass(LifecycleObserver.class);
verify(mLifecycleRegistry, atLeast(1)).addObserver(observerCaptor.capture());
- mLifecycleObservers.addAll(observerCaptor.getAllValues());
+ mLifecycleObservers.addAll(observerCaptor.getAllValues().stream().filter(
+ lifecycleObserver -> !(lifecycleObserver instanceof LifecycleCoroutineScope))
+ .toList());
updateLifecycle(Lifecycle.State.RESUMED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
index a77072217873..fbfe41f57927 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
@@ -1799,6 +1799,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
any(),
eq(null),
eq(null),
+ eq(null),
)
verify(activityStarter, never()).postStartActivityDismissingKeyguard(eq(clickIntent), any())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
index 42b81de92af7..c918ed82604c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
@@ -97,6 +97,7 @@ class QSTileViewModelImplTest : SysuiTestCase() {
qsTileLogger,
FakeSystemClock(),
testCoroutineDispatcher,
+ testCoroutineDispatcher,
testScope.backgroundScope,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index 6e6e31177564..e1c39117f6c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -23,6 +23,7 @@ import android.content.pm.ResolveInfo
import android.os.PowerManager
import android.os.Process
import android.os.UserHandle
+import android.os.UserManager
import android.testing.TestableContext
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -108,6 +109,7 @@ class OverviewProxyServiceTest : SysuiTestCase() {
@Mock private lateinit var navModeController: NavigationModeController
@Mock private lateinit var statusBarWinController: NotificationShadeWindowController
@Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var userManager: UserManager
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var sysuiUnlockAnimationController: KeyguardUnlockAnimationController
@Mock
@@ -199,11 +201,12 @@ class OverviewProxyServiceTest : SysuiTestCase() {
}
@Test
- fun connectToOverviewService_primaryUser_expectBindService() {
+ fun connectToOverviewService_primaryUserNoVisibleBgUsersSupported_expectBindService() {
val mockitoSession =
ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking()
try {
`when`(Process.myUserHandle()).thenReturn(UserHandle.SYSTEM)
+ `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false)
val spyContext = spy(context)
val ops = createOverviewProxyService(spyContext)
ops.startConnectionToCurrentUser()
@@ -214,11 +217,46 @@ class OverviewProxyServiceTest : SysuiTestCase() {
}
@Test
- fun connectToOverviewService_nonPrimaryUser_expectNoBindService() {
+ fun connectToOverviewService_nonPrimaryUserNoVisibleBgUsersSupported_expectNoBindService() {
val mockitoSession =
ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking()
try {
`when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345))
+ `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false)
+ val spyContext = spy(context)
+ val ops = createOverviewProxyService(spyContext)
+ ops.startConnectionToCurrentUser()
+ verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any())
+ } finally {
+ mockitoSession.finishMocking()
+ }
+ }
+
+ @Test
+ fun connectToOverviewService_nonPrimaryBgUserVisibleBgUsersSupported_expectBindService() {
+ val mockitoSession =
+ ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking()
+ try {
+ `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345))
+ `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true)
+ `when`(userManager.isUserForeground()).thenReturn(false)
+ val spyContext = spy(context)
+ val ops = createOverviewProxyService(spyContext)
+ ops.startConnectionToCurrentUser()
+ verify(spyContext, atLeast(1)).bindServiceAsUser(any(), any(), anyInt(), any())
+ } finally {
+ mockitoSession.finishMocking()
+ }
+ }
+
+ @Test
+ fun connectToOverviewService_nonPrimaryFgUserVisibleBgUsersSupported_expectNoBindService() {
+ val mockitoSession =
+ ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking()
+ try {
+ `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345))
+ `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true)
+ `when`(userManager.isUserForeground()).thenReturn(true)
val spyContext = spy(context)
val ops = createOverviewProxyService(spyContext)
ops.startConnectionToCurrentUser()
@@ -242,6 +280,7 @@ class OverviewProxyServiceTest : SysuiTestCase() {
sysUiState,
mock(),
userTracker,
+ userManager,
wakefulnessLifecycle,
uiEventLogger,
displayTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
new file mode 100644
index 000000000000..230ddf9d25db
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
@@ -0,0 +1,116 @@
+/*
+ * 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.statusbar.phone
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.testKosmos
+import com.android.systemui.util.kotlin.getValue
+import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class StatusBarTouchableRegionManagerTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val sceneRepository = kosmos.sceneContainerRepository
+
+ private val underTest by Lazy { kosmos.statusBarTouchableRegionManager }
+
+ @Test
+ @EnableSceneContainer
+ fun entireScreenTouchable_sceneContainerEnabled_isRemoteUserInteractionOngoing() =
+ testScope.runTest {
+ sceneRepository.setTransitionState(
+ flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Gone))
+ )
+ runCurrent()
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
+
+ sceneRepository.isRemoteUserInteractionOngoing.value = true
+ runCurrent()
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isTrue()
+
+ sceneRepository.isRemoteUserInteractionOngoing.value = false
+ runCurrent()
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
+ }
+
+ @Test
+ @DisableSceneContainer
+ fun entireScreenTouchable_sceneContainerDisabled_isRemoteUserInteractionOngoing() =
+ testScope.runTest {
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
+
+ sceneRepository.isRemoteUserInteractionOngoing.value = true
+ runCurrent()
+
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun entireScreenTouchable_sceneContainerEnabled_isIdleOnGone() =
+ testScope.runTest {
+ sceneRepository.setTransitionState(
+ flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Gone))
+ )
+ runCurrent()
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
+
+ sceneRepository.setTransitionState(
+ flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Shade))
+ )
+ runCurrent()
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isTrue()
+
+ sceneRepository.setTransitionState(
+ flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Gone))
+ )
+ runCurrent()
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
+ }
+
+ @Test
+ @DisableSceneContainer
+ fun entireScreenTouchable_sceneContainerDisabled_isIdleOnGone() =
+ testScope.runTest {
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
+
+ sceneRepository.setTransitionState(
+ flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Shade))
+ )
+ runCurrent()
+
+ assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index ee27cea48565..01540e7584a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -49,6 +49,8 @@ import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.animation.AnimatorTestRule;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.DisableSceneContainer;
+import com.android.systemui.flags.EnableSceneContainer;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogcatEchoTracker;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -302,6 +304,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
@Test
+ @DisableSceneContainer
public void disable_shadeOpenAndShouldHide_everythingHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -318,6 +321,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
@Test
+ @DisableSceneContainer
public void disable_shadeOpenButNotShouldHide_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -335,6 +339,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
/** Regression test for b/279790651. */
@Test
+ @DisableSceneContainer
public void disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -376,6 +381,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
@Test
+ @DisableSceneContainer
public void disable_isTransitioningToOccluded_everythingHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -390,6 +396,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
@Test
+ @DisableSceneContainer
public void disable_wasTransitioningToOccluded_transitionFinished_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -674,6 +681,80 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
@Test
+ @EnableSceneContainer
+ public void isHomeStatusBarAllowedByScene_false_everythingHidden() {
+ resumeAndGetFragment();
+
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(false);
+
+ // THEN all views are hidden
+ assertEquals(View.GONE, getClockView().getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void isHomeStatusBarAllowedByScene_true_everythingShown() {
+ resumeAndGetFragment();
+
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(true);
+
+ // THEN all views are shown
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void disable_isHomeStatusBarAllowedBySceneFalse_disableValuesIgnored() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN the scene doesn't allow the status bar
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(false);
+
+ // BUT the disable flags want to show the status bar
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // THEN all views are hidden (the disable flags aren't respected)
+ assertEquals(View.GONE, getClockView().getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void disable_isHomeStatusBarAllowedBySceneTrue_disableValuesUsed() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN the scene does allow the status bar
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(true);
+
+ // AND the disable flags want to hide the clock
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
+
+ // THEN all views are shown except the clock (the disable flags are used)
+ assertEquals(View.GONE, getClockView().getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
+ @DisableSceneContainer
+ public void isHomeStatusBarAllowedByScene_sceneContainerDisabled_valueNotUsed() {
+ resumeAndGetFragment();
+
+ // Even if the scene says to hide the home status bar
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(false);
+
+ // The value isn't used because the scene container flag is disabled, so all views are shown
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
public void disable_isDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(true);
@@ -758,6 +839,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
@Test
+ @DisableSceneContainer
public void testStatusBarIcons_hiddenThroughoutCameraLaunch() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -779,6 +861,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
@Test
+ @DisableSceneContainer
public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index b4c6106150b2..94159bcebf47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -24,6 +24,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -36,6 +37,10 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.log.assertLogsWtf
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
@@ -84,6 +89,8 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() {
kosmos.lightsOutInteractor,
kosmos.activeNotificationsInteractor,
kosmos.keyguardTransitionInteractor,
+ kosmos.sceneInteractor,
+ kosmos.sceneContainerOcclusionInteractor,
kosmos.ongoingActivityChipsViewModel,
kosmos.applicationCoroutineScope,
)
@@ -426,6 +433,68 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() {
assertIsShareToAppChip(latest)
}
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneLockscreen_notOccluded_false() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+ kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, taskInfo = null)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneLockscreen_occluded_true() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+ kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, taskInfo = null)
+
+ assertThat(latest).isTrue()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneBouncer_false() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Bouncer)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneCommunal_false() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Communal)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneShade_false() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Shade)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneGone_true() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
+
+ assertThat(latest).isTrue()
+ }
+
private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
ActiveNotificationsStore.Builder()
.apply { notifications.forEach(::addIndividualNotif) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
index b66eed05fa0d..d3f11253fc09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
@@ -31,6 +31,8 @@ class FakeCollapsedStatusBarViewModel : CollapsedStatusBarViewModel {
override val ongoingActivityChip: MutableStateFlow<OngoingActivityChipModel> =
MutableStateFlow(OngoingActivityChipModel.Hidden)
+ override val isHomeStatusBarAllowedByScene = MutableStateFlow(false)
+
override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut
fun setNotificationLightsOut(lightsOut: Boolean) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 78d8abeb477a..a124b34cde85 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -43,7 +43,7 @@ import androidx.core.animation.AndroidXAnimatorIsolationRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.systemui.broadcast.FakeBroadcastDispatcher;
import com.android.systemui.flags.SceneContainerRule;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
index 3c62b44ed2c4..b5e6f75c7915 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
@@ -23,7 +23,6 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificationIconContainerAlwaysOnDisplayViewModel
-import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.ui.systemBarUtilsProxy
val Kosmos.keyguardClockViewModel by
@@ -32,7 +31,6 @@ val Kosmos.keyguardClockViewModel by
keyguardClockInteractor = keyguardClockInteractor,
applicationScope = applicationCoroutineScope,
aodNotificationIconViewModel = notificationIconContainerAlwaysOnDisplayViewModel,
- notifsKeyguardInteractor = notificationsKeyguardInteractor,
shadeInteractor = shadeInteractor,
systemBarUtils = systemBarUtilsProxy,
configurationInteractor = configurationInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt
index 419e7810b604..dceb8bff0ae7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt
@@ -33,7 +33,6 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import javax.inject.Provider
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
var Kosmos.newFactoryTileMap by Kosmos.Fixture { emptyMap<String, Provider<QSTileViewModel>>() }
@@ -50,7 +49,7 @@ val Kosmos.customTileViewModelFactory: QSTileViewModelFactory.Component by
instanceIdSequenceFake.newInstanceId(),
)
object : QSTileViewModel {
- override val state: SharedFlow<QSTileState> =
+ override val state: StateFlow<QSTileState?> =
MutableStateFlow(QSTileState.build({ null }, tileSpec.spec) {})
override val config: QSTileConfig = config
override val isAvailable: StateFlow<Boolean> = MutableStateFlow(true)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt
index dcfcce77942e..537be4fc2527 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt
@@ -69,6 +69,7 @@ val Kosmos.qsQRCodeScannerViewModel by
qsTileLogger,
systemClock,
testDispatcher,
+ testDispatcher,
testScope.backgroundScope,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
index b85858d915b5..79b80bc71c58 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
@@ -27,7 +27,9 @@ import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.panelExpansionInteractor
import com.android.systemui.shade.transition.ScrimShadeTransitionController
+import com.android.systemui.statusbar.notification.stack.notificationStackScrollLayoutController
import com.android.systemui.statusbar.policy.splitShadeStateController
+import com.android.systemui.statusbar.pulseExpansionHandler
import com.android.systemui.util.mockito.mock
@Deprecated("ShadeExpansionStateManager is deprecated. Remove your dependency on it instead.")
@@ -45,5 +47,7 @@ val Kosmos.shadeStartable by Fixture {
sceneInteractorProvider = { sceneInteractor },
panelExpansionInteractorProvider = { panelExpansionInteractor },
shadeExpansionStateManager = shadeExpansionStateManager,
+ pulseExpansionHandler = pulseExpansionHandler,
+ nsslc = notificationStackScrollLayoutController,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerKosmos.kt
new file mode 100644
index 000000000000..8785256de452
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerKosmos.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.statusbar.phone
+
+import android.content.applicationContext
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.notificationShadeWindowController
+import com.android.systemui.statusbar.policy.configurationController
+import com.android.systemui.statusbar.policy.headsUpManager
+import com.android.systemui.util.kotlin.JavaAdapter
+import com.android.systemui.util.mockito.mock
+import org.mockito.Mockito.mock
+
+var Kosmos.statusBarTouchableRegionManager by
+ Kosmos.Fixture {
+ StatusBarTouchableRegionManager(
+ applicationContext,
+ notificationShadeWindowController,
+ configurationController,
+ headsUpManager,
+ shadeInteractor,
+ { sceneInteractor },
+ JavaAdapter(testScope.backgroundScope),
+ mock<UnlockedScreenOffAnimationController>(),
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ )
+ }
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index fec6ff17a608..0458f535c1eb 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -28,6 +28,9 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import java.util.concurrent.CopyOnWriteArrayList
+import java.util.concurrent.atomic.AtomicInteger
+
+private const val INVALID_ROTATION = -1
/**
* Allows to subscribe to rotation changes. Updates are provided for the display associated to
@@ -45,7 +48,7 @@ constructor(
private val listeners = CopyOnWriteArrayList<RotationListener>()
private val displayListener = RotationDisplayListener()
- private var lastRotation: Int? = null
+ private val lastRotation = AtomicInteger(INVALID_ROTATION)
override fun addCallback(listener: RotationListener) {
bgHandler.post {
@@ -61,7 +64,7 @@ constructor(
listeners -= listener
if (listeners.isEmpty()) {
unsubscribeToRotation()
- lastRotation = null
+ lastRotation.set(INVALID_ROTATION)
}
}
}
@@ -100,9 +103,8 @@ constructor(
if (displayId == display.displayId) {
val currentRotation = display.rotation
- if (lastRotation == null || lastRotation != currentRotation) {
+ if (lastRotation.compareAndSet(lastRotation.get(), currentRotation)) {
listeners.forEach { it.onRotationChanged(currentRotation) }
- lastRotation = currentRotation
}
}
} finally {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index f9196f3e0e0e..d3efa21a2311 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -610,7 +610,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
}
- void notifyAccessibilityButtonClicked(int displayId) {
+ void notifyMagnificationShortcutTriggered(int displayId) {
if (mMagnificationGestureHandler.size() != 0) {
final MagnificationGestureHandler handler = mMagnificationGestureHandler.get(displayId);
if (handler != null) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 1dc3fb421545..36d97f659f6c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2220,10 +2220,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
- private void sendAccessibilityButtonToInputFilter(int displayId) {
+ private void notifyMagnificationShortcutTriggered(int displayId) {
synchronized (mLock) {
if (mHasInputFilter && mInputFilter != null) {
- mInputFilter.notifyAccessibilityButtonClicked(displayId);
+ mInputFilter.notifyMagnificationShortcutTriggered(displayId);
}
}
}
@@ -3898,7 +3898,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
.isActivated(displayId);
logAccessibilityShortcutActivated(mContext, MAGNIFICATION_COMPONENT_NAME, shortcutType,
enabled);
- sendAccessibilityButtonToInputFilter(displayId);
+ notifyMagnificationShortcutTriggered(displayId);
return;
}
final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName);
diff --git a/services/autofill/java/com/android/server/autofill/RequestId.java b/services/autofill/java/com/android/server/autofill/RequestId.java
index 29ad786dbd4b..d8069a840156 100644
--- a/services/autofill/java/com/android/server/autofill/RequestId.java
+++ b/services/autofill/java/com/android/server/autofill/RequestId.java
@@ -16,8 +16,14 @@
package com.android.server.autofill;
-import java.util.List;
+import static com.android.server.autofill.Helper.sDebug;
+
+import android.util.Slog;
+import android.util.SparseArray;
+
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.List;
+import java.util.Random;
// Helper class containing various methods to deal with FillRequest Ids.
// For authentication flows, there needs to be a way to know whether to retrieve the Fill
@@ -25,56 +31,97 @@ import java.util.concurrent.atomic.AtomicInteger;
// way to achieve this is by assigning odd number request ids to secondary provider and
// even numbers to primary provider.
public class RequestId {
+ private AtomicInteger sIdCounter;
+
+ // The minimum request id is 2 to avoid possible authentication issues.
+ static final int MIN_REQUEST_ID = 2;
+ // The maximum request id is 0x7FFF to make sure the 16th bit is 0.
+ // This is to make sure the authentication id is always positive.
+ static final int MAX_REQUEST_ID = 0x7FFF; // 32767
+
+ // The maximum start id is made small to best avoid wrapping around.
+ static final int MAX_START_ID = 1000;
+ // The magic number is used to determine if a wrap has happened.
+ // The underlying assumption of MAGIC_NUMBER is that there can't be as many as MAGIC_NUMBER
+ // of fill requests in one session. so there can't be as many as MAGIC_NUMBER of fill requests
+ // getting dropped.
+ static final int MAGIC_NUMBER = 5000;
+
+ static final int MIN_PRIMARY_REQUEST_ID = 2;
+ static final int MAX_PRIMARY_REQUEST_ID = 0x7FFE; // 32766
+
+ static final int MIN_SECONDARY_REQUEST_ID = 3;
+ static final int MAX_SECONDARY_REQUEST_ID = 0x7FFF; // 32767
+
+ private static final String TAG = "RequestId";
+
+ // WARNING: This constructor should only be used for testing
+ RequestId(int startId) {
+ if (startId < MIN_REQUEST_ID || startId > MAX_REQUEST_ID) {
+ throw new IllegalArgumentException("startId must be between " + MIN_REQUEST_ID +
+ " and " + MAX_REQUEST_ID);
+ }
+ if (sDebug) {
+ Slog.d(TAG, "RequestId(int): startId= " + startId);
+ }
+ sIdCounter = new AtomicInteger(startId);
+ }
- private AtomicInteger sIdCounter;
-
- // Mainly used for tests
- RequestId(int start) {
- sIdCounter = new AtomicInteger(start);
- }
-
- public RequestId() {
- this((int) (Math.floor(Math.random() * 0xFFFF)));
- }
-
- public static int getLastRequestIdIndex(List<Integer> requestIds) {
- int lastId = -1;
- int indexOfBiggest = -1;
- // Biggest number is usually the latest request, since IDs only increase
- // The only exception is when the request ID wraps around back to 0
- for (int i = requestIds.size() - 1; i >= 0; i--) {
- if (requestIds.get(i) > lastId) {
- lastId = requestIds.get(i);
- indexOfBiggest = i;
- }
+ // WARNING: This get method should only be used for testing
+ int getRequestId() {
+ return sIdCounter.get();
}
- // 0xFFFE + 2 == 0x1 (for secondary)
- // 0xFFFD + 2 == 0x0 (for primary)
- // Wrap has occurred
- if (lastId >= 0xFFFD) {
- // Calculate the biggest size possible
- // If list only has one kind of request ids - we need to multiple by 2
- // (since they skip odd ints)
- // Also subtract one from size because at least one integer exists pre-wrap
- int calcSize = (requestIds.size()) * 2;
- //Biggest possible id after wrapping
- int biggestPossible = (lastId + calcSize) % 0xFFFF;
- lastId = -1;
- indexOfBiggest = -1;
- for (int i = 0; i < requestIds.size(); i++) {
- int currentId = requestIds.get(i);
- if (currentId <= biggestPossible && currentId > lastId) {
- lastId = currentId;
- indexOfBiggest = i;
+ public RequestId() {
+ Random random = new Random();
+ int low = MIN_REQUEST_ID;
+ int high = MAX_START_ID + 1; // nextInt is exclusive on upper limit
+
+ // Generate a random start request id that >= MIN_REQUEST_ID and <= MAX_START_ID
+ int startId = random.nextInt(high - low) + low;
+ if (sDebug) {
+ Slog.d(TAG, "RequestId(): startId= " + startId);
}
- }
+ sIdCounter = new AtomicInteger(startId);
}
- return indexOfBiggest;
- }
+ // Given a list of request ids, find the index of the last request id.
+ // Note: Since the request id wraps around, the largest request id may not be
+ // the latest request id.
+ //
+ // @param requestIds List of request ids in ascending order with at least one element.
+ // @return Index of the last request id.
+ public static int getLastRequestIdIndex(List<Integer> requestIds) {
+ // If there is only one request id, return index as 0.
+ if (requestIds.size() == 1) {
+ return 0;
+ }
+
+ // We have to use a magical number to determine if a wrap has happened because
+ // the request id could be lost. The underlying assumption of MAGIC_NUMBER is that
+ // there can't be as many as MAGIC_NUMBER of fill requests in one session.
+ boolean wrapHasHappened = false;
+ int latestRequestIdIndex = -1;
+
+ for (int i = 0; i < requestIds.size() - 1; i++) {
+ if (requestIds.get(i+1) - requestIds.get(i) > MAGIC_NUMBER) {
+ wrapHasHappened = true;
+ latestRequestIdIndex = i;
+ break;
+ }
+ }
+
+ // If there was no wrap, the last request index is the last index.
+ if (!wrapHasHappened) {
+ latestRequestIdIndex = requestIds.size() - 1;
+ }
+ if (sDebug) {
+ Slog.d(TAG, "getLastRequestIdIndex(): latestRequestIdIndex = " + latestRequestIdIndex);
+ }
+ return latestRequestIdIndex;
+ }
- public int nextId(boolean isSecondary) {
+ public int nextId(boolean isSecondary) {
// For authentication flows, there needs to be a way to know whether to retrieve the Fill
// Response from the primary provider or the secondary provider from the requestId. A simple
// way to achieve this is by assigning odd number request ids to secondary provider and
@@ -82,13 +129,20 @@ public class RequestId {
int requestId;
do {
- requestId = sIdCounter.incrementAndGet() % 0xFFFF;
+ requestId = sIdCounter.incrementAndGet() % (MAX_REQUEST_ID + 1);
+ // Skip numbers smaller than MIN_REQUEST_ID to avoid possible authentication issue
+ if (requestId < MIN_REQUEST_ID) {
+ requestId = MIN_REQUEST_ID;
+ }
sIdCounter.set(requestId);
} while (isSecondaryProvider(requestId) != isSecondary);
+ if (sDebug) {
+ Slog.d(TAG, "nextId(): requestId = " + requestId);
+ }
return requestId;
- }
+ }
- public static boolean isSecondaryProvider(int requestId) {
- return requestId % 2 == 1;
- }
+ public static boolean isSecondaryProvider(int requestId) {
+ return requestId % 2 == 1;
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 494e956c413f..c6ddc16211bc 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -6902,17 +6902,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return mPendingSaveUi != null && mPendingSaveUi.getState() == PendingUi.STATE_PENDING;
}
+ // Return latest response index in mResponses SparseArray.
@GuardedBy("mLock")
private int getLastResponseIndexLocked() {
- if (mResponses != null) {
- List<Integer> requestIdList = new ArrayList<>();
- final int responseCount = mResponses.size();
- for (int i = 0; i < responseCount; i++) {
- requestIdList.add(mResponses.keyAt(i));
- }
- return mRequestId.getLastRequestIdIndex(requestIdList);
+ if (mResponses == null || mResponses.size() == 0) {
+ return -1;
+ }
+ List<Integer> requestIdList = new ArrayList<>();
+ final int responseCount = mResponses.size();
+ for (int i = 0; i < responseCount; i++) {
+ requestIdList.add(mResponses.keyAt(i));
}
- return -1;
+ return mRequestId.getLastRequestIdIndex(requestIdList);
}
private LogMaker newLogMaker(int category) {
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 3c323f9ce69c..657e261a345f 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -24,6 +24,7 @@ import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAUL
import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CLIPBOARD;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
@@ -720,6 +721,13 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
}
break;
+ case POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR:
+ if (android.companion.virtualdevice.flags.Flags.activityControlApi()) {
+ synchronized (mVirtualDeviceLock) {
+ mDevicePolicies.put(policyType, devicePolicy);
+ }
+ }
+ break;
default:
throw new IllegalArgumentException("Device policy " + policyType
+ " cannot be changed at runtime. ");
@@ -1321,14 +1329,15 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
private void onActivityBlocked(int displayId, ActivityInfo activityInfo) {
Intent intent = BlockedAppStreamingActivity.createIntent(activityInfo, getDisplayName());
- if (!android.companion.virtualdevice.flags.Flags.activityControlApi()
- || !Objects.equals(activityInfo.getComponentName(), intent.getComponent())) {
+ if (shouldShowBlockedActivityDialog(
+ activityInfo.getComponentName(), intent.getComponent())) {
mContext.startActivityAsUser(
intent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK),
ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(),
UserHandle.SYSTEM);
}
+
if (android.companion.virtualdevice.flags.Flags.activityControlApi()) {
mActivityListenerAdapter.onActivityLaunchBlocked(
displayId,
@@ -1338,6 +1347,20 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
}
+ private boolean shouldShowBlockedActivityDialog(ComponentName blockedComponent,
+ ComponentName blockedAppStreamingActivityComponent) {
+ if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) {
+ return true;
+ }
+ if (Objects.equals(blockedComponent, blockedAppStreamingActivityComponent)) {
+ // Do not show the dialog if it was blocked for some reason already to avoid
+ // infinite blocking loop.
+ return false;
+ }
+ // Do not show the dialog if disabled by policy.
+ return getDevicePolicy(POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR) == DEVICE_POLICY_DEFAULT;
+ }
+
private void onSecureWindowShown(int displayId, int uid) {
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(displayId)) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d9962c7b02d5..1cd20ed0f7cd 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -47,7 +47,7 @@ genrule {
],
tools: ["protologtool"],
cmd: "$(location protologtool) transform-protolog-calls " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
"--loggroups-jar $(location :protolog-groups) " +
"--viewer-config-file-path /etc/core.protolog.pb " +
@@ -66,7 +66,7 @@ genrule {
],
tools: ["protologtool"],
cmd: "$(location protologtool) generate-viewer-config " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
"--loggroups-jar $(location :protolog-groups) " +
"--viewer-config-type json " +
@@ -83,7 +83,7 @@ genrule {
],
tools: ["protologtool"],
cmd: "$(location protologtool) generate-viewer-config " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
"--loggroups-jar $(location :protolog-groups) " +
"--viewer-config-type proto " +
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 3d3535d2dbd2..73d8384395d2 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -197,8 +197,8 @@ public final class SystemServerInitThreadPool implements Dumpable {
/* processCpuTracker= */null, /* lastPids= */null,
CompletableFuture.completedFuture(Watchdog.getInterestingNativePids()),
/* logExceptionCreatingFile= */null, /* subject= */null,
- /* criticalEventSection= */null, Runnable::run,
- /* latencyTracker= */null);
+ /* criticalEventSection= */null, /* extraHeaders= */ null,
+ Runnable::run, /* latencyTracker= */null);
}
@Override
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 72a55dbea481..21947bac137b 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -74,6 +74,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@@ -991,6 +992,9 @@ public class Watchdog implements Dumpable {
FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject);
}
+ final LinkedHashMap headersMap =
+ com.android.server.am.Flags.enableDropboxWatchdogHeaders()
+ ? new LinkedHashMap<>(Collections.singletonMap("Watchdog-Type", dropboxTag)) : null;
long anrTime = SystemClock.uptimeMillis();
StringBuilder report = new StringBuilder();
report.append(ResourcePressureUtil.currentPsiState());
@@ -998,8 +1002,9 @@ public class Watchdog implements Dumpable {
StringWriter tracesFileException = new StringWriter();
final File stack = StackTracesDumpHelper.dumpStackTraces(
pids, processCpuTracker, new SparseBooleanArray(),
- CompletableFuture.completedFuture(getInterestingNativePids()), tracesFileException,
- subject, criticalEvents, Runnable::run, /* latencyTracker= */null);
+ CompletableFuture.completedFuture(getInterestingNativePids()),
+ tracesFileException, subject, criticalEvents, headersMap,
+ Runnable::run, /* latencyTracker= */null);
// Give some extra time to make sure the stack traces get written.
// The system's been hanging for a whlie, another second or two won't hurt much.
SystemClock.sleep(5000);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f6b3b3972f36..25fb729e7e7c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -429,7 +429,7 @@ import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.policy.AttributeCache;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index d4d49654ad29..ba4b71cd7540 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -60,7 +60,6 @@ import com.android.server.ResourcePressureUtil;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.wm.WindowProcessController;
-import com.android.server.utils.AnrTimer;
import java.io.File;
import java.io.PrintWriter;
@@ -69,6 +68,7 @@ import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -429,7 +429,7 @@ class ProcessErrorStateRecord {
}
}
// Build memory headers for the ANRing process.
- String memoryHeaders = buildMemoryHeadersFor(pid);
+ LinkedHashMap<String, String> memoryHeaders = buildMemoryHeadersFor(pid);
// Get critical event log before logging the ANR so that it doesn't occur in the log.
latencyTracker.criticalEventLogStarted();
@@ -753,7 +753,7 @@ class ProcessErrorStateRecord {
resolver.getUserId()) != 0;
}
- private @Nullable String buildMemoryHeadersFor(int pid) {
+ private @Nullable LinkedHashMap<String, String> buildMemoryHeadersFor(int pid) {
if (pid <= 0) {
Slog.i(TAG, "Memory header requested with invalid pid: " + pid);
return null;
@@ -764,15 +764,13 @@ class ProcessErrorStateRecord {
return null;
}
- StringBuilder memoryHeaders = new StringBuilder();
- memoryHeaders.append("RssHwmKb: ")
- .append(snapshot.rssHighWaterMarkInKilobytes)
- .append("\n");
- memoryHeaders.append("RssKb: ").append(snapshot.rssInKilobytes).append("\n");
- memoryHeaders.append("RssAnonKb: ").append(snapshot.anonRssInKilobytes).append("\n");
- memoryHeaders.append("RssShmemKb: ").append(snapshot.rssShmemKilobytes).append("\n");
- memoryHeaders.append("VmSwapKb: ").append(snapshot.swapInKilobytes).append("\n");
- return memoryHeaders.toString();
+ LinkedHashMap<String, String> memoryHeaders = new LinkedHashMap<>();
+ memoryHeaders.put("RssHwmKb", Integer.toString(snapshot.rssHighWaterMarkInKilobytes));
+ memoryHeaders.put("RssKb", Integer.toString(snapshot.rssInKilobytes));
+ memoryHeaders.put("RssAnonKb", Integer.toString(snapshot.anonRssInKilobytes));
+ memoryHeaders.put("RssShmemKb", Integer.toString(snapshot.rssShmemKilobytes));
+ memoryHeaders.put("VmSwapKb", Integer.toString(snapshot.swapInKilobytes));
+ return memoryHeaders;
}
/**
* Unless configured otherwise, swallow ANRs in background processes & kill the process.
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c0947247de4b..f4b1229696f5 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -855,8 +855,8 @@ public final class ProcessList {
Slog.i(TAG, "Failed to connect to lmkd, retry after " +
LMKD_RECONNECT_DELAY_MS + " ms");
// retry after LMKD_RECONNECT_DELAY_MS
- sKillHandler.sendMessageDelayed(sKillHandler.obtainMessage(
- KillHandler.LMKD_RECONNECT_MSG), LMKD_RECONNECT_DELAY_MS);
+ sendMessageDelayed(obtainMessage(
+ LMKD_RECONNECT_MSG), LMKD_RECONNECT_DELAY_MS);
}
break;
default:
diff --git a/services/core/java/com/android/server/am/StackTracesDumpHelper.java b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
index c1374e1b5a05..2021ba4f3b5d 100644
--- a/services/core/java/com/android/server/am/StackTracesDumpHelper.java
+++ b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
@@ -47,6 +47,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -100,15 +102,17 @@ public class StackTracesDumpHelper {
/**
* @param subject the subject of the dumped traces
* @param criticalEventSection the critical event log, passed as a string
+ * @param extraHeaders Optional, Extra headers added by the dumping method
*/
public static File dumpStackTraces(ArrayList<Integer> firstPids,
ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids,
Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile,
- String subject, String criticalEventSection, @NonNull Executor auxiliaryTaskExecutor,
+ String subject, String criticalEventSection,
+ LinkedHashMap<String, String> extraHeaders, @NonNull Executor auxiliaryTaskExecutor,
AnrLatencyTracker latencyTracker) {
return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePidsFuture,
logExceptionCreatingFile, null, subject, criticalEventSection,
- /* memoryHeaders= */ null, auxiliaryTaskExecutor, null, latencyTracker);
+ extraHeaders, auxiliaryTaskExecutor, null, latencyTracker);
}
/**
@@ -119,7 +123,7 @@ public class StackTracesDumpHelper {
ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids,
Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile,
AtomicLong firstPidEndOffset, String subject, String criticalEventSection,
- String memoryHeaders, @NonNull Executor auxiliaryTaskExecutor,
+ LinkedHashMap<String, String> extraHeaders, @NonNull Executor auxiliaryTaskExecutor,
Future<File> firstPidFilePromise, AnrLatencyTracker latencyTracker) {
try {
@@ -159,11 +163,12 @@ public class StackTracesDumpHelper {
}
return null;
}
+ boolean extraHeadersExist = extraHeaders != null && !extraHeaders.isEmpty();
- if (subject != null || criticalEventSection != null || memoryHeaders != null) {
+ if (subject != null || criticalEventSection != null || extraHeadersExist) {
appendtoANRFile(tracesFile.getAbsolutePath(),
(subject != null ? "Subject: " + subject + "\n" : "")
- + (memoryHeaders != null ? memoryHeaders + "\n\n" : "")
+ + (extraHeadersExist ? stringifyHeaders(extraHeaders) + "\n\n" : "")
+ (criticalEventSection != null ? criticalEventSection : ""));
}
@@ -614,4 +619,15 @@ public class StackTracesDumpHelper {
return pids;
}
+ private static String stringifyHeaders(@NonNull LinkedHashMap<String, String> headers) {
+ StringBuilder headersString = new StringBuilder();
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
+ headersString.append(entry.getKey())
+ .append(": ")
+ .append(entry.getValue())
+ .append("\n");
+ }
+ return headersString.toString();
+ }
+
}
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 0dfa3302adfd..9b380ff12e2d 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -167,4 +167,12 @@ flag {
description: "Allow logcat collection on synchronous dropbox collection"
bug: "324222683"
is_fixed_read_only: true
-} \ No newline at end of file
+}
+
+flag {
+ name: "enable_dropbox_watchdog_headers"
+ namespace: "dropbox"
+ description: "Add watchdog-specific dropbox headers"
+ bug: "330682397"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 6ff4a617cec4..2986340c684d 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -2528,7 +2528,7 @@ public class AudioDeviceInventory {
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name);
- final int res = AudioSystem.setDeviceConnectionState(ada,
+ final int res = mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_AVAILABLE, codec);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
@@ -2575,7 +2575,7 @@ public class AudioDeviceInventory {
AudioDeviceAttributes ada = null;
if (device != AudioSystem.DEVICE_NONE) {
ada = new AudioDeviceAttributes(device, address);
- final int res = AudioSystem.setDeviceConnectionState(ada,
+ final int res = mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
codec);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 39cb5a96f564..97326211d18e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -461,6 +461,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_DISPATCH_PREFERRED_MIXER_ATTRIBUTES = 52;
private static final int MSG_CONFIGURATION_CHANGED = 54;
private static final int MSG_BROADCAST_MASTER_MUTE = 55;
+ private static final int MSG_UPDATE_CONTEXTUAL_VOLUMES = 56;
/**
* Messages handled by the {@link SoundDoseHelper}, do not exceed
@@ -4466,7 +4467,7 @@ public class AudioService extends IAudioService.Stub
}
}
if (mVoicePlaybackActive.getAndSet(voiceActive) != voiceActive) {
- updateHearingAidVolumeOnVoiceActivityUpdate();
+ postUpdateContextualVolumes();
}
if (mMediaPlaybackActive.getAndSet(mediaActive) != mediaActive && mediaActive) {
mSoundDoseHelper.scheduleMusicActiveCheck();
@@ -4604,13 +4605,29 @@ public class AudioService extends IAudioService.Stub
}
}
- private void updateHearingAidVolumeOnVoiceActivityUpdate() {
+
+ // delay between audio playback configuration update and checking
+ // actual stream activity to take async playback stop into account
+ private static final int UPDATE_CONTEXTUAL_VOLUME_DELAY_MS = 500;
+
+ /*package*/ void postUpdateContextualVolumes() {
+ sendMsg(mAudioHandler, MSG_UPDATE_CONTEXTUAL_VOLUMES, SENDMSG_REPLACE,
+ /*arg1*/ 0, /*arg2*/ 0, TAG, UPDATE_CONTEXTUAL_VOLUME_DELAY_MS);
+ }
+
+ private void onUpdateContextualVolumes() {
final int streamType = getBluetoothContextualVolumeStream();
- final int index = getStreamVolume(streamType);
- sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID,
- mVoicePlaybackActive.get(), streamType, index));
- mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
+ final int device = getDeviceForStream(streamType);
+ final int index = getStreamVolume(streamType, device);
+ if (AudioSystem.isLeAudioDeviceType(device)) {
+ mDeviceBroker.postSetLeAudioVolumeIndex(index * 10,
+ mStreamStates[streamType].getMaxIndex(), streamType);
+ } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
+ mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
+ }
+ sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME,
+ mVoicePlaybackActive.get(), streamType, index, device));
}
/**
@@ -9812,6 +9829,10 @@ public class AudioService extends IAudioService.Stub
onConfigurationChanged();
break;
+ case MSG_UPDATE_CONTEXTUAL_VOLUMES:
+ onUpdateContextualVolumes();
+ break;
+
case MusicFxHelper.MSG_EFFECT_CLIENT_GONE:
mMusicFxHelper.handleMessage(msg);
break;
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 8ea28bed30a2..631d5d80acd7 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -227,7 +227,7 @@ public class AudioServiceEvents {
static final int VOL_SET_HEARING_AID_VOL = 3;
static final int VOL_SET_AVRCP_VOL = 4;
static final int VOL_ADJUST_VOL_UID = 5;
- static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6;
+ static final int VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME = 6;
static final int VOL_MODE_CHANGE_HEARING_AID = 7;
static final int VOL_SET_GROUP_VOL = 8;
static final int VOL_MUTE_STREAM_INT = 9;
@@ -299,14 +299,14 @@ public class AudioServiceEvents {
logMetricEvent();
}
- /** used for VOL_VOICE_ACTIVITY_HEARING_AID */
- VolumeEvent(int op, boolean voiceActive, int stream, int index) {
+ /** used for VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME */
+ VolumeEvent(int op, boolean voiceActive, int stream, int index, int device) {
mOp = op;
mStream = stream;
mVal1 = index;
mVal2 = voiceActive ? 1 : 0;
// unused
- mVal3 = -1;
+ mVal3 = device;
mCaller = null;
mGroupName = null;
logMetricEvent();
@@ -445,14 +445,16 @@ public class AudioServiceEvents {
.set(MediaMetrics.Property.INDEX, mVal1)
.record();
return;
- case VOL_VOICE_ACTIVITY_HEARING_AID:
+ case VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME:
new MediaMetrics.Item(mMetricsId)
- .set(MediaMetrics.Property.EVENT, "voiceActivityHearingAid")
+ .set(MediaMetrics.Property.EVENT, "voiceActivityContextualVolume")
.set(MediaMetrics.Property.INDEX, mVal1)
.set(MediaMetrics.Property.STATE,
mVal2 == 1 ? "active" : "inactive")
.set(MediaMetrics.Property.STREAM_TYPE,
AudioSystem.streamToString(mStream))
+ .set(MediaMetrics.Property.DEVICE,
+ AudioSystem.getOutputDeviceName(mVal3))
.record();
return;
case VOL_MODE_CHANGE_HEARING_AID:
@@ -538,11 +540,12 @@ public class AudioServiceEvents {
.append(" flags:0x").append(Integer.toHexString(mVal2))
.append(") from ").append(mCaller)
.toString();
- case VOL_VOICE_ACTIVITY_HEARING_AID:
+ case VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME:
return new StringBuilder("Voice activity change (")
.append(mVal2 == 1 ? "active" : "inactive")
- .append(") causes setting HEARING_AID volume to idx:").append(mVal1)
+ .append(") causes setting volume to idx:").append(mVal1)
.append(" stream:").append(AudioSystem.streamToString(mStream))
+ .append(" device:").append(AudioSystem.getOutputDeviceName(mVal3))
.toString();
case VOL_MODE_CHANGE_HEARING_AID:
return new StringBuilder("setMode(")
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index e8394d43f266..619aecf4156f 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -19,6 +19,9 @@ package com.android.server.devicestate;
import static android.Manifest.permission.CONTROL_DEVICE_STATE;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY;
+import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST;
import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS;
import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
@@ -47,6 +50,8 @@ import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManagerInternal;
import android.hardware.devicestate.IDeviceStateManager;
import android.hardware.devicestate.IDeviceStateManagerCallback;
+import android.hardware.devicestate.feature.flags.FeatureFlags;
+import android.hardware.devicestate.feature.flags.FeatureFlagsImpl;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -175,7 +180,7 @@ public final class DeviceStateManagerService extends SystemService {
private Set<Integer> mDeviceStatesAvailableForAppRequests = new HashSet<>();
- private Set<Integer> mFoldedDeviceStates;
+ private Set<Integer> mFoldedDeviceStates = new HashSet<>();
@Nullable
private DeviceState mRearDisplayState;
@@ -185,6 +190,9 @@ public final class DeviceStateManagerService extends SystemService {
@Nullable
private OverrideRequest mRearDisplayPendingOverrideRequest;
+ @NonNull
+ private final FeatureFlags mFlags;
+
@VisibleForTesting
interface SystemPropertySetter {
void setDebugTracingDeviceStateProperty(String value);
@@ -245,6 +253,7 @@ public final class DeviceStateManagerService extends SystemService {
@NonNull SystemPropertySetter systemPropertySetter) {
super(context);
mSystemPropertySetter = systemPropertySetter;
+ mFlags = new FeatureFlagsImpl();
// We use the DisplayThread because this service indirectly drives
// display (on/off) and window (position) events through its callbacks.
DisplayThread displayThread = DisplayThread.get();
@@ -270,9 +279,12 @@ public final class DeviceStateManagerService extends SystemService {
publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService);
publishLocalService(DeviceStateManagerInternal.class, new LocalService());
- synchronized (mLock) {
- readStatesAvailableForRequestFromApps();
- mFoldedDeviceStates = readFoldedStates();
+ if (!mFlags.deviceStatePropertyMigration()) {
+ synchronized (mLock) {
+ readStatesAvailableForRequestFromApps();
+ mFoldedDeviceStates = readFoldedStates();
+ setRearDisplayStateLocked();
+ }
}
mActivityTaskManagerInternal.registerScreenObserver(mOverrideRequestScreenObserver);
@@ -461,8 +473,6 @@ public final class DeviceStateManagerService extends SystemService {
mOverrideRequestController.handleNewSupportedStates(newStateIdentifiers, reason);
updatePendingStateLocked();
- setRearDisplayStateLocked();
-
notifyDeviceStateInfoChangedAsync();
mHandler.post(this::notifyPolicyIfNeeded);
@@ -838,12 +848,22 @@ public final class DeviceStateManagerService extends SystemService {
OverrideRequest request = new OverrideRequest(token, callingPid, callingUid,
deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
- // If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay
- if (!hasControlDeviceStatePermission && mRearDisplayState != null
- && state == mRearDisplayState.getIdentifier()) {
- showRearDisplayEducationalOverlayLocked(request);
+ if (mFlags.deviceStatePropertyMigration()) {
+ // If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay
+ if (!hasControlDeviceStatePermission && deviceState.get().hasProperty(
+ PROPERTY_FEATURE_REAR_DISPLAY)) {
+ showRearDisplayEducationalOverlayLocked(request);
+ } else {
+ mOverrideRequestController.addRequest(request);
+ }
} else {
- mOverrideRequestController.addRequest(request);
+ // If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay
+ if (!hasControlDeviceStatePermission && mRearDisplayState != null
+ && state == mRearDisplayState.getIdentifier()) {
+ showRearDisplayEducationalOverlayLocked(request);
+ } else {
+ mOverrideRequestController.addRequest(request);
+ }
}
}
}
@@ -1034,7 +1054,13 @@ public final class DeviceStateManagerService extends SystemService {
private boolean isStateAvailableForAppRequests(int state) {
synchronized (mLock) {
- return mDeviceStatesAvailableForAppRequests.contains(state);
+ if (mFlags.deviceStatePropertyMigration()) {
+ Optional<DeviceState> deviceState = getStateLocked(state);
+ return deviceState.isPresent() && deviceState.get().hasProperty(
+ PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST);
+ } else {
+ return mDeviceStatesAvailableForAppRequests.contains(state);
+ }
}
}
@@ -1096,9 +1122,20 @@ public final class DeviceStateManagerService extends SystemService {
*/
@GuardedBy("mLock")
private boolean isDeviceOpeningLocked(int newBaseState) {
- return mBaseState.filter(
- deviceState -> mFoldedDeviceStates.contains(deviceState.getIdentifier())
- && !mFoldedDeviceStates.contains(newBaseState)).isPresent();
+ if (mFlags.deviceStatePropertyMigration()) {
+ final DeviceState currentBaseState = mBaseState.orElse(INVALID_DEVICE_STATE);
+ final DeviceState newDeviceBaseState = getStateLocked(newBaseState).orElse(
+ INVALID_DEVICE_STATE);
+
+ return currentBaseState.hasProperty(
+ PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)
+ && !newDeviceBaseState.hasProperty(
+ PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY);
+ } else {
+ return mBaseState.filter(
+ deviceState -> mFoldedDeviceStates.contains(deviceState.getIdentifier())
+ && !mFoldedDeviceStates.contains(newBaseState)).isPresent();
+ }
}
private final class DeviceStateProviderListener implements DeviceStateProvider.Listener {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index de9715ac812d..7cd9144be77b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -2098,7 +2098,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private void onDisplayOffloadUnblockScreenOn(DisplayOffloadSession displayOffloadSession) {
Message msg = mHandler.obtainMessage(MSG_OFFLOADING_SCREEN_ON_UNBLOCKED,
displayOffloadSession);
- mHandler.sendMessage(msg);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
}
private void unblockScreenOnByDisplayOffload() {
@@ -2116,7 +2116,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (mDisplayOffloadSession == null) {
return;
}
- if (mPendingScreenOnUnblockerByDisplayOffload != null) {
+ if (mPendingScreenOnUnblockerByDisplayOffload == null) {
// Already unblocked.
return;
}
@@ -2134,7 +2134,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// If the screen is turning on, give displayoffload a chance to do something before the
// screen actually turns on.
- // TODO(b/316941732): add tests for this displayoffload screen-on blocker.
if (isOn && changed && !mScreenTurningOnWasBlockedByDisplayOffload) {
blockScreenOnByDisplayOffload(mDisplayOffloadSession);
} else if (!isOn && mScreenTurningOnWasBlockedByDisplayOffload) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 18a9986d34ba..886857c1b880 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -1079,6 +1079,21 @@ public final class DreamManagerService extends SystemService {
}
@Override // Binder call
+ public void finishSelfOneway(IBinder token, boolean immediate) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ finishSelfInternal(token, immediate);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
public void startDozing(
IBinder token, int screenState, @Display.StateReason int reason,
int screenBrightness) {
@@ -1096,6 +1111,23 @@ public final class DreamManagerService extends SystemService {
}
@Override // Binder call
+ public void startDozingOneway(
+ IBinder token, int screenState, @Display.StateReason int reason,
+ int screenBrightness) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ startDozingInternal(token, screenState, reason, screenBrightness);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
public void stopDozing(IBinder token) {
// Requires no permission, called by Dream from an arbitrary process.
if (token == null) {
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapper.java b/services/core/java/com/android/server/health/HealthServiceWrapper.java
index 25d1a885bc18..9c14b5b079b1 100644
--- a/services/core/java/com/android/server/health/HealthServiceWrapper.java
+++ b/services/core/java/com/android/server/health/HealthServiceWrapper.java
@@ -71,6 +71,21 @@ public abstract class HealthServiceWrapper {
public abstract android.hardware.health.HealthInfo getHealthInfo() throws RemoteException;
/**
+ * Calls into getBatteryHealthData() in the health HAL.
+ * This function does not have a corresponding HIDL implementation, so
+ * returns null by default, unless there is an AIDL class that overrides
+ * this one.
+ *
+ * @return battery health data. {@code null} if no health HAL service.
+ * {@code null} if any service-specific error when calling {@code
+ * getBatteryHealthData}, e.g. it is unsupported.
+ * @throws RemoteException for any transaction-level errors
+ */
+ public android.hardware.health.BatteryHealthData getBatteryHealthData() throws RemoteException {
+ return null;
+ }
+
+ /**
* Create a new HealthServiceWrapper instance.
*
* @param healthInfoCallback the callback to call when health info changes
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java b/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
index fd3a92e97c26..2a3fbc3f2466 100644
--- a/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
+++ b/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
@@ -212,6 +212,17 @@ class HealthServiceWrapperAidl extends HealthServiceWrapper {
}
}
+ @Override
+ public BatteryHealthData getBatteryHealthData() throws RemoteException {
+ IHealth service = mLastService.get();
+ if (service == null) return null;
+ try {
+ return service.getBatteryHealthData();
+ } catch (UnsupportedOperationException | ServiceSpecificException ex) {
+ return null;
+ }
+ }
+
public void setChargingPolicy(int policy) throws RemoteException {
IHealth service = mLastService.get();
if (service == null) return;
diff --git a/services/core/java/com/android/server/input/BatteryController.java b/services/core/java/com/android/server/input/BatteryController.java
index 38a0d37c5679..62c21bda1fd1 100644
--- a/services/core/java/com/android/server/input/BatteryController.java
+++ b/services/core/java/com/android/server/input/BatteryController.java
@@ -83,6 +83,7 @@ final class BatteryController {
private final Handler mHandler;
private final UEventManager mUEventManager;
private final BluetoothBatteryManager mBluetoothBatteryManager;
+ private final Runnable mHandlePollEventCallback = this::handlePollEvent;
// Maps a pid to the registered listener record for that process. There can only be one battery
// listener per process.
@@ -206,7 +207,7 @@ final class BatteryController {
if (!mIsInteractive || !anyOf(mDeviceMonitors, DeviceMonitor::requiresPolling)) {
// Stop polling.
mIsPolling = false;
- mHandler.removeCallbacks(this::handlePollEvent);
+ mHandler.removeCallbacks(mHandlePollEventCallback);
return;
}
@@ -215,7 +216,7 @@ final class BatteryController {
}
// Start polling.
mIsPolling = true;
- mHandler.postDelayed(this::handlePollEvent, delayStart ? POLLING_PERIOD_MILLIS : 0);
+ mHandler.postDelayed(mHandlePollEventCallback, delayStart ? POLLING_PERIOD_MILLIS : 0);
}
private <R> R processInputDevice(int deviceId, R defaultValue, Function<InputDevice, R> func) {
@@ -366,7 +367,7 @@ final class BatteryController {
}
final long eventTime = SystemClock.uptimeMillis();
mDeviceMonitors.forEach((deviceId, monitor) -> monitor.onPoll(eventTime));
- mHandler.postDelayed(this::handlePollEvent, POLLING_PERIOD_MILLIS);
+ mHandler.postDelayed(mHandlePollEventCallback, POLLING_PERIOD_MILLIS);
}
}
diff --git a/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java b/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java
index 0749edce97a1..aeace7ac9aee 100644
--- a/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java
+++ b/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java
@@ -103,8 +103,8 @@ final class AutofillSuggestionsController {
// Note that current user ID is guaranteed to be userId.
final var imeId = mBindingController.getSelectedMethodId();
- final InputMethodInfo imi = InputMethodSettingsRepository.get(mBindingController.mUserId)
- .getMethodMap().get(imeId);
+ final InputMethodInfo imi = InputMethodSettingsRepository.get(
+ mBindingController.getUserId()).getMethodMap().get(imeId);
if (imi == null || !isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) {
callback.onInlineSuggestionsUnsupported();
return;
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index aa4b3386e548..356bc40cb985 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -53,10 +53,10 @@ import com.android.server.wm.WindowManagerInternal;
import java.util.Objects;
/**
- * The default implementation of {@link ImeVisibilityApplier} used in
- * {@link InputMethodManagerService}.
+ * A stateless helper class for IME visibility operations like show/hide and update Z-ordering
+ * relative to the IME targeted window.
*/
-final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
+final class DefaultImeVisibilityApplier {
private static final String TAG = "DefaultImeVisibilityApplier";
@@ -75,9 +75,18 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
mImeTargetVisibilityPolicy = LocalServices.getService(ImeTargetVisibilityPolicy.class);
}
+ /**
+ * Performs showing IME on top of the given window.
+ *
+ * @param showInputToken a token that represents the requester to show IME
+ * @param statsToken the token tracking the current IME request
+ * @param resultReceiver if non-null, this will be called back to the caller when
+ * it has processed request to tell what it has done
+ * @param reason yhe reason for requesting to show IME
+ * @param userId the target user when performing show IME
+ */
@GuardedBy("ImfLock.class")
- @Override
- public void performShowIme(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
+ void performShowIme(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
@InputMethod.ShowFlags int showFlags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason, @UserIdInt int userId) {
final var bindingController = mService.getInputMethodBindingController(userId);
@@ -105,9 +114,18 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
}
}
+ /**
+ * Performs hiding IME to the given window
+ *
+ * @param hideInputToken a token that represents the requester to hide IME
+ * @param statsToken the token tracking the current IME request
+ * @param resultReceiver if non-null, this will be called back to the caller when
+ * it has processed request to tell what it has done
+ * @param reason the reason for requesting to hide IME
+ * @param userId the target user when performing hide IME
+ */
@GuardedBy("ImfLock.class")
- @Override
- public void performHideIme(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
+ void performHideIme(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason,
@UserIdInt int userId) {
final var bindingController = mService.getInputMethodBindingController(userId);
@@ -139,14 +157,16 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
}
}
- @GuardedBy("ImfLock.class")
- @Override
- public void applyImeVisibility(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
- @ImeVisibilityStateComputer.VisibilityState int state, @UserIdInt int userId) {
- applyImeVisibility(windowToken, statsToken, state,
- SoftInputShowHideReason.NOT_SET /* ignore reason */, userId);
- }
-
+ /**
+ * Applies the IME visibility from {@link android.inputmethodservice.InputMethodService} with
+ * according to the given visibility state.
+ *
+ * @param windowToken the token of a window for applying the IME visibility
+ * @param statsToken the token tracking the current IME request
+ * @param state the new IME visibility state for the applier to handle
+ * @param reason one of {@link SoftInputShowHideReason}
+ * @param userId the target user when applying the IME visibility state
+ */
@GuardedBy("ImfLock.class")
void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
@ImeVisibilityStateComputer.VisibilityState int state,
@@ -218,9 +238,16 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
}
}
+ /**
+ * Shows the IME screenshot and attach it to the given IME target window.
+ *
+ * @param imeTarget the token of a window to show the IME screenshot
+ * @param displayId the unique id to identify the display
+ * @param userId the target user when when showing the IME screenshot
+ * @return {@code true} if success, {@code false} otherwise
+ */
@GuardedBy("ImfLock.class")
- @Override
- public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId,
+ boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId,
@UserIdInt int userId) {
if (mImeTargetVisibilityPolicy.showImeScreenshot(imeTarget, displayId)) {
mService.onShowHideSoftInputRequested(false /* show */, imeTarget,
@@ -230,9 +257,15 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
return false;
}
+ /**
+ * Removes the IME screenshot on the given display.
+ *
+ * @param displayId the target display of showing IME screenshot
+ * @param userId the target user of showing IME screenshot
+ * @return {@code true} if success, {@code false} otherwise
+ */
@GuardedBy("ImfLock.class")
- @Override
- public boolean removeImeScreenshot(int displayId, @UserIdInt int userId) {
+ boolean removeImeScreenshot(int displayId, @UserIdInt int userId) {
final var userData = mService.getUserData(userId);
if (mImeTargetVisibilityPolicy.removeImeScreenshot(displayId)) {
mService.onShowHideSoftInputRequested(false /* show */,
diff --git a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
index 56fa8c9364f5..14551a1a0033 100644
--- a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
+++ b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
@@ -23,7 +23,6 @@ import android.annotation.Nullable;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.util.Log;
import android.view.inputmethod.ImeTracker;
@@ -70,8 +69,8 @@ public final class ImeTrackerService extends IImeTracker.Stub {
private final Object mLock = new Object();
- ImeTrackerService(@NonNull Looper looper) {
- mHandler = new Handler(looper, null /* callback */, true /* async */);
+ ImeTrackerService(@NonNull Handler handler) {
+ mHandler = handler;
}
@NonNull
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
deleted file mode 100644
index c1069f2a23d7..000000000000
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.inputmethod;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.os.IBinder;
-import android.os.ResultReceiver;
-import android.view.inputmethod.ImeTracker;
-import android.view.inputmethod.InputMethod;
-
-import com.android.internal.inputmethod.SoftInputShowHideReason;
-
-/**
- * Interface for IME visibility operations like show/hide and update Z-ordering relative to the IME
- * targeted window.
- */
-interface ImeVisibilityApplier {
- /**
- * Performs showing IME on top of the given window.
- *
- * @param showInputToken a token that represents the requester to show IME
- * @param statsToken the token tracking the current IME request
- * @param resultReceiver if non-null, this will be called back to the caller when
- * it has processed request to tell what it has done
- * @param reason yhe reason for requesting to show IME
- * @param userId the target user when performing show IME
- */
- default void performShowIme(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
- @InputMethod.ShowFlags int showFlags, ResultReceiver resultReceiver,
- @SoftInputShowHideReason int reason, @UserIdInt int userId) {
- }
-
- /**
- * Performs hiding IME to the given window
- *
- * @param hideInputToken a token that represents the requester to hide IME
- * @param statsToken the token tracking the current IME request
- * @param resultReceiver if non-null, this will be called back to the caller when
- * it has processed request to tell what it has done
- * @param reason the reason for requesting to hide IME
- * @param userId the target user when performing hide IME
- */
- default void performHideIme(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
- ResultReceiver resultReceiver, @SoftInputShowHideReason int reason,
- @UserIdInt int userId) {
- }
-
- /**
- * Applies the IME visibility from {@link android.inputmethodservice.InputMethodService} with
- * according to the given visibility state.
- *
- * @param windowToken the token of a window for applying the IME visibility
- * @param statsToken the token tracking the current IME request
- * @param state the new IME visibility state for the applier to handle
- * @param userId the target user when applying the IME visibility state
- */
- default void applyImeVisibility(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
- @ImeVisibilityStateComputer.VisibilityState int state, @UserIdInt int userId) {
- }
-
- /**
- * Updates the IME Z-ordering relative to the given window.
- *
- * This used to adjust the IME relative layer of the window during
- * {@link InputMethodManagerService} is in switching IME clients.
- *
- * @param windowToken the token of a window to update the Z-ordering relative to the IME
- */
- default void updateImeLayeringByTarget(IBinder windowToken) {
- // TODO: add a method in WindowManagerInternal to call DC#updateImeInputAndControlTarget
- // here to end up updating IME layering after IMMS#attachNewInputLocked called.
- }
-
- /**
- * Shows the IME screenshot and attach it to the given IME target window.
- *
- * @param windowToken the token of a window to show the IME screenshot
- * @param displayId the unique id to identify the display
- * @param userId the target user when when showing the IME screenshot
- * @return {@code true} if success, {@code false} otherwise
- */
- default boolean showImeScreenshot(@NonNull IBinder windowToken, int displayId,
- @UserIdInt int userId) {
- return false;
- }
-
- /**
- * Removes the IME screenshot on the given display.
- *
- * @param displayId the target display of showing IME screenshot
- * @param userId the target user of showing IME screenshot
- * @return {@code true} if success, {@code false} otherwise
- */
- default boolean removeImeScreenshot(int displayId, @UserIdInt int userId) {
- return false;
- }
-}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index afc10290ee02..e1aa3a2ee177 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -70,7 +70,7 @@ final class InputMethodBindingController {
/** Time in milliseconds that the IME service has to bind before it is reconnected. */
static final long TIME_TO_RECONNECT = 3 * 1000;
- @UserIdInt final int mUserId;
+ @UserIdInt private final int mUserId;
@NonNull private final InputMethodManagerService mService;
@NonNull private final Context mContext;
@NonNull private final AutofillSuggestionsController mAutofillController;
@@ -657,4 +657,9 @@ final class InputMethodBindingController {
int getDeviceIdToShowIme() {
return mDeviceIdToShowIme;
}
+
+ @UserIdInt
+ int getUserId() {
+ return mUserId;
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3c74b23fc8c2..78d501c225f8 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -90,7 +90,6 @@ import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.LocaleList;
-import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
@@ -321,6 +320,19 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
&& Flags.concurrentInputMethods();
}
+ /**
+ * Figures out the target IME user ID for a given {@link Binder} IPC.
+ *
+ * @param callingProcessUserId the user ID of the calling process
+ * @return User ID to be used for this {@link Binder} call.
+ */
+ @GuardedBy("ImfLock.class")
+ @UserIdInt
+ @BinderThread
+ private int resolveImeUserIdLocked(@UserIdInt int callingProcessUserId) {
+ return mExperimentalConcurrentMultiUserModeEnabled ? callingProcessUserId : mCurrentUserId;
+ }
+
final Context mContext;
final Resources mRes;
private final Handler mHandler;
@@ -511,16 +523,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private final WeakHashMap<IBinder, Boolean> mFocusedWindowPerceptible = new WeakHashMap<>();
/**
- * The token we have made for the currently active input method, to
- * identify it in the future.
- */
- @GuardedBy("ImfLock.class")
- @Nullable
- IBinder getCurTokenLocked() {
- return getInputMethodBindingController(mCurrentUserId).getCurToken();
- }
-
- /**
* The displayId of current active input method.
*/
@GuardedBy("ImfLock.class")
@@ -1169,8 +1171,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mIoHandler = Handler.createAsync(ioThread.getLooper());
}
SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler);
- mImeTrackerService = new ImeTrackerService(serviceThreadForTesting != null
- ? serviceThreadForTesting.getLooper() : Looper.getMainLooper());
+ mImeTrackerService = new ImeTrackerService(mHandler);
// Note: SettingsObserver doesn't register observers in its constructor.
mSettingsObserver = new SettingsObserver(mHandler);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
@@ -1493,14 +1494,16 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
* Returns true iff the caller is identified to be the current input method with the token.
*
* @param token the window token given to the input method when it was started
+ * @param userId userId of the calling IME process
* @return true if and only if non-null valid token is specified
*/
@GuardedBy("ImfLock.class")
- private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
+ private boolean calledWithValidTokenLocked(@NonNull IBinder token, @UserIdInt int userId) {
if (token == null) {
throw new InvalidParameterException("token must not be null.");
}
- if (token != getCurTokenLocked()) {
+ final var bindingController = getInputMethodBindingController(userId);
+ if (token != bindingController.getCurToken()) {
Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
+ " uid:" + Binder.getCallingUid() + " token:" + token);
return false;
@@ -1878,7 +1881,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final var statsToken = createStatsTokenForFocusedClient(false /* show */,
SoftInputShowHideReason.UNBIND_CURRENT_METHOD, userId);
mVisibilityApplier.applyImeVisibility(userData.mImeBindingState.mFocusedWindow,
- statsToken, STATE_HIDE_IME, userId);
+ statsToken, STATE_HIDE_IME, SoftInputShowHideReason.NOT_SET /* ignore reason */,
+ userId);
}
}
@@ -2051,7 +2055,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@NonNull ImeOnBackInvokedDispatcher imeDispatcher,
@NonNull InputMethodBindingController bindingController) {
- final int userId = bindingController.mUserId;
+ final int userId = bindingController.getUserId();
final var userData = getUserData(userId);
// Compute the final shown display ID with validated cs.selfReportedDisplayId for this
@@ -2068,8 +2072,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// Potentially override the selected input method if the new display belongs to a virtual
// device with a custom IME.
String selectedMethodId = bindingController.getSelectedMethodId();
- final String deviceMethodId = computeCurrentDeviceMethodIdLocked(bindingController.mUserId,
- selectedMethodId);
+ final String deviceMethodId = computeCurrentDeviceMethodIdLocked(
+ bindingController.getUserId(), selectedMethodId);
if (deviceMethodId == null) {
mVisibilityStateComputer.getImePolicy().setImeHiddenByDisplayPolicy(true);
} else if (!Objects.equals(deviceMethodId, selectedMethodId)) {
@@ -2567,7 +2571,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@GuardedBy("ImfLock.class")
void clearClientSessionsLocked(@NonNull InputMethodBindingController bindingController) {
- final int userId = bindingController.mUserId;
+ final int userId = bindingController.getUserId();
final var userData = getUserData(userId);
if (bindingController.getCurMethod() != null) {
// TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
@@ -2599,9 +2603,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@BinderThread
private void updateStatusIcon(@NonNull IBinder token, String packageName,
- @DrawableRes int iconId) {
+ @DrawableRes int iconId, @UserIdInt int userId) {
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
return;
}
final long ident = Binder.clearCallingIdentity();
@@ -2743,24 +2747,26 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@BinderThread
@SuppressWarnings("deprecation")
- private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
+ private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition,
+ @UserIdInt int userId) {
final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
return;
}
+ final var bindingController = getInputMethodBindingController(userId);
// Skip update IME status when current token display is not same as focused display.
// Note that we still need to update IME status when focusing external display
// that does not support system decoration and fallback to show IME on default
// display since it is intentional behavior.
- final int tokenDisplayId = getCurTokenDisplayIdLocked();
+ final int tokenDisplayId = bindingController.getCurTokenDisplayId();
if (tokenDisplayId != topFocusedDisplayId && tokenDisplayId != FALLBACK_DISPLAY_ID) {
return;
}
mImeWindowVis = vis;
mBackDisposition = backDisposition;
- updateSystemUiLocked(vis, backDisposition);
+ updateSystemUiLocked(vis, backDisposition, userId);
}
final boolean dismissImeOnBackKeyPressed;
@@ -2780,9 +2786,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
@BinderThread
- private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
+ private void reportStartInput(@NonNull IBinder token, IBinder startInputToken,
+ @UserIdInt int userId) {
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
return;
}
final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
@@ -2922,6 +2929,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final var userData = getUserData(userId);
userData.mSwitchingController.resetCircularListLocked(mContext, settings);
userData.mHardwareKeyboardShortcutController.update(settings);
+
+ final var bindingController = getInputMethodBindingController(userId);
+ bindingController.setSelectedMethodId(id);
}
@GuardedBy("ImfLock.class")
@@ -3107,19 +3117,19 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
int lastClickToolType, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#showSoftInput", mDumper);
synchronized (ImfLock.class) {
- if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken)) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
+ if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken,
+ userId)) {
ImeTracker.forLogging().onFailed(
statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return false;
}
- // TODO(b/305849394): Create a utility method for the following policy.
- final int userId = mExperimentalConcurrentMultiUserModeEnabled
- ? UserHandle.getCallingUserId() : mCurrentUserId;
final long ident = Binder.clearCallingIdentity();
final var userData = getUserData(userId);
try {
@@ -3271,13 +3281,15 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
try {
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#startStylusHandwriting", mDumper);
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
synchronized (ImfLock.class) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
if (!acceptingDelegation) {
mHwController.clearPendingHandwritingDelegation();
}
if (!canInteractWithImeLocked(uid, client, "startStylusHandwriting",
- null /* statsToken */)) {
+ null /* statsToken */, userId)) {
return false;
}
if (!hasSupportedStylusLocked()) {
@@ -3287,7 +3299,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
final long ident = Binder.clearCallingIdentity();
try {
- final var bindingController = getInputMethodBindingController(mCurrentUserId);
+ final var bindingController = getInputMethodBindingController(userId);
if (!bindingController.supportsStylusHandwriting()) {
Slog.w(TAG,
"Stylus HW unsupported by IME. Ignoring startStylusHandwriting()");
@@ -3537,11 +3549,13 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
@NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#hideSoftInput", mDumper);
synchronized (ImfLock.class) {
- if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken)) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
+ if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken, userId)) {
if (isInputShownLocked()) {
ImeTracker.forLogging().onFailed(
statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
@@ -3551,9 +3565,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
return false;
}
- // TODO(b/305849394): Create a utility method for the following policy.
- final int userId = mExperimentalConcurrentMultiUserModeEnabled
- ? UserHandle.getCallingUserId() : mCurrentUserId;
final long ident = Binder.clearCallingIdentity();
final var userData = getUserData(userId);
try {
@@ -3588,9 +3599,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Override
@IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)
public void hideSoftInputFromServerForTest() {
+ final int callingUserId = UserHandle.getCallingUserId();
synchronized (ImfLock.class) {
- // TODO(b/305849394): Get userId from caller.
- final int userId = mCurrentUserId;
+ final int userId = resolveImeUserIdLocked(callingUserId);
final var userData = getUserData(userId);
hideCurrentInputLocked(userData.mImeBindingState.mFocusedWindow, 0 /* flags */,
SoftInputShowHideReason.HIDE_SOFT_INPUT, userId);
@@ -3856,7 +3867,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
+ " cs=" + cs);
}
- final int userId = bindingController.mUserId;
+ final int userId = bindingController.getUserId();
final var userData = getUserData(userId);
final boolean sameWindowFocused = userData.mImeBindingState.mFocusedWindow == windowToken;
final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
@@ -3890,7 +3901,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
null, null, null, null, -1, false);
}
- userData.mImeBindingState = new ImeBindingState(bindingController.mUserId, windowToken,
+ userData.mImeBindingState = new ImeBindingState(bindingController.getUserId(), windowToken,
softInputMode, cs, editorInfo);
mFocusedWindowPerceptible.put(windowToken, true);
@@ -3951,9 +3962,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@GuardedBy("ImfLock.class")
private boolean canInteractWithImeLocked(int uid, IInputMethodClient client, String methodName,
- @Nullable ImeTracker.Token statsToken) {
- // TODO(b/305849394): Get userId from callers.
- final int userId = mCurrentUserId;
+ @Nullable ImeTracker.Token statsToken, @UserIdInt int userId) {
final var userData = getUserData(userId);
if (userData.mCurClient == null || client == null
|| userData.mCurClient.mClient.asBinder() != client.asBinder()) {
@@ -4000,15 +4009,14 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Override
public void showInputMethodPickerFromClient(IInputMethodClient client,
int auxiliarySubtypeMode) {
+ final int callingUserId = UserHandle.getCallingUserId();
synchronized (ImfLock.class) {
if (!canShowInputMethodPickerLocked(client)) {
Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
+ Binder.getCallingUid() + ": " + client);
return;
}
- // TODO(b/305849394): Create a utility method for the following policy.
- final int userId = mExperimentalConcurrentMultiUserModeEnabled
- ? UserHandle.getCallingUserId() : mCurrentUserId;
+ final int userId = resolveImeUserIdLocked(callingUserId);
final var userData = getUserData(userId);
// Always call subtype picker, because subtype picker is a superset of input method
// picker.
@@ -4048,10 +4056,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private void setInputMethod(@NonNull IBinder token, String id, @UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
return;
}
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final InputMethodInfo imi = settings.getMethodMap().get(id);
if (imi == null || !canCallerAccessInputMethod(
imi.getPackageName(), callingUid, userId, settings)) {
@@ -4066,10 +4074,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
InputMethodSubtype subtype, @UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
return;
}
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final InputMethodInfo imi = settings.getMethodMap().get(id);
if (imi == null || !canCallerAccessInputMethod(
imi.getPackageName(), callingUid, userId, settings)) {
@@ -4087,7 +4095,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@BinderThread
private boolean switchToPreviousInputMethod(@NonNull IBinder token, @UserIdInt int userId) {
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
return false;
}
final var bindingController = getInputMethodBindingController(userId);
@@ -4169,7 +4177,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme,
@UserIdInt int userId) {
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
return false;
}
return switchToNextInputMethodLocked(token, onlyCurrentIme, userId);
@@ -4196,7 +4204,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token,
@UserIdInt int userId) {
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
return false;
}
final var bindingController = getInputMethodBindingController(userId);
@@ -4324,13 +4332,11 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
return Binder.withCleanCallingIdentity(() -> {
final int curTokenDisplayId;
synchronized (ImfLock.class) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
if (!canInteractWithImeLocked(callingUid, client,
- "getInputMethodWindowVisibleHeight", null /* statsToken */)) {
+ "getInputMethodWindowVisibleHeight", null /* statsToken */, userId)) {
return 0;
}
- // TODO(b/305849394): Create a utility method for the following policy.
- final int userId = mExperimentalConcurrentMultiUserModeEnabled
- ? callingUserId : mCurrentUserId;
final var bindingController = getInputMethodBindingController(userId);
// This should probably use the caller's display id, but because this is unsupported
// and maintained only for compatibility, there's no point in fixing it.
@@ -4459,10 +4465,12 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)
@Override
public void addVirtualStylusIdForTestSession(IInputMethodClient client) {
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
synchronized (ImfLock.class) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
if (!canInteractWithImeLocked(uid, client, "addVirtualStylusIdForTestSession",
- null /* statsToken */)) {
+ null /* statsToken */, userId)) {
return;
}
final long ident = Binder.clearCallingIdentity();
@@ -4486,10 +4494,12 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Override
public void setStylusWindowIdleTimeoutForTest(
IInputMethodClient client, @DurationMillisLong long timeout) {
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
synchronized (ImfLock.class) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
if (!canInteractWithImeLocked(uid, client, "setStylusWindowIdleTimeoutForTest",
- null /* statsToken */)) {
+ null /* statsToken */, userId)) {
return;
}
final long ident = Binder.clearCallingIdentity();
@@ -4658,7 +4668,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.applyImeVisibility");
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
return;
@@ -4669,7 +4679,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
windowToken, userId);
mVisibilityApplier.applyImeVisibility(requestToken, statsToken,
setVisible ? ImeVisibilityStateComputer.STATE_SHOW_IME
- : ImeVisibilityStateComputer.STATE_HIDE_IME, userId);
+ : ImeVisibilityStateComputer.STATE_HIDE_IME,
+ SoftInputShowHideReason.NOT_SET /* ignore reason */, userId);
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -4757,7 +4768,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
return;
@@ -4796,7 +4807,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showMySoftInput");
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
return;
@@ -4829,11 +4840,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
}
+ @GuardedBy("ImfLock.class")
@VisibleForTesting
- ImeVisibilityApplier getVisibilityApplier() {
- synchronized (ImfLock.class) {
- return mVisibilityApplier;
- }
+ DefaultImeVisibilityApplier getVisibilityApplierLocked() {
+ return mVisibilityApplier;
}
void onApplyImeVisibilityFromComputer(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
@@ -6012,7 +6022,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen,
@UserIdInt int userId) {
synchronized (ImfLock.class) {
- if (!calledWithValidTokenLocked(token)) {
+ if (!calledWithValidTokenLocked(token, userId)) {
return;
}
final var userData = getUserData(userId);
@@ -6842,13 +6852,13 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@BinderThread
@Override
public void setImeWindowStatusAsync(int vis, int backDisposition) {
- mImms.setImeWindowStatus(mToken, vis, backDisposition);
+ mImms.setImeWindowStatus(mToken, vis, backDisposition, mUserId);
}
@BinderThread
@Override
public void reportStartInputAsync(IBinder startInputToken) {
- mImms.reportStartInput(mToken, startInputToken);
+ mImms.reportStartInput(mToken, startInputToken, mUserId);
}
@BinderThread
@@ -6932,7 +6942,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@BinderThread
@Override
public void updateStatusIconAsync(String packageName, @DrawableRes int iconId) {
- mImms.updateStatusIcon(mToken, packageName, iconId);
+ mImms.updateStatusIcon(mToken, packageName, iconId, mUserId);
}
@BinderThread
@@ -6999,7 +7009,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Override
public void switchKeyboardLayoutAsync(int direction) {
synchronized (ImfLock.class) {
- if (!mImms.calledWithValidTokenLocked(mToken)) {
+ if (!mImms.calledWithValidTokenLocked(mToken, mUserId)) {
return;
}
final long ident = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 381b66735e9a..a0aad5215f00 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -225,19 +225,20 @@ public class ContextHubService extends IContextHubService.Stub {
@Override
public void handleNanoappMessage(short hostEndpointId, NanoAppMessage message,
List<String> nanoappPermissions, List<String> messagePermissions) {
- if (Flags.reliableMessageImplementation()
+ // Only process the message normally if not using test mode manager or if
+ // the test mode manager call returned false as this indicates it did not
+ // process the message.
+ boolean useTestModeManager = Flags.reliableMessageImplementation()
&& Flags.reliableMessageTestModeBehavior()
- && mIsTestModeEnabled.get()
- && mTestModeManager.handleNanoappMessage(() -> {
- handleClientMessageCallback(mContextHubId, hostEndpointId, message,
- nanoappPermissions, messagePermissions);
+ && mIsTestModeEnabled.get();
+ if (!useTestModeManager
+ || !mTestModeManager.handleNanoappMessage(() -> {
+ handleClientMessageCallback(mContextHubId, hostEndpointId,
+ message, nanoappPermissions, messagePermissions);
}, message)) {
- // The ContextHubTestModeManager handled the nanoapp message, so return here.
- return;
+ handleClientMessageCallback(mContextHubId, hostEndpointId,
+ message, nanoappPermissions, messagePermissions);
}
-
- handleClientMessageCallback(mContextHubId, hostEndpointId, message,
- nanoappPermissions, messagePermissions);
}
@Override
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index 3051379d7b35..1a449e024ee1 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -618,12 +618,14 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Processes message transactions, starting and completing them as needed.
+ * <p>
* This function is called when adding a message transaction or when a timer
* expires for an existing message transaction's retry or timeout. The
* internal processing loop will iterate at most twice as if one iteration
* completes a transaction, the next iteration can only start new transactions.
* If the first iteration does not complete any transaction, the loop will
* only iterate once.
+ * <p>
*/
private synchronized void processMessageTransactions() {
if (!Flags.reliableMessageRetrySupportService()) {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 6eac72d84fd4..173fc5c86dd3 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -2504,13 +2504,13 @@ final class InstallPackageHelper {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- private void enableRestrictedSettings(String pkgName, int appId, int userId) {
+ private void setAccessRestrictedSettingsMode(String pkgName, int appId, int userId, int mode) {
final AppOpsManager appOpsManager = mPm.mContext.getSystemService(AppOpsManager.class);
final int uid = UserHandle.getUid(userId, appId);
appOpsManager.setMode(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
uid,
pkgName,
- AppOpsManager.MODE_ERRORED);
+ mode);
}
/**
@@ -2888,8 +2888,21 @@ final class InstallPackageHelper {
mPm.notifyPackageChanged(packageName, request.getAppId());
}
- if (!android.permission.flags.Flags.enhancedConfirmationModeApisEnabled()
- || !android.security.Flags.extendEcmToAllSettings()) {
+ // Set the OP_ACCESS_RESTRICTED_SETTINGS op, which is used by ECM (see {@link
+ // EnhancedConfirmationManager}) as a persistent state denoting whether an app is
+ // currently guarded by ECM, not guarded by ECM, or (in Android V+) that this should
+ // be decided later.
+ if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled()
+ && android.security.Flags.extendEcmToAllSettings()) {
+ final int appId = request.getAppId();
+ mPm.mHandler.post(() -> {
+ for (int userId : firstUserIds) {
+ // MODE_DEFAULT means that the app's guardedness will be decided lazily
+ setAccessRestrictedSettingsMode(packageName, appId, userId,
+ AppOpsManager.MODE_DEFAULT);
+ }
+ });
+ } else {
// Apply restricted settings on potentially dangerous packages. Needs to happen
// after appOpsManager is notified of the new package
if (request.getPackageSource() == PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
@@ -2898,7 +2911,9 @@ final class InstallPackageHelper {
final int appId = request.getAppId();
mPm.mHandler.post(() -> {
for (int userId : firstUserIds) {
- enableRestrictedSettings(packageName, appId, userId);
+ // MODE_ERRORED means that the app is explicitly guarded
+ setAccessRestrictedSettingsMode(packageName, appId, userId,
+ AppOpsManager.MODE_ERRORED);
}
});
}
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 57ea233c0a2b..4d07ab5cbb30 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -807,7 +807,7 @@ final class DefaultPermissionGrantPolicy {
getDefaultSystemHandlerActivityPackage(pm,
SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
- NOTIFICATION_PERMISSIONS, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS);
+ NOTIFICATION_PERMISSIONS);
}
// Voice recognition
@@ -875,6 +875,12 @@ final class DefaultPermissionGrantPolicy {
getDefaultSystemHandlerActivityPackage(pm, ACTION_TRACK, userId), userId,
SENSORS_PERMISSIONS);
}
+
+ // Allow voice search on wear
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm,
+ SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
+ userId, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS);
}
// Print Spooler
diff --git a/services/core/java/com/android/server/stats/pull/BatteryHealthUtility.java b/services/core/java/com/android/server/stats/pull/BatteryHealthUtility.java
new file mode 100644
index 000000000000..e0768fe1f0e5
--- /dev/null
+++ b/services/core/java/com/android/server/stats/pull/BatteryHealthUtility.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 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.stats.pull;
+
+import android.util.StatsEvent;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+
+/**
+ * Utility class to redact Battery Health data from HealthServiceWrapper
+ *
+ * @hide
+ */
+public abstract class BatteryHealthUtility {
+ /**
+ * Create a StatsEvent corresponding to the Battery Health data, the fields
+ * of which are redacted to preserve users' privacy.
+ * The redaction consists in truncating the timestamps to the Monday of the
+ * corresponding week, and reducing the battery serial into the last byte
+ * of its MD5.
+ */
+ public static StatsEvent buildStatsEvent(int atomTag,
+ android.hardware.health.BatteryHealthData data, int chargeStatus, int chargePolicy)
+ throws NoSuchAlgorithmException {
+ int manufacturingDate = secondsToWeekYYYYMMDD(data.batteryManufacturingDateSeconds);
+ int firstUsageDate = secondsToWeekYYYYMMDD(data.batteryFirstUsageSeconds);
+ long stateOfHealth = data.batteryStateOfHealth;
+ int partStatus = data.batteryPartStatus;
+ int serialHashTruncated = stringToIntHash(data.batterySerialNumber) & 0xFF; // Last byte
+
+ return FrameworkStatsLog.buildStatsEvent(atomTag, manufacturingDate, firstUsageDate,
+ (int) stateOfHealth, serialHashTruncated, partStatus, chargeStatus, chargePolicy);
+ }
+
+ private static int secondsToWeekYYYYMMDD(long seconds) {
+ Calendar calendar = Calendar.getInstance();
+ long millis = seconds * 1000L;
+
+ calendar.setTimeInMillis(millis);
+
+ // Truncate all date information, up to week, which is rounded to
+ // MONDAY
+ calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.US);
+
+ String formattedDate = sdf.format(calendar.getTime());
+
+ return Integer.parseInt(formattedDate);
+ }
+
+ private static int stringToIntHash(String data) throws NoSuchAlgorithmException {
+ if (data == null || data.isEmpty()) {
+ return 0;
+ }
+
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ byte[] hashBytes = digest.digest(data.getBytes());
+
+ // Convert to integer (simplest way, but potential for loss of information)
+ BigInteger bigInt = new BigInteger(1, hashBytes);
+ return bigInt.intValue();
+ }
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index c1b825b3f8d1..0041d39f4b2b 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -119,6 +119,8 @@ import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
+import android.os.BatteryManager;
+import android.os.BatteryProperty;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.BatteryStatsManager;
@@ -243,6 +245,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
@@ -769,6 +772,7 @@ public class StatsPullAtomService extends SystemService {
case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
case FrameworkStatsLog.BATTERY_VOLTAGE:
case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
+ case FrameworkStatsLog.BATTERY_HEALTH:
synchronized (mHealthHalLock) {
return pullHealthHalLocked(atomTag, data);
}
@@ -999,6 +1003,7 @@ public class StatsPullAtomService extends SystemService {
registerFullBatteryCapacity();
registerBatteryVoltage();
registerBatteryCycleCount();
+ registerBatteryHealth();
registerSettingsStats();
registerInstalledIncrementalPackages();
registerKeystoreStorageStats();
@@ -4365,7 +4370,15 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) {
+ private void registerBatteryHealth() {
+ int tagId = FrameworkStatsLog.BATTERY_HEALTH;
+ mStatsManager.setPullAtomCallback(tagId,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR, mStatsCallbackImpl);
+ }
+
+ @GuardedBy("mHealthHalLock")
+ private int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) {
if (mHealthService == null) {
return StatsManager.PULL_SKIP;
}
@@ -4396,6 +4409,44 @@ public class StatsPullAtomService extends SystemService {
case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
pulledValue = healthInfo.batteryCycleCount;
break;
+ case FrameworkStatsLog.BATTERY_HEALTH:
+ android.hardware.health.BatteryHealthData bhd;
+ try {
+ bhd = mHealthService.getBatteryHealthData();
+ } catch (RemoteException | IllegalStateException e) {
+ return StatsManager.PULL_SKIP;
+ }
+ if (bhd == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ StatsEvent batteryHealthEvent;
+ try {
+ BatteryProperty chargeStatusProperty = new BatteryProperty();
+ BatteryProperty chargePolicyProperty = new BatteryProperty();
+
+ if (0 > mHealthService.getProperty(
+ BatteryManager.BATTERY_PROPERTY_STATUS, chargeStatusProperty)) {
+ return StatsManager.PULL_SKIP;
+ }
+ if (0 > mHealthService.getProperty(
+ BatteryManager.BATTERY_PROPERTY_CHARGING_POLICY,
+ chargePolicyProperty)) {
+ return StatsManager.PULL_SKIP;
+ }
+ int chargeStatus = (int) chargeStatusProperty.getLong();
+ int chargePolicy = (int) chargePolicyProperty.getLong();
+ batteryHealthEvent = BatteryHealthUtility.buildStatsEvent(
+ atomTag, bhd, chargeStatus, chargePolicy);
+ pulledData.add(batteryHealthEvent);
+
+ return StatsManager.PULL_SUCCESS;
+ } catch (RemoteException | IllegalStateException e) {
+ Slog.e(TAG, "Failed to add pulled data", e);
+ } catch (NoSuchAlgorithmException e) {
+ Slog.e(TAG, "Could not find message digest algorithm", e);
+ }
+ return StatsManager.PULL_SKIP;
default:
return StatsManager.PULL_SKIP;
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 3e177c9fe8c6..a8dcaa8a90e1 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -102,7 +102,7 @@ import android.window.TransitionInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.Watchdog;
import com.android.server.pm.KnownPackages;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index dce496d42585..7d7592fa0838 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -386,7 +386,7 @@ import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.AttributeCache;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
diff --git a/services/core/java/com/android/server/wm/ActivityRefresher.java b/services/core/java/com/android/server/wm/ActivityRefresher.java
index 23a97089fd60..056c09eb0ce9 100644
--- a/services/core/java/com/android/server/wm/ActivityRefresher.java
+++ b/services/core/java/com/android/server/wm/ActivityRefresher.java
@@ -27,7 +27,7 @@ import android.content.res.Configuration;
import android.os.Handler;
import android.os.RemoteException;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 717c3998aba4..5bfe9d744975 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -127,7 +127,7 @@ import android.window.RemoteTransition;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
import com.android.server.pm.PackageArchiver;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 2109f5d5ab8f..dded1ca93270 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -260,7 +260,7 @@ import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.AttributeCache;
import com.android.internal.policy.KeyguardDismissCallback;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index cd5576fca2f9..d65a106a1079 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -148,7 +148,7 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.ReferrerIntent;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index 0013c5c63798..80671effdc98 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -345,7 +345,7 @@ class AnrController {
null /* processCpuTracker */, null /* lastPids */,
CompletableFuture.completedFuture(nativePids),
null /* logExceptionCreatingFile */, "Pre-dump", criticalEvents,
- Runnable::run, null/* AnrLatencyTracker */);
+ null /* extraHeaders */, Runnable::run, null/* AnrLatencyTracker */);
if (tracesFile != null) {
tracesFile.renameTo(
new File(tracesFile.getParent(), tracesFile.getName() + "_pre"));
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c2b9128daac5..bc7e84ae9f86 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -135,7 +135,7 @@ import android.view.animation.TranslateAnimation;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.DumpUtils.Dump;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index c55a1003f402..44b414f1ea7e 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -92,7 +92,7 @@ import android.view.WindowManager.TransitionType;
import android.window.ITaskFragmentOrganizer;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index a8cc2ae161cf..4554b210e3fd 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -30,7 +30,7 @@ import android.util.Slog;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 14ae918129f7..cb690394480e 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -61,7 +61,7 @@ import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index 0b2c851c4366..ba4ab7df8270 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -22,7 +22,7 @@ import android.graphics.Rect;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
import java.util.function.Supplier;
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index 0c751cfe4f46..92040177ad9e 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -32,7 +32,7 @@ import android.content.res.Configuration;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
/**
diff --git a/services/core/java/com/android/server/wm/CameraStateMonitor.java b/services/core/java/com/android/server/wm/CameraStateMonitor.java
index ea7edea7d4b3..a54141ce5230 100644
--- a/services/core/java/com/android/server/wm/CameraStateMonitor.java
+++ b/services/core/java/com/android/server/wm/CameraStateMonitor.java
@@ -26,7 +26,7 @@ import android.os.Handler;
import android.util.ArraySet;
import android.util.Slog;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index b795987f1d11..44202a2ae58e 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -48,7 +48,7 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.Xml;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index d70a88062ebd..7e7073c4a52c 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -42,7 +42,7 @@ import android.view.DisplayInfo;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.display.feature.DisplayManagerFlags;
/**
diff --git a/services/core/java/com/android/server/wm/ContentRecordingController.java b/services/core/java/com/android/server/wm/ContentRecordingController.java
index b5890856fa6f..283f819fc6ae 100644
--- a/services/core/java/com/android/server/wm/ContentRecordingController.java
+++ b/services/core/java/com/android/server/wm/ContentRecordingController.java
@@ -23,7 +23,7 @@ import android.annotation.Nullable;
import android.view.ContentRecordingSession;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* Orchestrates the handoff between displays if the recording session changes, and keeps track of
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index be44629a1fcf..3b999549b302 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -36,7 +36,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.utils.DisplayInfoOverrides.DisplayInfoFieldsUpdater;
import com.android.window.flags.Flags;
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
index 735c73a990cb..22fa88f12386 100644
--- a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -29,7 +29,7 @@ import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 0006bd250087..def495f3daa5 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -45,7 +45,7 @@ import android.window.DisplayAreaInfo;
import android.window.IDisplayAreaOrganizer;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 3dc3be9abf74..8f471d797904 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -33,7 +33,7 @@ import android.window.IDisplayAreaOrganizer;
import android.window.IDisplayAreaOrganizerController;
import android.window.WindowContainerToken;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 8c52288c4be5..bb596cc829c9 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -42,7 +42,7 @@ import android.window.WindowContainerToken;
import com.android.internal.annotations.Keep;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7ffffe97b646..b5b937775333 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -254,7 +254,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4a59fc2a8f15..b36fbd34866c 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -132,7 +132,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.policy.ForceShowNavBarSettingsObserver;
import com.android.internal.policy.GestureNavigationSettingsObserver;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.ScreenshotRequest;
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index afcf364d4729..f3ccc3b5aef8 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -80,7 +80,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index 6ecafdb03d20..beb376788367 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -42,7 +42,7 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.UiThread;
/**
diff --git a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
index 50b29ec965ea..f94b8c41b24a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
@@ -26,7 +26,7 @@ import android.annotation.Nullable;
import android.content.ActivityInfoProto;
import android.view.Surface;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* Defines the behavior of reversion from device rotation overrides.
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index c79565ae79fa..8bd8098b6be9 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.os.UserHandle.USER_SYSTEM;
import static android.view.Display.TYPE_VIRTUAL;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
@@ -27,6 +28,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.WindowConfiguration;
import android.os.Environment;
import android.util.ArrayMap;
@@ -42,6 +44,7 @@ import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider;
+import com.android.window.flags.Flags;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -53,6 +56,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
+import java.util.Set;
/**
* Implementation of {@link SettingsProvider} that reads the base settings provided in a display
@@ -91,11 +95,11 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
@NonNull
private ReadableSettings mBaseSettings;
@NonNull
- private final WritableSettings mOverrideSettings;
+ private WritableSettings mOverrideSettings;
DisplayWindowSettingsProvider() {
this(new AtomicFileStorage(getVendorSettingsFile()),
- new AtomicFileStorage(getOverrideSettingsFile()));
+ new AtomicFileStorage(getOverrideSettingsFileForUser(USER_SYSTEM)));
}
@VisibleForTesting
@@ -133,6 +137,48 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
mBaseSettings = new ReadableSettings(baseSettingsStorage);
}
+ /**
+ * Overrides the storage that should be used to save override settings for a user.
+ *
+ * @see #DATA_DISPLAY_SETTINGS_FILE_PATH
+ */
+ void setOverrideSettingsForUser(@UserIdInt int userId) {
+ if (!Flags.perUserDisplayWindowSettings()) {
+ return;
+ }
+ final AtomicFile settingsFile = getOverrideSettingsFileForUser(userId);
+ setOverrideSettingsStorage(new AtomicFileStorage(settingsFile));
+ }
+
+ /**
+ * Removes display override settings that are no longer associated with active displays.
+ * This is necessary because displays can be dynamically added or removed during
+ * the system's lifecycle (e.g., user switch, system server restart).
+ *
+ * @param root The root window container used to obtain the currently active displays.
+ */
+ void removeStaleDisplaySettings(@NonNull RootWindowContainer root) {
+ if (!Flags.perUserDisplayWindowSettings()) {
+ return;
+ }
+ final Set<String> displayIdentifiers = new ArraySet<>();
+ root.forAllDisplays(dc -> {
+ final String identifier = mOverrideSettings.getIdentifier(dc.getDisplayInfo());
+ displayIdentifiers.add(identifier);
+ });
+ mOverrideSettings.removeStaleDisplaySettings(displayIdentifiers);
+ }
+
+ /**
+ * Overrides the storage that should be used to save override settings.
+ *
+ * @see #setOverrideSettingsForUser(int)
+ */
+ @VisibleForTesting
+ void setOverrideSettingsStorage(@NonNull WritableSettingsStorage overrideSettingsStorage) {
+ mOverrideSettings = new WritableSettings(overrideSettingsStorage);
+ }
+
@Override
@NonNull
public SettingsEntry getSettings(@NonNull DisplayInfo info) {
@@ -302,6 +348,12 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
mVirtualDisplayIdentifiers.remove(identifier);
}
+ void removeStaleDisplaySettings(@NonNull Set<String> currentDisplayIdentifiers) {
+ if (mSettings.retainAll(currentDisplayIdentifiers)) {
+ writeSettings();
+ }
+ }
+
private void writeSettings() {
final FileData fileData = new FileData();
fileData.mIdentifierType = mIdentifierType;
@@ -332,9 +384,14 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
}
@NonNull
- private static AtomicFile getOverrideSettingsFile() {
- final File overrideSettingsFile = new File(Environment.getDataDirectory(),
- DATA_DISPLAY_SETTINGS_FILE_PATH);
+ private static AtomicFile getOverrideSettingsFileForUser(@UserIdInt int userId) {
+ final File directory;
+ if (userId == USER_SYSTEM || !Flags.perUserDisplayWindowSettings()) {
+ directory = Environment.getDataDirectory();
+ } else {
+ directory = Environment.getDataSystemCeDirectory(userId);
+ }
+ final File overrideSettingsFile = new File(directory, DATA_DISPLAY_SETTINGS_FILE_PATH);
return new AtomicFile(overrideSettingsFile, WM_DISPLAY_COMMIT_TAG);
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index e3827aa86d9e..4be5bad644f7 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -64,7 +64,7 @@ import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.view.IDragAndDropPermissions;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index a21ba2603ec6..c66d6596226a 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -35,7 +35,7 @@ import android.view.InputApplicationHandle;
import android.view.InputChannel;
import android.window.InputTransferToken;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.input.InputManagerService;
/**
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 156e9f98b7a7..91c61b1bd550 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -40,7 +40,7 @@ import android.view.inputmethod.Flags;
import android.view.inputmethod.ImeTracker;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8035a298e45a..74dbd15d1399 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -66,7 +66,7 @@ import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.SoftInputShowHideReason;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.inputmethod.InputMethodManagerInternal;
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index f68b67f626f9..33dea54574e6 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -48,7 +48,7 @@ import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.TriFunction;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a967f7af3bb9..348384203fba 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -41,7 +41,7 @@ import android.view.InsetsState;
import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.inputmethod.InputMethodManagerInternal;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 0f9998cafc4e..0dadade38ddb 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -63,7 +63,7 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.telephony.CellBroadcastUtils;
import com.android.internal.widget.LockPatternUtils;
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
index 36c092b3f535..1a895ea22f36 100644
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -35,7 +35,7 @@ import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.WindowManager;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 4c797f8d17ea..3cf301c1d730 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -36,7 +36,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.DeviceStateController.DeviceState;
public class PhysicalDisplaySwitchTransitionLauncher {
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index e07b72a05123..6f2528085d74 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -80,7 +80,7 @@ import android.view.WindowInsets;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 469cc647b1b5..c592caf488ad 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -42,7 +42,7 @@ import android.os.Trace;
import android.util.Slog;
import android.view.IRecentsAnimationRunner;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 312c4befb0d6..6f947135b789 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -64,7 +64,7 @@ import android.window.WindowAnimationState;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 63bbb3140bfb..a8edaebd24a6 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -45,7 +45,7 @@ import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FastPrintWriter;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
diff --git a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
index c22b07a4efa1..e4962bffc570 100644
--- a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
+++ b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
@@ -28,7 +28,7 @@ import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index d497d8cbf9cd..243dbc78998d 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -24,7 +24,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Debug;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
import java.util.function.Consumer;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6abd4887645b..d1f1cab43b8a 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -141,7 +141,7 @@ import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.LocalServices;
@@ -2158,6 +2158,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Use Task#setBoundsUnchecked to skip checking windowing mode as the windowing mode
// will be updated later after this is collected in transition.
rootTask.setBoundsUnchecked(taskFragment.getBounds());
+ // The exit-PIP activity resumes early for seamless transition. In certain
+ // scenarios, this introduces unintended addition to recents. To address this,
+ // we mark the root task for automatic removal from recents. This ensures that
+ // after the pinned activity reparents to its original task, the root task is
+ // automatically removed from the recents list.
+ rootTask.autoRemoveRecents = true;
// Move the last recents animation transaction from original task to the new one.
if (task.mLastRecentsAnimationTransaction != null) {
diff --git a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
index 967f415d2c11..ad4faab1e106 100644
--- a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
+++ b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
@@ -33,7 +33,7 @@ import android.view.ContentRecordingSession;
import android.window.IScreenRecordingCallback;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index e7bffdfd448b..3eb321804520 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -57,7 +57,7 @@ import android.window.ScreenCapture;
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.display.DisplayControl;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 4a0239bc29b2..9addce6d5f08 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -84,7 +84,7 @@ import android.window.OnBackInvokedCallbackInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.logging.MetricsLoggerWrapper;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.wm.WindowManagerService.H;
import com.android.window.flags.Flags;
diff --git a/services/core/java/com/android/server/wm/SmoothDimmer.java b/services/core/java/com/android/server/wm/SmoothDimmer.java
index b5d94a2efbdf..2b4d901e8231 100644
--- a/services/core/java/com/android/server/wm/SmoothDimmer.java
+++ b/services/core/java/com/android/server/wm/SmoothDimmer.java
@@ -26,7 +26,7 @@ import android.view.Surface;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
class SmoothDimmer extends Dimmer {
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index c632714bd8ce..9cfd39688c12 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -33,7 +33,7 @@ import android.view.SurfaceControl.Transaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
import java.io.StringWriter;
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index 0c36d27603c8..34abf23daa2a 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -31,7 +31,7 @@ import android.view.SurfaceControl;
import android.window.ScreenCapture;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* This class handles "freezing" of an Animatable. The Animatable in question should implement
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f9c53aa35bd8..52a1ed98a4ce 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -181,7 +181,7 @@ import android.window.WindowContainerToken;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index eff831552320..eaf3012a3b11 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -52,7 +52,7 @@ import android.view.SurfaceControl;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 3cd071bd329e..9b2c022df963 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -106,7 +106,7 @@ import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOrganizerToken;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.am.HostingRecord;
import com.android.server.pm.pkg.AndroidPackage;
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 26315f9cc2c3..b6b6cf2dc430 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -59,7 +59,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import java.lang.annotation.Retention;
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index b24d53b26caa..6e36d427bd13 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -57,7 +57,7 @@ import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 9b3fb6b881c4..972dd2e382cc 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -59,7 +59,7 @@ import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.TaskResizingAlgorithm;
import com.android.internal.policy.TaskResizingAlgorithm.CtrlType;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.concurrent.CompletableFuture;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index e698a3d95841..35a77022737f 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -106,7 +106,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 08123232866b..f4ff404c2bff 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -53,7 +53,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.FgThread;
import com.android.window.flags.Flags;
diff --git a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
index fa2d9bf21dee..c0dc4247a7c2 100644
--- a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
+++ b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
@@ -40,7 +40,7 @@ import android.window.ITrustedPresentationListener;
import android.window.TrustedPresentationThresholds;
import android.window.WindowInfosListener;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.utils.RegionUtils;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 4a5a20e57804..fffe692a39dd 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -27,7 +27,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 43f7ecc6ab1c..3b5a6058e803 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -57,7 +57,7 @@ import android.window.ScreenCapture;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.wallpaper.WallpaperCropper.WallpaperCropUtils;
import com.android.window.flags.Flags;
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index b7f8505b4a65..31156de5debf 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -31,7 +31,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.SparseArray;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import java.util.function.Consumer;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 8afcf0e1e05a..03342d316d1c 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -34,7 +34,7 @@ import android.util.TimeUtils;
import android.view.Choreographer;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 1f31af68c693..325ef0d184df 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -111,7 +111,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.AnimationType;
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
index b000a9841d06..57fc4c7a6860 100644
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
@@ -39,7 +39,7 @@ import android.view.SurfaceControl.Builder;
import android.view.SurfaceControl.Transaction;
import android.view.animation.Animation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.AnimationType;
diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java
index 21f251fbc736..cd785e5174e5 100644
--- a/services/core/java/com/android/server/wm/WindowContextListenerController.java
+++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java
@@ -39,7 +39,7 @@ import android.view.WindowManager.LayoutParams.WindowType;
import android.window.WindowContext;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.Objects;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 521560936d81..57b8040ef0ac 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -335,7 +335,7 @@ import com.android.internal.policy.IShortcutService;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.protolog.LegacyProtoLogImpl;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
@@ -3743,6 +3743,8 @@ public class WindowManagerService extends IWindowManager.Stub
null /* trigger */, null /* remote */, null /* disp */);
}
mCurrentUserId = newUserId;
+ mDisplayWindowSettingsProvider.setOverrideSettingsForUser(newUserId);
+ mDisplayWindowSettingsProvider.removeStaleDisplaySettings(mRoot);
mPolicy.setCurrentUserLw(newUserId);
mKeyguardDisableHandler.setCurrentUser(newUserId);
@@ -5479,6 +5481,9 @@ public class WindowManagerService extends IWindowManager.Stub
// DisplayWindowSettings are applied. In addition, wide-color/hdr/isTouchDevice also
// affect the Configuration.
mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
+ // Per-user display settings may leave outdated settings after user switches, especially
+ // during reboots starting with the default user without setCurrentUser called.
+ mDisplayWindowSettingsProvider.removeStaleDisplaySettings(mRoot);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 1f06bfac5668..6febe80166f4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -51,7 +51,7 @@ import com.android.internal.os.ByteTransferPipe;
import com.android.internal.protolog.LegacyProtoLogImpl;
import com.android.internal.protolog.PerfettoProtoLogImpl;
import com.android.internal.protolog.common.IProtoLog;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.IoThread;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d26df7a67ad5..de584573fcaf 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -124,7 +124,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.pm.LauncherAppsService.LauncherAppsServiceInternal;
@@ -1105,6 +1105,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
break;
}
if (activity.isVisible() || activity.isVisibleRequested()) {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
// Prevent the transition from being executed too early if the activity is
// visible.
activity.finishIfPossible("finish-activity-op", false /* oomAdj */);
@@ -1122,6 +1123,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
final SafeActivityOptions safeOptions =
SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
caller.mPid, caller.mUid, taskId, safeOptions));
break;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index b8780726f992..60d3e787cac4 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -82,7 +82,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d845968767e5..fec1175785ea 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -250,7 +250,7 @@ import android.window.OnBackInvokedCallbackInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.policy.WindowManagerPolicy;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9ecd49213237..397a6357fb66 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -62,7 +62,7 @@ import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import com.android.server.policy.WindowManagerPolicy;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 4456a94ef510..d9766e0dfa61 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -36,7 +36,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
import android.view.WindowContentFrameStats;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 4dca23bc03c7..11ef2cde65a9 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -47,7 +47,7 @@ import android.view.WindowManager;
import android.view.WindowManager.LayoutParams.WindowType;
import android.window.WindowContext;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index b0e71bda787a..ba5323ee1f8f 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -37,7 +37,7 @@ import android.view.Choreographer;
import com.android.internal.protolog.LegacyProtoLogImpl;
import com.android.internal.protolog.common.IProtoLog;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.TraceBuffer;
import java.io.File;
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index c558aae5248e..7ed23cd7df3e 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -230,18 +230,7 @@ class AppIdPermissionPolicy : SchemePolicy() {
}
val isSoftRestricted =
if (permission.isSoftRestricted && !isExempt) {
- val targetSdkVersion =
- reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT) {
- targetSdkVersion,
- packageState ->
- if (permissionName in packageState.androidPackage!!.requestedPermissions) {
- targetSdkVersion.coerceAtMost(
- packageState.androidPackage!!.targetSdkVersion
- )
- } else {
- targetSdkVersion
- }
- }
+ val targetSdkVersion = getAppIdTargetSdkVersion(appId, permissionName)
!anyPackageInAppId(appId) {
permissionName in it.androidPackage!!.requestedPermissions &&
isSoftRestrictedPermissionExemptForPackage(
@@ -718,18 +707,8 @@ class AppIdPermissionPolicy : SchemePolicy() {
// If the app is updated, and has scoped storage permissions, then it is possible that the
// app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
- val oldTargetSdkVersion =
- reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, oldState) {
- targetSdkVersion,
- packageState ->
- targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
- }
- val newTargetSdkVersion =
- reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, newState) {
- targetSdkVersion,
- packageState ->
- targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
- }
+ val oldTargetSdkVersion = getAppIdTargetSdkVersion(appId, null, oldState)
+ val newTargetSdkVersion = getAppIdTargetSdkVersion(appId, null, newState)
@Suppress("ConvertTwoComparisonsToRangeCheck")
val isTargetSdkVersionDowngraded =
oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
@@ -1115,10 +1094,9 @@ class AppIdPermissionPolicy : SchemePolicy() {
}
private fun MutateStateScope.inheritImplicitPermissionStates(appId: Int, userId: Int) {
- var targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
+ val targetSdkVersion = getAppIdTargetSdkVersion(appId, null)
val implicitPermissions = MutableIndexedSet<String>()
forEachPackageInAppId(appId) {
- targetSdkVersion = targetSdkVersion.coerceAtMost(it.androidPackage!!.targetSdkVersion)
implicitPermissions += it.androidPackage!!.implicitPermissions
}
implicitPermissions.forEachIndexed implicitPermissions@{ _, implicitPermissionName ->
@@ -1418,6 +1396,22 @@ class AppIdPermissionPolicy : SchemePolicy() {
else -> false
}
+ private fun MutateStateScope.getAppIdTargetSdkVersion(
+ appId: Int,
+ permissionName: String?,
+ state: AccessState = newState
+ ): Int =
+ reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, state) {
+ targetSdkVersion,
+ packageState ->
+ val androidPackage = packageState.androidPackage!!
+ if (permissionName == null || permissionName in androidPackage.requestedPermissions) {
+ targetSdkVersion.coerceAtMost(androidPackage.targetSdkVersion)
+ } else {
+ targetSdkVersion
+ }
+ }
+
private inline fun MutateStateScope.anyPackageInAppId(
appId: Int,
state: AccessState = newState,
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
index 9acebf71ee18..33ea9b459b31 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -50,6 +50,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
@@ -73,9 +74,8 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
@Before
public void setUp() throws RemoteException {
super.setUp();
- mVisibilityApplier =
- (DefaultImeVisibilityApplier) mInputMethodManagerService.getVisibilityApplier();
synchronized (ImfLock.class) {
+ mVisibilityApplier = mInputMethodManagerService.getVisibilityApplierLocked();
mUserId = mInputMethodManagerService.getCurrentImeUserIdLocked();
mInputMethodManagerService.setAttachedClientForTesting(requireNonNull(
mInputMethodManagerService.getClientStateLocked(mMockInputMethodClient)));
@@ -106,7 +106,7 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
assertThrows(IllegalArgumentException.class, () -> {
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
- STATE_INVALID, mUserId);
+ STATE_INVALID, eq(SoftInputShowHideReason.NOT_SET), mUserId);
}
});
}
@@ -116,7 +116,7 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
final var statsToken = ImeTracker.Token.empty();
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_SHOW_IME,
- mUserId);
+ eq(SoftInputShowHideReason.NOT_SET), mUserId);
}
verify(mMockWindowManagerInternal).showImePostLayout(eq(mWindowToken), eq(statsToken));
}
@@ -126,7 +126,7 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
final var statsToken = ImeTracker.Token.empty();
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME,
- mUserId);
+ eq(SoftInputShowHideReason.NOT_SET), mUserId);
}
verify(mMockWindowManagerInternal).hideIme(eq(mWindowToken), anyInt() /* displayId */,
eq(statsToken));
@@ -137,7 +137,7 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
- STATE_HIDE_IME_EXPLICIT, mUserId);
+ STATE_HIDE_IME_EXPLICIT, eq(SoftInputShowHideReason.NOT_SET), mUserId);
}
verifyHideSoftInput(true, true);
}
@@ -147,7 +147,7 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
- STATE_HIDE_IME_NOT_ALWAYS, mUserId);
+ STATE_HIDE_IME_NOT_ALWAYS, eq(SoftInputShowHideReason.NOT_SET), mUserId);
}
verifyHideSoftInput(true, true);
}
@@ -156,7 +156,7 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
public void testApplyImeVisibility_showImeImplicit() throws Exception {
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
- STATE_SHOW_IME_IMPLICIT, mUserId);
+ STATE_SHOW_IME_IMPLICIT, eq(SoftInputShowHideReason.NOT_SET), mUserId);
}
verifyShowSoftInput(true, true, 0 /* showFlags */);
}
@@ -177,7 +177,7 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
// Verify hideIme will apply the expected displayId when the default IME
// visibility applier app STATE_HIDE_IME.
mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME,
- mUserId);
+ eq(SoftInputShowHideReason.NOT_SET), mUserId);
verify(mInputMethodManagerService.mWindowManagerInternal).hideIme(
eq(mWindowToken), eq(displayIdToShowIme), eq(statsToken));
}
@@ -224,7 +224,8 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
// the IME hidden state.
// The unbind will cancel the previous stats token, and create a new one internally.
verify(mVisibilityApplier).applyImeVisibility(
- eq(mWindowToken), any(), eq(STATE_HIDE_IME), eq(mUserId) /* userId */);
+ eq(mWindowToken), any(), eq(STATE_HIDE_IME),
+ eq(SoftInputShowHideReason.NOT_SET), eq(mUserId) /* userId */);
verify(mInputMethodManagerService.mWindowManagerInternal).hideIme(
eq(mWindowToken), eq(displayIdToShowIme), and(not(eq(statsToken)), notNull()));
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
index a22cacbcb5df..337d5c1faf94 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
@@ -58,8 +58,8 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
/**
- * Test the behavior of {@link ImeVisibilityStateComputer} and {@link ImeVisibilityApplier} when
- * requesting the IME visibility.
+ * Test the behavior of {@link ImeVisibilityStateComputer} and {@link DefaultImeVisibilityApplier}
+ * when requesting the IME visibility.
*
* <p> Build/Install/Run:
* atest FrameworksInputMethodSystemServerTests:ImeVisibilityStateComputerTest
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index 42bd75a7a67e..80eab112d814 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -189,6 +189,7 @@ public class InputMethodManagerServiceTestBase {
// Injecting and mocked InputMethodBindingController and InputMethod.
mMockInputMethodInvoker = IInputMethodInvoker.create(mMockInputMethod);
mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mMockIInputManager);
+ when(mMockInputMethodBindingController.getUserId()).thenReturn(mCallingUserId);
synchronized (ImfLock.class) {
when(mMockInputMethodBindingController.getCurMethod())
.thenReturn(mMockInputMethodInvoker);
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
index f9f45057f57f..e2f3eec1a20b 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
@@ -106,7 +106,7 @@ public final class UserDataRepositoryTest {
// Assert UserDataRepository called the InputMethodBindingController creator function.
verify(bindingControllerFactorySpy).apply(ANY_USER_ID);
- assertThat(allUserData.get(0).mBindingController.mUserId).isEqualTo(ANY_USER_ID);
+ assertThat(allUserData.get(0).mBindingController.getUserId()).isEqualTo(ANY_USER_ID);
}
@Test
@@ -149,7 +149,7 @@ public final class UserDataRepositoryTest {
assertThat(allUserData.get(0).mUserId).isEqualTo(ANY_USER_ID);
// Assert UserDataRepository called the InputMethodBindingController creator function.
- assertThat(allUserData.get(0).mBindingController.mUserId).isEqualTo(ANY_USER_ID);
+ assertThat(allUserData.get(0).mBindingController.getUserId()).isEqualTo(ANY_USER_ID);
}
private List<UserDataRepository.UserData> collectUserData(UserDataRepository repository) {
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 bb774eec9d4e..7b8b712c1aee 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1707,7 +1707,8 @@ public final class DisplayPowerControllerTest {
int initState = Display.STATE_OFF;
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
- when(mDisplayOffloadSession.blockScreenOn(any())).thenReturn(true);
+ ArgumentCaptor<Runnable> argumentCaptor = ArgumentCaptor.forClass(Runnable.class);
+ when(mDisplayOffloadSession.blockScreenOn(argumentCaptor.capture())).thenReturn(true);
// Start with OFF.
when(mHolder.displayPowerState.getScreenState()).thenReturn(initState);
@@ -1721,8 +1722,7 @@ public final class DisplayPowerControllerTest {
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1); // Run updatePowerState
- ArgumentCaptor<Runnable> argumentCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mDisplayOffloadSession).blockScreenOn(argumentCaptor.capture());
+ verify(mDisplayOffloadSession).blockScreenOn(any());
// Unblocked
argumentCaptor.getValue().run();
diff --git a/services/tests/servicestests/src/com/android/server/autofill/RequestIdTest.java b/services/tests/servicestests/src/com/android/server/autofill/RequestIdTest.java
index 6d56c417f789..60c3659202be 100644
--- a/services/tests/servicestests/src/com/android/server/autofill/RequestIdTest.java
+++ b/services/tests/servicestests/src/com/android/server/autofill/RequestIdTest.java
@@ -17,17 +17,25 @@ package com.android.server.autofill;
import static com.google.common.truth.Truth.assertThat;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.ArrayList;
-import java.util.List;
-
@RunWith(JUnit4.class)
public class RequestIdTest {
+ private static final int TEST_DATASET_SIZE = 300;
+ private static final int TEST_WRAP_SIZE = 50; // Number of request ids before wrap happens
+ private static final String TAG = "RequestIdTest";
+
List<Integer> datasetPrimaryNoWrap = new ArrayList<>();
List<Integer> datasetPrimaryWrap = new ArrayList<>();
List<Integer> datasetSecondaryNoWrap = new ArrayList<>();
@@ -35,151 +43,200 @@ public class RequestIdTest {
List<Integer> datasetMixedNoWrap = new ArrayList<>();
List<Integer> datasetMixedWrap = new ArrayList<>();
- @Before
- public void setup() throws Exception {
- int datasetSize = 300;
+ List<Integer> manualWrapRequestIdList = Arrays.asList(3, 9, 15,
+ RequestId.MAX_SECONDARY_REQUEST_ID - 5,
+ RequestId.MAX_SECONDARY_REQUEST_ID - 3);
+ List<Integer> manualNoWrapRequestIdList =Arrays.asList(2, 6, 10, 14, 18, 22, 26, 30);
+ List<Integer> manualOneElementRequestIdList = Arrays.asList(1);
+
+ @Before
+ public void setup() throws IllegalArgumentException {
+ Slog.d(TAG, "setup()");
{ // Generate primary only ids that do not wrap
- RequestId requestId = new RequestId(0);
- for (int i = 0; i < datasetSize; i++) {
+ RequestId requestId = new RequestId(RequestId.MIN_PRIMARY_REQUEST_ID);
+ for (int i = 0; i < TEST_DATASET_SIZE; i++) {
datasetPrimaryNoWrap.add(requestId.nextId(false));
}
+ Collections.sort(datasetPrimaryNoWrap);
}
{ // Generate primary only ids that wrap
- RequestId requestId = new RequestId(0xff00);
- for (int i = 0; i < datasetSize; i++) {
+ RequestId requestId = new RequestId(RequestId.MAX_PRIMARY_REQUEST_ID -
+ TEST_WRAP_SIZE * 2);
+ for (int i = 0; i < TEST_DATASET_SIZE; i++) {
datasetPrimaryWrap.add(requestId.nextId(false));
}
+ Collections.sort(datasetPrimaryWrap);
}
{ // Generate SECONDARY only ids that do not wrap
- RequestId requestId = new RequestId(0);
- for (int i = 0; i < datasetSize; i++) {
+ RequestId requestId = new RequestId(RequestId.MIN_SECONDARY_REQUEST_ID);
+ for (int i = 0; i < TEST_DATASET_SIZE; i++) {
datasetSecondaryNoWrap.add(requestId.nextId(true));
}
+ Collections.sort(datasetSecondaryNoWrap);
}
{ // Generate SECONDARY only ids that wrap
- RequestId requestId = new RequestId(0xff00);
- for (int i = 0; i < datasetSize; i++) {
+ RequestId requestId = new RequestId(RequestId.MAX_SECONDARY_REQUEST_ID -
+ TEST_WRAP_SIZE * 2);
+ for (int i = 0; i < TEST_DATASET_SIZE; i++) {
datasetSecondaryWrap.add(requestId.nextId(true));
}
+ Collections.sort(datasetSecondaryWrap);
}
{ // Generate MIXED only ids that do not wrap
- RequestId requestId = new RequestId(0);
- for (int i = 0; i < datasetSize; i++) {
+ RequestId requestId = new RequestId(RequestId.MIN_REQUEST_ID);
+ for (int i = 0; i < TEST_DATASET_SIZE; i++) {
datasetMixedNoWrap.add(requestId.nextId(i % 2 != 0));
}
+ Collections.sort(datasetMixedNoWrap);
}
{ // Generate MIXED only ids that wrap
- RequestId requestId = new RequestId(0xff00);
- for (int i = 0; i < datasetSize; i++) {
+ RequestId requestId = new RequestId(RequestId.MAX_REQUEST_ID -
+ TEST_WRAP_SIZE);
+ for (int i = 0; i < TEST_DATASET_SIZE; i++) {
datasetMixedWrap.add(requestId.nextId(i % 2 != 0));
}
+ Collections.sort(datasetMixedWrap);
}
+ Slog.d(TAG, "finishing setup()");
}
@Test
public void testRequestIdLists() {
+ Slog.d(TAG, "testRequestIdLists()");
for (int id : datasetPrimaryNoWrap) {
assertThat(RequestId.isSecondaryProvider(id)).isFalse();
- assertThat(id >= 0).isTrue();
- assertThat(id < 0xffff).isTrue();
+ assertThat(id).isAtLeast(RequestId.MIN_PRIMARY_REQUEST_ID);
+ assertThat(id).isAtMost(RequestId.MAX_PRIMARY_REQUEST_ID);
}
for (int id : datasetPrimaryWrap) {
assertThat(RequestId.isSecondaryProvider(id)).isFalse();
- assertThat(id >= 0).isTrue();
- assertThat(id < 0xffff).isTrue();
+ assertThat(id).isAtLeast(RequestId.MIN_PRIMARY_REQUEST_ID);
+ assertThat(id).isAtMost(RequestId.MAX_PRIMARY_REQUEST_ID);
}
for (int id : datasetSecondaryNoWrap) {
assertThat(RequestId.isSecondaryProvider(id)).isTrue();
- assertThat(id >= 0).isTrue();
- assertThat(id < 0xffff).isTrue();
+ assertThat(id).isAtLeast(RequestId.MIN_SECONDARY_REQUEST_ID);
+ assertThat(id).isAtMost(RequestId.MAX_SECONDARY_REQUEST_ID);
}
for (int id : datasetSecondaryWrap) {
assertThat(RequestId.isSecondaryProvider(id)).isTrue();
- assertThat(id >= 0).isTrue();
- assertThat(id < 0xffff).isTrue();
+ assertThat(id).isAtLeast(RequestId.MIN_SECONDARY_REQUEST_ID);
+ assertThat(id).isAtMost(RequestId.MAX_SECONDARY_REQUEST_ID);
}
}
@Test
- public void testRequestIdGeneration() {
- RequestId requestId = new RequestId(0);
+ public void testCreateNewRequestId() {
+ Slog.d(TAG, "testCreateNewRequestId()");
+ for (int i = 0; i < 100000; i++) {
+ RequestId requestId = new RequestId();
+ assertThat(requestId.getRequestId()).isAtLeast(RequestId.MIN_REQUEST_ID);
+ assertThat(requestId.getRequestId()).isAtMost(RequestId.MAX_START_ID);
+ }
+ }
+ @Test
+ public void testGetNextRequestId() throws IllegalArgumentException{
+ Slog.d(TAG, "testGetNextRequestId()");
+ RequestId requestId = new RequestId();
// Large Primary
for (int i = 0; i < 100000; i++) {
int y = requestId.nextId(false);
assertThat(RequestId.isSecondaryProvider(y)).isFalse();
- assertThat(y >= 0).isTrue();
- assertThat(y < 0xffff).isTrue();
+ assertThat(y).isAtLeast(RequestId.MIN_PRIMARY_REQUEST_ID);
+ assertThat(y).isAtMost(RequestId.MAX_PRIMARY_REQUEST_ID);
}
// Large Secondary
- requestId = new RequestId(0);
+ requestId = new RequestId();
for (int i = 0; i < 100000; i++) {
int y = requestId.nextId(true);
assertThat(RequestId.isSecondaryProvider(y)).isTrue();
- assertThat(y >= 0).isTrue();
- assertThat(y < 0xffff).isTrue();
+ assertThat(y).isAtLeast(RequestId.MIN_SECONDARY_REQUEST_ID);
+ assertThat(y).isAtMost(RequestId.MAX_SECONDARY_REQUEST_ID);
}
// Large Mixed
- requestId = new RequestId(0);
+ requestId = new RequestId();
for (int i = 0; i < 50000; i++) {
int y = requestId.nextId(i % 2 != 0);
- assertThat(RequestId.isSecondaryProvider(y)).isEqualTo(i % 2 == 0);
- assertThat(y >= 0).isTrue();
- assertThat(y < 0xffff).isTrue();
+ assertThat(y).isAtLeast(RequestId.MIN_REQUEST_ID);
+ assertThat(y).isAtMost(RequestId.MAX_REQUEST_ID);
}
}
@Test
public void testGetLastRequestId() {
- // In this test, request ids are generated FIFO, so the last entry is also the last
- // request
+ Slog.d(TAG, "testGetLastRequestId()");
- { // Primary no wrap
- int lastIdIndex = datasetPrimaryNoWrap.size() - 1;
- int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetPrimaryNoWrap);
- assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
+ { // Primary no wrap
+ int lastIdIndex = datasetPrimaryNoWrap.size() - 1;
+ int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetPrimaryNoWrap);
+ assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
}
- { // Primary wrap
- int lastIdIndex = datasetPrimaryWrap.size() - 1;
+ { // Primary wrap
+ // The last index would be the # of request ids left after wrap
+ // minus 1 (index starts at 0)
+ int lastIdIndex = TEST_DATASET_SIZE - TEST_WRAP_SIZE - 1;
int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetPrimaryWrap);
- assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
+ assertThat(lastComputedIdIndex).isEqualTo(lastIdIndex);
}
- { // Secondary no wrap
+ { // Secondary no wrap
int lastIdIndex = datasetSecondaryNoWrap.size() - 1;
int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetSecondaryNoWrap);
assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
}
- { // Secondary wrap
- int lastIdIndex = datasetSecondaryWrap.size() - 1;
+ { // Secondary wrap
+ int lastIdIndex = TEST_DATASET_SIZE - TEST_WRAP_SIZE - 1;
int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetSecondaryWrap);
assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
}
- { // Mixed no wrap
+ { // Mixed no wrap
int lastIdIndex = datasetMixedNoWrap.size() - 1;
int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetMixedNoWrap);
assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
}
- { // Mixed wrap
- int lastIdIndex = datasetMixedWrap.size() - 1;
+ { // Mixed wrap
+ int lastIdIndex = TEST_DATASET_SIZE - TEST_WRAP_SIZE - 1;
int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetMixedWrap);
assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
}
+ { // Manual wrap
+ int lastIdIndex = 2; // [3, 9, 15,
+ // MAX_SECONDARY_REQUEST_ID - 5, MAX_SECONDARY_REQUEST_ID - 3]
+ int lastComputedIdIndex = RequestId.getLastRequestIdIndex(manualWrapRequestIdList);
+ assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
+ }
+
+ { // Manual no wrap
+ int lastIdIndex = manualNoWrapRequestIdList.size() - 1; // [2, 6, 10, 14,
+ // 18, 22, 26, 30]
+ int lastComputedIdIndex = RequestId.getLastRequestIdIndex(manualNoWrapRequestIdList);
+ assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
+
+ }
+
+ { // Manual one element
+ int lastIdIndex = 0; // [1]
+ int lastComputedIdIndex = RequestId.getLastRequestIdIndex(
+ manualOneElementRequestIdList);
+ assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex);
+
+ }
}
}
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index b2922945aff9..6ba2c7010cf3 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -28,7 +28,7 @@ genrule {
],
tools: ["protologtool"],
cmd: "$(location protologtool) transform-protolog-calls " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
"--loggroups-jar $(location :protolog-groups) " +
// Used for the ProtoLogIntegrationTest, where don't test decoding or writing to file
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 7d9fdd507235..3fcf3042ab94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -24,9 +24,12 @@ import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import static org.testng.Assert.assertFalse;
import android.annotation.Nullable;
@@ -55,6 +58,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
+import java.util.function.Consumer;
/**
* Tests for the {@link DisplayWindowSettingsProvider} class.
@@ -128,9 +132,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
// Update settings with new value, should trigger write to injector.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
- SettingsEntry overrideSettings = provider.getOverrideSettings(mPrimaryDisplayInfo);
- overrideSettings.mForcedDensity = 200;
- provider.updateOverrideSettings(mPrimaryDisplayInfo, overrideSettings);
+ updateOverrideSettings(provider, mPrimaryDisplayInfo,
+ overrideSettings -> overrideSettings.mForcedDensity = 200);
assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
// Verify that display identifier was updated.
@@ -167,7 +170,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
}
@Test
- public void testReadingDisplaySettingsFromStorage_secondayVendorDisplaySettingsLocation() {
+ public void testReadingDisplaySettingsFromStorage_secondaryVendorDisplaySettingsLocation() {
final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
prepareSecondaryDisplaySettings(displayIdentifier);
@@ -216,11 +219,11 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
// Write some settings to storage.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
- SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- overrideSettings.mShouldShowSystemDecors = true;
- overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
- overrideSettings.mDontMoveToTop = true;
- provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ updateOverrideSettings(provider, secondaryDisplayInfo, overrideSettings -> {
+ overrideSettings.mShouldShowSystemDecors = true;
+ overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
+ overrideSettings.mDontMoveToTop = true;
+ });
assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
// Verify that settings were stored correctly.
@@ -235,6 +238,29 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
}
@Test
+ public void testWritingDisplaySettingsToStorage_secondaryUserDisplaySettingsLocation() {
+ final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
+ final DisplayInfo displayInfo = mPrimaryDisplay.getDisplayInfo();
+ final TestStorage secondaryUserOverrideSettingsStorage = new TestStorage();
+ final SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mForcedDensity = 356;
+
+ // Write some settings to storage from default user.
+ updateOverrideSettings(provider, displayInfo, settings -> settings.mForcedDensity = 356);
+ assertThat(mOverrideSettingsStorage.wasWriteSuccessful()).isTrue();
+
+ // Now switch to secondary user override settings and write some settings.
+ provider.setOverrideSettingsStorage(secondaryUserOverrideSettingsStorage);
+ updateOverrideSettings(provider, displayInfo, settings -> settings.mForcedDensity = 420);
+ assertThat(secondaryUserOverrideSettingsStorage.wasWriteSuccessful()).isTrue();
+
+ // Switch back to primary and assert default user settings remain unchanged.
+ provider.setOverrideSettingsStorage(mOverrideSettingsStorage);
+ assertThat(provider.getOverrideSettings(displayInfo)).isEqualTo(expectedSettings);
+ }
+
+ @Test
public void testDoNotWriteVirtualDisplaySettingsToStorage() throws Exception {
final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
secondaryDisplayInfo.type = TYPE_VIRTUAL;
@@ -242,11 +268,11 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
// No write to storage on virtual display change.
final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
- final SettingsEntry virtualSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- virtualSettings.mShouldShowSystemDecors = true;
- virtualSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
- virtualSettings.mDontMoveToTop = true;
- provider.updateOverrideSettings(secondaryDisplayInfo, virtualSettings);
+ updateOverrideSettings(provider, secondaryDisplayInfo, virtualSettings -> {
+ virtualSettings.mShouldShowSystemDecors = true;
+ virtualSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
+ virtualSettings.mDontMoveToTop = true;
+ });
assertFalse(mOverrideSettingsStorage.wasWriteSuccessful());
}
@@ -263,10 +289,10 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
// Write some settings to storage.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
- SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- overrideSettings.mShouldShowSystemDecors = true;
- overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
- provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ updateOverrideSettings(provider, secondaryDisplayInfo, overrideSettings -> {
+ overrideSettings.mShouldShowSystemDecors = true;
+ overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
+ });
assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
// Verify that settings were stored correctly.
@@ -283,16 +309,16 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
final int initialSize = provider.getOverrideSettingsSize();
-
- // Size + 1 when query for a new display.
final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
- final SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
+ updateOverrideSettings(provider, secondaryDisplayInfo, overrideSettings -> {
+ // Size + 1 when query for a new display.
+ assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
- // When a display is removed, its override Settings is not removed if there is any override.
- overrideSettings.mShouldShowSystemDecors = true;
- provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ // When a display is removed, its override Settings is not removed if there is any
+ // override.
+ overrideSettings.mShouldShowSystemDecors = true;
+ });
provider.onDisplayRemoved(secondaryDisplayInfo);
assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
@@ -309,23 +335,53 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
final int initialSize = provider.getOverrideSettingsSize();
-
- // Size + 1 when query for a new display.
final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
secondaryDisplayInfo.type = TYPE_VIRTUAL;
- final SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
+ updateOverrideSettings(provider, secondaryDisplayInfo, overrideSettings -> {
+ // Size + 1 when query for a new display.
+ assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
- // When a virtual display is removed, its override Settings is removed even if it has
- // override.
- overrideSettings.mShouldShowSystemDecors = true;
- provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ // When a virtual display is removed, its override Settings is removed
+ // even if it has override.
+ overrideSettings.mShouldShowSystemDecors = true;
+ });
provider.onDisplayRemoved(secondaryDisplayInfo);
assertEquals(initialSize, provider.getOverrideSettingsSize());
}
+ @Test
+ public void testRemovesStaleDisplaySettings() {
+ assumeTrue(com.android.window.flags.Flags.perUserDisplayWindowSettings());
+
+ final DisplayWindowSettingsProvider provider =
+ new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage,
+ mOverrideSettingsStorage);
+ final DisplayInfo displayInfo = mSecondaryDisplay.getDisplayInfo();
+ updateOverrideSettings(provider, displayInfo, settings -> settings.mForcedDensity = 356);
+ mRootWindowContainer.removeChild(mSecondaryDisplay);
+
+ provider.removeStaleDisplaySettings(mRootWindowContainer);
+
+ assertThat(mOverrideSettingsStorage.wasWriteSuccessful()).isTrue();
+ assertThat(provider.getOverrideSettingsSize()).isEqualTo(0);
+ }
+
+ /**
+ * Updates the override settings for a specific display.
+ *
+ * @param provider the provider to obtain and update the settings from.
+ * @param displayInfo the information about the display to be updated.
+ * @param modifier a function that modifies the settings for the display.
+ */
+ private static void updateOverrideSettings(DisplayWindowSettingsProvider provider,
+ DisplayInfo displayInfo, Consumer<SettingsEntry> modifier) {
+ final SettingsEntry settings = provider.getOverrideSettings(displayInfo);
+ modifier.accept(settings);
+ provider.updateOverrideSettings(displayInfo, settings);
+ }
+
/**
* Prepares display settings and stores in {@link #mOverrideSettingsStorage}. Uses provided
* display identifier and stores windowingMode=WINDOWING_MODE_PINNED.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
index c5bf78bb60b5..7efbc88833cf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
@@ -29,7 +29,7 @@ import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.ProtoLogImpl;
import com.android.internal.protolog.common.IProtoLog;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import org.junit.After;
import org.junit.Ignore;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index eb79118fe1c7..3078df026d8a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -392,6 +392,8 @@ public class RootWindowContainerTests extends WindowTestsBase {
assertEquals(newPipTask, mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask());
assertNotEquals(newPipTask, activity1.getTask());
assertFalse("Created PiP task must not be in recents", newPipTask.inRecents);
+ assertThat(newPipTask.autoRemoveRecents).isTrue();
+ assertThat(activity1.getTask().autoRemoveRecents).isFalse();
}
/**
@@ -427,6 +429,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
bounds.scale(0.5f);
task.setBounds(bounds);
assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertThat(task.autoRemoveRecents).isFalse();
}
/**
@@ -451,6 +454,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
// Ensure a task has moved over.
ensureTaskPlacement(task, activity);
assertTrue(task.inPinnedWindowingMode());
+ assertThat(task.autoRemoveRecents).isFalse();
}
/**
@@ -480,6 +484,8 @@ public class RootWindowContainerTests extends WindowTestsBase {
ensureTaskPlacement(fullscreenTask, secondActivity);
assertTrue(pinnedRootTask.inPinnedWindowingMode());
assertEquals(WINDOWING_MODE_FULLSCREEN, fullscreenTask.getWindowingMode());
+ assertThat(pinnedRootTask.autoRemoveRecents).isTrue();
+ assertThat(secondActivity.getTask().autoRemoveRecents).isFalse();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index e01cea3d62f8..ef0aa9ef7666 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -42,6 +42,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
import static com.android.server.wm.TaskFragment.EMBEDDED_DIM_AREA_PARENT_TASK;
import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
@@ -222,6 +223,27 @@ public class TaskTests extends WindowTestsBase {
}
@Test
+ public void testReparentPinnedActivityBackToOriginalTask() {
+ final ActivityRecord activityMain = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final Task originalTask = activityMain.getTask();
+ final ActivityRecord activityPip = new ActivityBuilder(mAtm).setTask(originalTask).build();
+ activityPip.setState(RESUMED, "test");
+ mAtm.mRootWindowContainer.moveActivityToPinnedRootTask(activityPip,
+ null /* launchIntoPipHostActivity */, "test");
+ final Task pinnedActivityTask = activityPip.getTask();
+
+ // Simulate pinnedActivityTask unintentionally added to recent during top activity resume.
+ mAtm.getRecentTasks().getRawTasks().add(pinnedActivityTask);
+
+ // Reparent the activity back to its original task when exiting PIP mode.
+ pinnedActivityTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ assertThat(activityPip.getTask()).isEqualTo(originalTask);
+ assertThat(originalTask.autoRemoveRecents).isFalse();
+ assertThat(mAtm.getRecentTasks().getRawTasks()).containsExactly(originalTask);
+ }
+
+ @Test
public void testReparent_BetweenDisplays() {
// Create first task on primary display.
final Task rootTask1 = createTask(mDisplayContent);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 27c383c283a1..bf46154caf3e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -113,6 +113,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
import com.android.server.utils.AlarmQueue;
@@ -1063,6 +1064,18 @@ public class UsageStatsService extends SystemService implements
synchronized (mReportedEvents) {
LinkedList<Event> events = mReportedEvents.get(userId);
if (events == null) {
+ // TODO (b/347644400): callers of this API should verify that the userId passed to
+ // this method exists - there is currently a known case where USER_ALL is passed
+ // here and it would be added to the queue, never to be flushed correctly. The logic
+ // below should only remain as a last-resort catch-all fix.
+ final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+ if (umi == null || (umi != null && !umi.exists(userId))) {
+ // The userId passed is a non-existent user so don't report the event.
+ Slog.wtf(TAG, "Attempted to report event for non-existent user " + userId
+ + " (" + event.mPackage + "/" + event.mClass
+ + " eventType:" + event.mEventType + ")");
+ return;
+ }
events = new LinkedList<>();
mReportedEvents.put(userId, events);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 09cb464198b5..61698dbebe7c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -9981,6 +9981,18 @@ public class CarrierConfigManager {
"carrier_roaming_satellite_default_services_int_array";
/**
+ * Indicate whether carrier roaming to satellite is using ESOS (Emergency SOS) which connects
+ * to an emergency provider instead of PSAP (Public Safety Answering Point) for emergency
+ * messaging.
+ *
+ * This will need agreement with carriers before enabling this flag.
+ *
+ * The default value is false.
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public static final String KEY_SATELLITE_ESOS_SUPPORTED_BOOL = "satellite_esos_supported_bool";
+
+ /**
* Indicating whether DUN APN should be disabled when the device is roaming. In that case,
* the default APN (i.e. internet) will be used for tethering.
*
@@ -11137,6 +11149,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, false);
sDefaults.putInt(KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
(int) TimeUnit.SECONDS.toMillis(30));
+ sDefaults.putBoolean(KEY_SATELLITE_ESOS_SUPPORTED_BOOL, false);
sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORTS_BUSINESS_CALL_COMPOSER_BOOL, false);
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 58488d1900fe..1089602934fd 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -274,6 +274,11 @@ public class SubscriptionInfo implements Parcelable {
private final int mServiceCapabilities;
/**
+ * Whether the carrier roaming to satellite is using ESOS for emergency messaging.
+ */
+ private final boolean mIsSatelliteESOSSupported;
+
+ /**
* @hide
*
* @deprecated Use {@link SubscriptionInfo.Builder}.
@@ -400,6 +405,7 @@ public class SubscriptionInfo implements Parcelable {
this.mIsOnlyNonTerrestrialNetwork = false;
this.mServiceCapabilities = 0;
this.mTransferStatus = 0;
+ this.mIsSatelliteESOSSupported = false;
}
/**
@@ -441,6 +447,7 @@ public class SubscriptionInfo implements Parcelable {
this.mIsOnlyNonTerrestrialNetwork = builder.mIsOnlyNonTerrestrialNetwork;
this.mServiceCapabilities = builder.mServiceCapabilities;
this.mTransferStatus = builder.mTransferStatus;
+ this.mIsSatelliteESOSSupported = builder.mIsSatelliteESOSSupported;
}
/**
@@ -898,6 +905,19 @@ public class SubscriptionInfo implements Parcelable {
return mIsOnlyNonTerrestrialNetwork;
}
+
+ /**
+ * Checks if the subscription is supported ESOS over Carrier Roaming NB-IOT Satellite.
+ *
+ * @return {@code true} if the subscription supports ESOS over Carrier Roaming NB-IOT Satellite,
+ * {@code false} otherwise.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public boolean isSatelliteESOSSupported() {
+ return mIsSatelliteESOSSupported;
+ }
+
// TODO(b/316183370): replace @code with @link in javadoc after feature is released
/**
* Retrieves the service capabilities for the current subscription.
@@ -989,6 +1009,7 @@ public class SubscriptionInfo implements Parcelable {
.setServiceCapabilities(
SubscriptionManager.getServiceCapabilitiesSet(source.readInt()))
.setTransferStatus(source.readInt())
+ .setSatelliteESOSSupported(source.readBoolean())
.build();
}
@@ -1033,6 +1054,7 @@ public class SubscriptionInfo implements Parcelable {
dest.writeBoolean(mIsOnlyNonTerrestrialNetwork);
dest.writeInt(mServiceCapabilities);
dest.writeInt(mTransferStatus);
+ dest.writeBoolean(mIsSatelliteESOSSupported);
}
@Override
@@ -1099,6 +1121,7 @@ public class SubscriptionInfo implements Parcelable {
+ " serviceCapabilities=" + SubscriptionManager.getServiceCapabilitiesSet(
mServiceCapabilities).toString()
+ " transferStatus=" + mTransferStatus
+ + " isSatelliteESOSSupported=" + mIsSatelliteESOSSupported
+ "]";
}
@@ -1126,7 +1149,8 @@ public class SubscriptionInfo implements Parcelable {
&& mCountryIso.equals(that.mCountryIso) && mGroupOwner.equals(that.mGroupOwner)
&& mIsOnlyNonTerrestrialNetwork == that.mIsOnlyNonTerrestrialNetwork
&& mServiceCapabilities == that.mServiceCapabilities
- && mTransferStatus == that.mTransferStatus;
+ && mTransferStatus == that.mTransferStatus
+ && mIsSatelliteESOSSupported == that.mIsSatelliteESOSSupported;
}
@Override
@@ -1136,7 +1160,7 @@ public class SubscriptionInfo implements Parcelable {
mCardString, mIsOpportunistic, mGroupUuid, mCountryIso, mCarrierId, mProfileClass,
mType, mGroupOwner, mAreUiccApplicationsEnabled, mPortIndex, mUsageSetting, mCardId,
mIsGroupDisabled, mIsOnlyNonTerrestrialNetwork, mServiceCapabilities,
- mTransferStatus);
+ mTransferStatus, mIsSatelliteESOSSupported);
result = 31 * result + Arrays.hashCode(mEhplmns);
result = 31 * result + Arrays.hashCode(mHplmns);
result = 31 * result + Arrays.hashCode(mNativeAccessRules);
@@ -1346,6 +1370,11 @@ public class SubscriptionInfo implements Parcelable {
* Service capabilities bitmasks the subscription supports.
*/
private int mServiceCapabilities = 0;
+ /**
+ * {@code true} if the subscription supports ESOS over Carrier Roaming NB-IOT Satellite.
+ * {@code false} otherwise.
+ */
+ private boolean mIsSatelliteESOSSupported = false;
/**
* Default constructor.
@@ -1392,6 +1421,7 @@ public class SubscriptionInfo implements Parcelable {
mIsOnlyNonTerrestrialNetwork = info.mIsOnlyNonTerrestrialNetwork;
mServiceCapabilities = info.mServiceCapabilities;
mTransferStatus = info.mTransferStatus;
+ mIsSatelliteESOSSupported = info.mIsSatelliteESOSSupported;
}
/**
@@ -1828,6 +1858,21 @@ public class SubscriptionInfo implements Parcelable {
}
/**
+ * Set whether the subscription is supported ESOS over Carrier Roaming NB-IOT Satellite or
+ * not.
+ *
+ * @param isSatelliteESOSSupported {@code true} if the subscription supports ESOS over
+ * Carrier Roaming NB-IOT Satellite, {@code false} otherwise.
+ * @return The builder.
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ @NonNull
+ public Builder setSatelliteESOSSupported(boolean isSatelliteESOSSupported) {
+ mIsSatelliteESOSSupported = isSatelliteESOSSupported;
+ return this;
+ }
+
+ /**
* Build the {@link SubscriptionInfo}.
*
* @return The {@link SubscriptionInfo} instance.
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 76b4e0052792..dea10b70b7b9 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1127,7 +1127,7 @@ public class SubscriptionManager {
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String IS_NTN = SimInfo.COLUMN_IS_NTN;
+ public static final String IS_ONLY_NTN = SimInfo.COLUMN_IS_ONLY_NTN;
/**
* TelephonyProvider column name to identify service capabilities.
@@ -1167,6 +1167,16 @@ public class SubscriptionManager {
public static final String SATELLITE_ENTITLEMENT_PLMNS =
SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS;
+ /**
+ * TelephonyProvider column name to indicate the satellite ESOS supported. The value of this
+ * column is set based on {@link CarrierConfigManager#KEY_SATELLITE_ESOS_SUPPORTED_BOOL}.
+ * By default, it's disabled.
+ * <P>Type: INTEGER (int)</P>
+ *
+ * @hide
+ */
+ public static final String SATELLITE_ESOS_SUPPORTED = SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"USAGE_SETTING_"},
@@ -2783,17 +2793,17 @@ public class SubscriptionManager {
return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getActiveModemCount();
}
- /** @hide */
+ /**
+ * Puts phone ID and subscription ID into the {@code intent}.
+ *
+ * <p>If the subscription ID is not valid, only puts phone ID into the {@code intent}.
+ *
+ * @hide
+ */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
int subId = SubscriptionManager.getSubscriptionId(phoneId);
- if (isValidSubscriptionId(subId)) {
- putPhoneIdAndSubIdExtra(intent, phoneId, subId);
- } else {
- logd("putPhoneIdAndSubIdExtra: no valid subs");
- intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
- intent.putExtra(EXTRA_SLOT_INDEX, phoneId);
- }
+ putPhoneIdAndMaybeSubIdExtra(intent, phoneId, subId);
}
/** @hide */
@@ -2806,6 +2816,23 @@ public class SubscriptionManager {
}
/**
+ * Puts phone ID and subscription ID into the {@code intent}.
+ *
+ * <p>If the subscription ID is not valid, only puts phone ID into the {@code intent}.
+ *
+ * @hide
+ */
+ public static void putPhoneIdAndMaybeSubIdExtra(Intent intent, int phoneId, int subId) {
+ if (isValidSubscriptionId(subId)) {
+ putPhoneIdAndSubIdExtra(intent, phoneId, subId);
+ } else {
+ if (VDBG) logd("putPhoneIdAndMaybeSubIdExtra: invalid subId");
+ intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
+ intent.putExtra(EXTRA_SLOT_INDEX, phoneId);
+ }
+ }
+
+ /**
* Get visible subscription Id(s) of the currently active SIM(s).
*
* @return the list of subId's that are active,
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 2a359cd56d1b..6caed14bc31d 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -371,6 +371,24 @@ public final class SatelliteManager {
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
public static final int SATELLITE_RESULT_MODEM_TIMEOUT = 24;
+ /**
+ * Telephony framework needs to access the current location of the device to perform the
+ * request. However, location in the settings is disabled by users.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ public static final int SATELLITE_RESULT_LOCATION_DISABLED = 25;
+
+ /**
+ * Telephony framework needs to access the current location of the device to perform the
+ * request. However, Telephony fails to fetch the current location from location service.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ public static final int SATELLITE_RESULT_LOCATION_NOT_AVAILABLE = 26;
+
/** @hide */
@IntDef(prefix = {"SATELLITE_RESULT_"}, value = {
SATELLITE_RESULT_SUCCESS,
@@ -397,7 +415,9 @@ public final class SatelliteManager {
SATELLITE_RESULT_REQUEST_IN_PROGRESS,
SATELLITE_RESULT_MODEM_BUSY,
SATELLITE_RESULT_ILLEGAL_STATE,
- SATELLITE_RESULT_MODEM_TIMEOUT
+ SATELLITE_RESULT_MODEM_TIMEOUT,
+ SATELLITE_RESULT_LOCATION_DISABLED,
+ SATELLITE_RESULT_LOCATION_NOT_AVAILABLE
})
@Retention(RetentionPolicy.SOURCE)
public @interface SatelliteResult {}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 0f1373c34ce6..2d5b50b528a3 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -17,7 +17,6 @@
package com.android.protolog.tool
import com.android.internal.protolog.common.LogLevel
-import com.android.internal.protolog.common.ProtoLog
import com.android.internal.protolog.common.ProtoLogToolInjected
import com.android.protolog.tool.CommandOptions.Companion.USAGE
import com.github.javaparser.ParseProblemException
@@ -61,6 +60,8 @@ object ProtoLogTool {
const val PROTOLOG_IMPL_SRC_PATH =
"frameworks/base/core/java/com/android/internal/protolog/ProtoLogImpl.java"
+ private const val PROTOLOG_CLASS_NAME = "ProtoLog"; // ProtoLog::class.java.simpleName
+
data class LogCall(
val messageString: String,
val logLevel: LogLevel,
@@ -124,7 +125,7 @@ object ProtoLogTool {
val text = injector.readText(file)
val outSrc = try {
val code = tryParse(text, path)
- if (containsProtoLogText(text, ProtoLog::class.java.simpleName)) {
+ if (containsProtoLogText(text, PROTOLOG_CLASS_NAME)) {
transformer.processClass(text, path, packagePath(file, code), code)
} else {
text
diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
index 822118cc5343..2a8367787ba1 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
@@ -35,7 +35,7 @@ class EndToEndTest {
val output = run(
srcs = mapOf("frameworks/base/org/example/Example.java" to """
package org.example;
- import com.android.internal.protolog.common.ProtoLog;
+ import com.android.internal.protolog.ProtoLog;
import static com.android.internal.protolog.ProtoLogGroup.GROUP;
class Example {
@@ -48,7 +48,7 @@ class EndToEndTest {
""".trimIndent()),
logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
commandOptions = CommandOptions(arrayOf("transform-protolog-calls",
- "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
+ "--protolog-class", "com.android.internal.protolog.ProtoLog",
"--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
"--loggroups-jar", "not_required.jar",
"--viewer-config-file-path", "not_required.pb",
@@ -69,7 +69,7 @@ class EndToEndTest {
val output = run(
srcs = mapOf("frameworks/base/org/example/Example.java" to """
package org.example;
- import com.android.internal.protolog.common.ProtoLog;
+ import com.android.internal.protolog.ProtoLog;
import static com.android.internal.protolog.ProtoLogGroup.GROUP;
class Example {
@@ -82,7 +82,7 @@ class EndToEndTest {
""".trimIndent()),
logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
commandOptions = CommandOptions(arrayOf("generate-viewer-config",
- "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
+ "--protolog-class", "com.android.internal.protolog.ProtoLog",
"--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
"--loggroups-jar", "not_required.jar",
"--viewer-config-type", "json",