summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DREAM_MANAGER_OWNERS1
-rw-r--r--Ravenwood.bp24
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java9
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java32
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java35
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java28
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java10
-rw-r--r--core/java/android/app/Dialog.java8
-rw-r--r--core/java/android/app/DreamManager.java17
-rw-r--r--core/java/android/app/OWNERS3
-rw-r--r--core/java/android/companion/virtual/flags.aconfig11
-rw-r--r--core/java/android/content/pm/PackageParser.java18
-rw-r--r--core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java33
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java54
-rw-r--r--core/java/android/hardware/face/FaceManager.java4
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java4
-rw-r--r--core/java/android/net/NetworkPolicyManager.java6
-rw-r--r--core/java/android/net/Uri.java6
-rw-r--r--core/java/android/provider/Settings.java40
-rw-r--r--core/java/android/service/dreams/DreamService.java13
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl3
-rw-r--r--core/java/android/service/dreams/flags.aconfig9
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java3
-rw-r--r--core/java/android/tracing/perfetto/DataSource.java7
-rw-r--r--core/java/android/tracing/perfetto/DataSourceParams.java61
-rw-r--r--core/java/android/view/GestureDetector.java72
-rw-r--r--core/java/android/view/VelocityTracker.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java79
-rw-r--r--core/java/android/view/inputmethod/InputMethodInfo.java23
-rw-r--r--core/java/android/view/inputmethod/InputMethodSubtypeArray.java13
-rw-r--r--core/java/android/widget/flags/notification_widget_flags.aconfig10
-rw-r--r--core/java/android/window/SplashScreenView.java8
-rw-r--r--core/java/com/android/internal/inputmethod/ImeTracingPerfettoImpl.java10
-rw-r--r--core/java/com/android/internal/inputmethod/InlineSuggestionsRequestCallback.java81
-rw-r--r--core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java9
-rw-r--r--core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java55
-rw-r--r--core/java/com/android/internal/widget/MessagingLinearLayout.java6
-rw-r--r--core/jni/android_tracing_PerfettoDataSource.cpp20
-rw-r--r--core/jni/platform/host/HostRuntime.cpp2
-rw-r--r--core/res/res/drawable/ic_signal_cellular_1_4_bar.xml4
-rw-r--r--core/res/res/drawable/ic_signal_cellular_1_5_bar.xml4
-rw-r--r--core/res/res/drawable/ic_signal_cellular_2_4_bar.xml4
-rw-r--r--core/res/res/drawable/ic_signal_cellular_2_5_bar.xml4
-rw-r--r--core/res/res/drawable/ic_signal_cellular_3_4_bar.xml4
-rw-r--r--core/res/res/drawable/ic_signal_cellular_3_5_bar.xml4
-rw-r--r--core/res/res/drawable/ic_signal_cellular_4_5_bar.xml4
-rw-r--r--core/res/res/layout/side_fps_toast.xml2
-rw-r--r--core/res/res/values-watch/config.xml3
-rw-r--r--core/res/res/values/attrs.xml45
-rw-r--r--core/res/res/values/colors.xml45
-rw-r--r--core/res/res/values/symbols.xml65
-rw-r--r--core/res/res/values/themes_device_defaults.xml1122
-rw-r--r--core/tests/coretests/Android.bp1
-rw-r--r--core/tests/coretests/src/android/net/OWNERS3
-rw-r--r--core/tests/coretests/src/android/net/UriTest.java11
-rw-r--r--core/tests/coretests/src/com/android/internal/ravenwood/RavenwoodEnvironmentTest.java38
-rw-r--r--data/fonts/font_fallback_cjkvf.xml8
-rw-r--r--data/fonts/fonts_cjkvf.xml72
-rw-r--r--libs/WindowManager/Shell/aconfig/multitasking.aconfig7
-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.kt296
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt256
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java443
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt81
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/DesktopModeFlickerScenarios.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java15
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt264
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java237
-rw-r--r--libs/input/MouseCursorController.cpp4
-rw-r--r--libs/input/PointerController.h2
-rw-r--r--libs/input/SpriteController.h2
-rw-r--r--libs/input/tests/PointerController_test.cpp12
-rw-r--r--packages/PrintSpooler/res/values-night/themes.xml1
-rw-r--r--packages/PrintSpooler/res/values/themes.xml1
-rw-r--r--packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java7
-rw-r--r--packages/SettingsLib/aconfig/settingslib.aconfig7
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java5
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java4
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java12
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/Android.bp17
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig21
-rw-r--r--packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt97
-rw-r--r--packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt1
-rw-r--r--packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt106
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt25
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt16
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt15
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt13
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt13
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt23
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt5
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt5
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt12
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt24
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt13
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt19
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt24
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt27
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt63
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt68
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt6
-rwxr-xr-xpackages/SystemUI/flag_check.py44
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt42
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt13
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java14
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt)155
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java)7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt9
-rw-r--r--packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml1
-rw-r--r--packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml1
-rw-r--r--packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml1
-rw-r--r--packages/SystemUI/res/layout/screenshot_shelf.xml10
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt68
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt88
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt79
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt118
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt90
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt69
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt101
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/PriorityPeopleSection.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt66
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java322
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt45
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt113
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java11
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java17
-rw-r--r--proto/src/am_capabilities.proto8
-rw-r--r--ravenwood/Android.bp2
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java753
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java3
-rwxr-xr-xravenwood/scripts/ravenwood-stats-collector.sh14
-rw-r--r--ravenwood/texts/ravenwood-annotation-allowed-classes.txt2
-rw-r--r--ravenwood/texts/ravenwood-framework-policies.txt80
-rw-r--r--ravenwood/texts/ravenwood-services-policies.txt4
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java15
-rw-r--r--services/companion/java/com/android/server/companion/securechannel/SecureChannel.java10
-rw-r--r--services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java14
-rw-r--r--services/core/java/com/android/server/PinnerService.java13
-rw-r--r--services/core/java/com/android/server/WallpaperUpdateReceiver.java9
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java88
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java242
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java10
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java33
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java6
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java91
-rw-r--r--services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java26
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java26
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java1
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java72
-rw-r--r--services/core/java/com/android/server/dreams/DreamController.java14
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java23
-rw-r--r--services/core/java/com/android/server/input/InputManagerInternal.java9
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java5
-rw-r--r--services/core/java/com/android/server/input/NativeInputManagerService.java12
-rw-r--r--services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java68
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeBindingState.java10
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java8
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java102
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodMap.java24
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java10
-rw-r--r--services/core/java/com/android/server/net/NetworkManagementService.java228
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyLogger.java14
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java89
-rw-r--r--services/core/java/com/android/server/net/flags.aconfig10
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java67
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java170
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java16
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java20
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/callbacks/ListenableDownloadCallback.java97
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java30
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java13
-rw-r--r--services/core/java/com/android/server/stats/stats_flags.aconfig8
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java5
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java2
-rw-r--r--services/core/java/com/android/server/wm/PerfettoTransitionTracer.java8
-rw-r--r--services/core/java/com/android/server/wm/Task.java34
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java28
-rw-r--r--services/core/java/com/android/server/wm/utils/AlwaysTruePredicate.java33
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp10
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java29
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java58
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java66
-rw-r--r--services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java28
-rw-r--r--services/tests/servicestests/AndroidTest.xml7
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java78
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt3
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt4
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt2
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt2
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt4
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt2
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt4
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt5
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt3
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt4
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt2
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt4
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt5
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt2
-rw-r--r--tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt4
-rw-r--r--tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt2
-rw-r--r--tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt2
-rw-r--r--tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt3
-rw-r--r--tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt2
-rw-r--r--tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt2
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt11
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt36
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt72
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt94
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt102
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt94
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt130
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt3
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java22
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java6
341 files changed, 8243 insertions, 2822 deletions
diff --git a/DREAM_MANAGER_OWNERS b/DREAM_MANAGER_OWNERS
new file mode 100644
index 000000000000..48bde6024cba
--- /dev/null
+++ b/DREAM_MANAGER_OWNERS
@@ -0,0 +1 @@
+brycelee@google.com
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 74b34fbcf2a1..412f2b746887 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -104,6 +104,18 @@ genrule {
],
}
+genrule {
+ name: "framework-minus-apex.ravenwood.keep_all",
+ defaults: ["ravenwood-internal-only-visibility-genrule"],
+ cmd: "cp $(in) $(out)",
+ srcs: [
+ ":framework-minus-apex.ravenwood-base{hoststubgen_keep_all.txt}",
+ ],
+ out: [
+ "hoststubgen_framework-minus-apex_keep_all.txt",
+ ],
+}
+
java_library {
name: "services.core-for-hoststubgen",
installable: false, // host only jar.
@@ -189,6 +201,18 @@ genrule {
],
}
+genrule {
+ name: "services.core.ravenwood.keep_all",
+ defaults: ["ravenwood-internal-only-visibility-genrule"],
+ cmd: "cp $(in) $(out)",
+ srcs: [
+ ":services.core.ravenwood-base{hoststubgen_keep_all.txt}",
+ ],
+ out: [
+ "hoststubgen_services.core_keep_all.txt",
+ ],
+}
+
java_library {
name: "services.core.ravenwood-jarjar",
installable: false,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 384d78618c8b..ff73a4922977 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -80,6 +80,7 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.storage.StorageManagerInternal;
@@ -179,6 +180,8 @@ public class JobSchedulerService extends com.android.server.SystemService
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean DEBUG_STANDBY = DEBUG || false;
+ public static final String TRACE_TRACK_NAME = "JobScheduler";
+
/** The maximum number of jobs that we allow an app to schedule */
private static final int MAX_JOBS_PER_APP = 150;
/** The number of the most recently completed jobs to keep track of for debugging purposes. */
@@ -4344,7 +4347,11 @@ public class JobSchedulerService extends com.android.server.SystemService
final boolean wasConsideredCharging = isConsideredCharging();
mChargingPolicy = newPolicy;
-
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+ Trace.instantForTrack(Trace.TRACE_TAG_SYSTEM_SERVER,
+ JobSchedulerService.TRACE_TRACK_NAME,
+ "CHARGING POLICY CHANGED#" + mChargingPolicy);
+ }
if (isConsideredCharging() != wasConsideredCharging) {
for (int c = mControllers.size() - 1; c >= 0; --c) {
mControllers.get(c).onBatteryStateChangedLocked();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 39d50f53d2c4..d65a66c83fcc 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -535,29 +535,17 @@ public final class JobServiceContext implements ServiceConnection {
sEnqueuedJwiAtJobStart.logSampleWithUid(job.getUid(), job.getWorkCount());
final String sourcePackage = job.getSourcePackageName();
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
- final String componentPackage = job.getServiceComponent().getPackageName();
- String traceTag = "*job*<" + job.getSourceUid() + ">" + sourcePackage;
- if (!sourcePackage.equals(componentPackage)) {
- traceTag += ":" + componentPackage;
- }
- traceTag += "/" + job.getServiceComponent().getShortClassName();
- if (!componentPackage.equals(job.serviceProcessName)) {
- traceTag += "$" + job.serviceProcessName;
- }
- if (job.getNamespace() != null) {
- traceTag += "@" + job.getNamespace();
- }
- traceTag += "#" + job.getJobId();
-
// Use the context's ID to distinguish traces since there'll only be one job
// running per context.
- Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler",
- traceTag, getId());
+ Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
+ JobSchedulerService.TRACE_TRACK_NAME, job.computeSystemTraceTag(),
+ getId());
}
if (job.getAppTraceTag() != null) {
// Use the job's ID to distinguish traces since the ID will be unique per app.
- Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, "JobScheduler",
- job.getAppTraceTag(), job.getJobId());
+ Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP,
+ JobSchedulerService.TRACE_TRACK_NAME, job.getAppTraceTag(),
+ job.getJobId());
}
try {
mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid());
@@ -1605,12 +1593,12 @@ public final class JobServiceContext implements ServiceConnection {
completedJob.getFilteredTraceTag(),
completedJob.getFilteredDebugTags());
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
- Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler",
- getId());
+ Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER,
+ JobSchedulerService.TRACE_TRACK_NAME, getId());
}
if (completedJob.getAppTraceTag() != null) {
- Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, "JobScheduler",
- completedJob.getJobId());
+ Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP,
+ JobSchedulerService.TRACE_TRACK_NAME, completedJob.getJobId());
}
try {
mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), mRunningJob.getSourceUid(),
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 7fca867356af..e3af1d894762 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -572,6 +572,9 @@ public final class JobStatus {
/** The reason a job most recently went from ready to not ready. */
private int mReasonReadyToUnready = JobParameters.STOP_REASON_UNDEFINED;
+ /** The system trace tag for this job. */
+ private String mSystemTraceTag;
+
/**
* Core constructor for JobStatus instances. All other ctors funnel down to this one.
*
@@ -1058,6 +1061,38 @@ public final class JobStatus {
return job.getTraceTag();
}
+ /** Returns a trace tag using debug information provided by job scheduler service. */
+ @NonNull
+ public String computeSystemTraceTag() {
+ // Guarded by JobSchedulerService.mLock, no need for synchronization.
+ if (mSystemTraceTag != null) {
+ return mSystemTraceTag;
+ }
+
+ mSystemTraceTag = computeSystemTraceTagInner();
+ return mSystemTraceTag;
+ }
+
+ @NonNull
+ private String computeSystemTraceTagInner() {
+ final String componentPackage = getServiceComponent().getPackageName();
+ StringBuilder traceTag = new StringBuilder(128);
+ traceTag.append("*job*<").append(sourceUid).append(">").append(sourcePackageName);
+ if (!sourcePackageName.equals(componentPackage)) {
+ traceTag.append(":").append(componentPackage);
+ }
+ traceTag.append("/").append(getServiceComponent().getShortClassName());
+ if (!componentPackage.equals(serviceProcessName)) {
+ traceTag.append("$").append(serviceProcessName);
+ }
+ if (mNamespace != null && !mNamespace.trim().isEmpty()) {
+ traceTag.append("@").append(mNamespace);
+ }
+ traceTag.append("#").append(getJobId());
+
+ return traceTag.toString();
+ }
+
/** Returns whether this job was scheduled by one app on behalf of another. */
public boolean isProxyJob() {
return mIsProxyJob;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index c240b3f423a9..a1c72fb4c06c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -50,6 +50,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
@@ -2181,6 +2182,12 @@ public final class QuotaController extends StateController {
}
scheduleCutoff();
}
+ } else {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+ Trace.instantForTrack(Trace.TRACE_TAG_SYSTEM_SERVER,
+ JobSchedulerService.TRACE_TRACK_NAME,
+ "QC/- " + mPkg);
+ }
}
}
@@ -2720,6 +2727,11 @@ public final class QuotaController extends StateController {
if (timeRemainingMs <= 50) {
// Less than 50 milliseconds left. Start process of shutting down jobs.
if (DEBUG) Slog.d(TAG, pkg + " has reached its quota.");
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+ Trace.instantForTrack(Trace.TRACE_TAG_SYSTEM_SERVER,
+ JobSchedulerService.TRACE_TRACK_NAME,
+ pkg + "#" + MSG_REACHED_TIME_QUOTA);
+ }
mStateChangedListener.onControllerStateChanged(
maybeUpdateConstraintForPkgLocked(
sElapsedRealtimeClock.millis(),
@@ -2748,6 +2760,11 @@ public final class QuotaController extends StateController {
pkg.userId, pkg.packageName);
if (timeRemainingMs <= 0) {
if (DEBUG) Slog.d(TAG, pkg + " has reached its EJ quota.");
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+ Trace.instantForTrack(Trace.TRACE_TAG_SYSTEM_SERVER,
+ JobSchedulerService.TRACE_TRACK_NAME,
+ pkg + "#" + MSG_REACHED_EJ_TIME_QUOTA);
+ }
mStateChangedListener.onControllerStateChanged(
maybeUpdateConstraintForPkgLocked(
sElapsedRealtimeClock.millis(),
@@ -2772,6 +2789,12 @@ public final class QuotaController extends StateController {
Slog.d(TAG, pkg + " has reached its count quota.");
}
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+ Trace.instantForTrack(Trace.TRACE_TAG_SYSTEM_SERVER,
+ JobSchedulerService.TRACE_TRACK_NAME,
+ pkg + "#" + MSG_REACHED_COUNT_QUOTA);
+ }
+
mStateChangedListener.onControllerStateChanged(
maybeUpdateConstraintForPkgLocked(
sElapsedRealtimeClock.millis(),
@@ -2928,6 +2951,11 @@ public final class QuotaController extends StateController {
}
mTempAllowlistGraceCache.delete(uid);
mTopAppGraceCache.delete(uid);
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+ Trace.instantForTrack(Trace.TRACE_TAG_SYSTEM_SERVER,
+ JobSchedulerService.TRACE_TRACK_NAME,
+ "<" + uid + ">#" + MSG_END_GRACE_PERIOD);
+ }
final ArraySet<String> packages = mService.getPackagesForUidLocked(uid);
if (packages != null) {
final int userId = UserHandle.getUserId(uid);
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
index 488292d68620..f726361effd6 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
@@ -292,13 +292,17 @@ public class AccessibilityNodeInfoDumper {
int childCount = node.getChildCount();
for (int x = 0; x < childCount; x++) {
AccessibilityNodeInfo childNode = node.getChild(x);
-
+ if (childNode == null) {
+ continue;
+ }
if (!safeCharSeqToString(childNode.getContentDescription()).isEmpty()
- || !safeCharSeqToString(childNode.getText()).isEmpty())
+ || !safeCharSeqToString(childNode.getText()).isEmpty()) {
return true;
+ }
- if (childNafCheck(childNode))
+ if (childNafCheck(childNode)) {
return true;
+ }
}
return false;
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 0e201384812d..cd7f1e4c02c2 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -679,11 +679,13 @@ public class Dialog implements DialogInterface, Window.Callback,
if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
if (mCancelable) {
cancel();
- } else {
+ event.startTracking();
+ return true;
+ } else if (mWindow.shouldCloseOnTouchOutside()) {
dismiss();
+ event.startTracking();
+ return true;
}
- event.startTracking();
- return true;
}
return false;
diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java
index ef6982e4a13c..4ac40a1f77b2 100644
--- a/core/java/android/app/DreamManager.java
+++ b/core/java/android/app/DreamManager.java
@@ -18,6 +18,7 @@ package android.app;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+import android.annotation.FlaggedApi;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
@@ -30,6 +31,7 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.DreamService;
+import android.service.dreams.Flags;
import android.service.dreams.IDreamManager;
/**
@@ -217,4 +219,19 @@ public class DreamManager {
}
return false;
}
+
+ /**
+ * Sets whether the dream is obscured by something.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_DREAM_HANDLES_BEING_OBSCURED)
+ @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
+ public void setDreamIsObscured(boolean isObscured) {
+ try {
+ mService.setDreamIsObscured(isObscured);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 97c2e43a1db6..2e38c06a7479 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -60,6 +60,9 @@ per-file ReceiverInfo* = file:/BROADCASTS_OWNERS
# ComponentCaller
per-file ComponentCaller.java = file:COMPONENT_CALLER_OWNERS
+# DreamManager
+per-file DreamManager.java = file:/DREAM_MANAGER_OWNERS
+
# GrammaticalInflectionManager
per-file *GrammaticalInflection* = file:/services/core/java/com/android/server/grammaticalinflection/OWNERS
per-file grammatical_inflection_manager.aconfig = file:/services/core/java/com/android/server/grammaticalinflection/OWNERS
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 3e23762a4f70..b29b52d67310 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -127,4 +127,15 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "impulse_velocity_strategy_for_touch_navigation"
+ is_exported: true
+ namespace: "virtual_devices"
+ description: "Use impulse velocity strategy during conversion of touch navigation flings into Dpad events"
+ bug: "338426241"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
} \ No newline at end of file
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4b579e7db9f8..1f6730b9e3f9 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2628,6 +2628,15 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + targetCode
@@ -2699,6 +2708,15 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 153dd9a93490..c7403c0ea98c 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -316,6 +316,15 @@ public class FrameworkParsingPackageUtils {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Parsed package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -368,19 +377,27 @@ public class FrameworkParsingPackageUtils {
return input.success(targetVers);
}
+ // If it's a pre-release SDK and the codename matches this platform, it
+ // definitely targets this SDK.
+ if (matchTargetCode(platformSdkCodenames, targetCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Parsed package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
try {
if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
} catch (IllegalArgumentException e) {
- // isAtMost() throws it when encountering an older SDK codename
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage());
- }
-
- // If it's a pre-release SDK and the codename matches this platform, it
- // definitely targets this SDK.
- if (matchTargetCode(platformSdkCodenames, targetCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
}
// Otherwise, we're looking at an incompatible pre-release SDK.
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 2b7d8f155bff..708f8a173aba 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -39,7 +39,6 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.hardware.CameraExtensionSessionStats;
-import android.hardware.CameraIdRemapping;
import android.hardware.CameraStatus;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
@@ -1996,17 +1995,6 @@ public final class CameraManager {
}
/**
- * Remaps Camera Ids in the CameraService.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.CAMERA_INJECT_EXTERNAL_CAMERA)
- public void remapCameraIds(@NonNull CameraIdRemapping cameraIdRemapping)
- throws CameraAccessException, SecurityException, IllegalArgumentException {
- CameraManagerGlobal.get().remapCameraIds(cameraIdRemapping);
- }
-
- /**
* Injects session params into existing clients in the CameraService.
*
* @param cameraId The camera id of client to inject session params into.
@@ -2117,13 +2105,6 @@ public final class CameraManager {
private final Object mLock = new Object();
- /**
- * The active CameraIdRemapping. This will be used to refresh the cameraIdRemapping state
- * in the CameraService every time we connect to it, including when the CameraService
- * Binder dies and we reconnect to it.
- */
- @Nullable private CameraIdRemapping mActiveCameraIdRemapping;
-
// Access only through getCameraService to deal with binder death
private ICameraService mCameraService;
private boolean mHasOpenCloseListenerPermission = false;
@@ -2275,41 +2256,6 @@ public final class CameraManager {
} catch (RemoteException e) {
// Camera service died in all probability
}
-
- if (mActiveCameraIdRemapping != null) {
- try {
- cameraService.remapCameraIds(mActiveCameraIdRemapping);
- } catch (ServiceSpecificException e) {
- // Unexpected failure, ignore and continue.
- Log.e(TAG, "Unable to remap camera Ids in the camera service");
- } catch (RemoteException e) {
- // Camera service died in all probability
- }
- }
- }
-
- /** Updates the cameraIdRemapping state in the CameraService. */
- public void remapCameraIds(@NonNull CameraIdRemapping cameraIdRemapping)
- throws CameraAccessException, SecurityException {
- synchronized (mLock) {
- ICameraService cameraService = getCameraService();
- if (cameraService == null) {
- throw new CameraAccessException(
- CameraAccessException.CAMERA_DISCONNECTED,
- "Camera service is currently unavailable.");
- }
-
- try {
- cameraService.remapCameraIds(cameraIdRemapping);
- mActiveCameraIdRemapping = cameraIdRemapping;
- } catch (ServiceSpecificException e) {
- throw ExceptionUtils.throwAsPublicException(e);
- } catch (RemoteException e) {
- throw new CameraAccessException(
- CameraAccessException.CAMERA_DISCONNECTED,
- "Camera service is currently unavailable.");
- }
- }
}
/** Injects session params into an existing client for cameraid. */
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index d340f3ff70bb..3f2ef84a4ef0 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -732,6 +732,10 @@ public class FaceManager implements BiometricAuthenticator {
/**
* Get statically configured sensor properties.
+ * @deprecated Generally unsafe to use, use
+ * {@link FaceManager#addAuthenticatorsRegisteredCallback} API instead.
+ * In most cases this method will work as expected, but during early boot up, it will be
+ * null/empty and there is no way for the caller to know when it's actual value is ready.
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 25bfb2ab91e7..2ded615580fd 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -1189,6 +1189,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
/**
* Get statically configured sensor properties.
+ * @deprecated Generally unsafe to use, use
+ * {@link FingerprintManager#addAuthenticatorsRegisteredCallback} API instead.
+ * In most cases this method will work as expected, but during early boot up, it will be
+ * null/empty and there is no way for the caller to know when it's actual value is ready.
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 594ec18d9996..334b2316b268 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -173,6 +173,12 @@ public class NetworkPolicyManager {
public static final String FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY = "low_power_standby";
/** @hide */
public static final String FIREWALL_CHAIN_NAME_BACKGROUND = "background";
+ /** @hide */
+ public static final String FIREWALL_CHAIN_NAME_METERED_ALLOW = "metered_allow";
+ /** @hide */
+ public static final String FIREWALL_CHAIN_NAME_METERED_DENY_USER = "metered_deny_user";
+ /** @hide */
+ public static final String FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN = "metered_deny_admin";
private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 05a3e182135c..fedc97dcf989 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1387,7 +1387,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
* @param scheme name or {@code null} if this is a relative Uri
*/
public Builder scheme(String scheme) {
- this.scheme = scheme;
+ if (scheme != null) {
+ this.scheme = scheme.replaceAll("://", "");
+ } else {
+ this.scheme = null;
+ }
return this;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 009713f0f942..4f5b67c34845 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11173,6 +11173,35 @@ public final class Settings {
"visual_query_accessibility_detection_enabled";
/**
+ * Timeout to be used for unbinding to the configured remote
+ * {@link android.service.ondeviceintelligence.OnDeviceIntelligenceService} if there are no
+ * requests in the queue. A value of -1 represents to never unbind.
+ *
+ * @hide
+ */
+ public static final String ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS =
+ "on_device_intelligence_unbind_timeout_ms";
+
+
+ /**
+ * Timeout that represents maximum idle time before which a callback should be populated.
+ *
+ * @hide
+ */
+ public static final String ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS =
+ "on_device_intelligence_idle_timeout_ms";
+
+ /**
+ * Timeout to be used for unbinding to the configured remote
+ * {@link android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService} if there
+ * are no requests in the queue. A value of -1 represents to never unbind.
+ *
+ * @hide
+ */
+ public static final String ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS =
+ "on_device_inference_unbind_timeout_ms";
+
+ /**
* Control whether Night display is currently activated.
* @hide
*/
@@ -14909,6 +14938,17 @@ public final class Settings {
public static final String DROPBOX_TAG_PREFIX = "dropbox:";
/**
+ * Lines of kernel logs to include with system crash/ANR/etc. reports, as a
+ * prefix of the dropbox tag of the report type. For example,
+ * "kernel_logs_for_system_server_anr" controls the lines of kernel logs
+ * captured with system server ANR reports. 0 to disable.
+ *
+ * @hide
+ */
+ @Readable
+ public static final String ERROR_KERNEL_LOG_PREFIX = "kernel_logs_for_";
+
+ /**
* Lines of logcat to include with system crash/ANR/etc. reports, as a
* prefix of the dropbox tag of the report type. For example,
* "logcat_for_system_server_anr" controls the lines of logcat captured
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 5f6bdbf193b9..38ab590b3c46 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -18,7 +18,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.dreamTracksFocus;
+import static android.service.dreams.Flags.dreamHandlesBeingObscured;
import android.annotation.FlaggedApi;
import android.annotation.IdRes;
@@ -571,15 +571,6 @@ public class DreamService extends Service implements Window.Callback {
/** {@inheritDoc} */
@Override
public void onWindowFocusChanged(boolean hasFocus) {
- if (!dreamTracksFocus()) {
- return;
- }
-
- try {
- mDreamManager.onDreamFocusChanged(hasFocus);
- } catch (RemoteException ex) {
- // system server died
- }
}
/** {@inheritDoc} */
@@ -1737,7 +1728,7 @@ public class DreamService extends Service implements Window.Callback {
@Override
public void comeToFront() {
- if (!dreamTracksFocus()) {
+ if (!dreamHandlesBeingObscured()) {
return;
}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 85f0368a7b5c..cf98bfe05faf 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -48,5 +48,6 @@ interface IDreamManager {
void setSystemDreamComponent(in ComponentName componentName);
void registerDreamOverlayService(in ComponentName componentName);
void startDreamActivity(in Intent intent);
- void onDreamFocusChanged(in boolean hasFocus);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)")
+ oneway void setDreamIsObscured(in boolean isObscured);
}
diff --git a/core/java/android/service/dreams/flags.aconfig b/core/java/android/service/dreams/flags.aconfig
index a42eaff68917..54d950c18af8 100644
--- a/core/java/android/service/dreams/flags.aconfig
+++ b/core/java/android/service/dreams/flags.aconfig
@@ -39,8 +39,11 @@ flag {
}
flag {
- name: "dream_tracks_focus"
+ name: "dream_handles_being_obscured"
namespace: "communal"
- description: "This flag enables the ability for dreams to track whether or not they have focus"
- bug: "331798001"
+ description: "This flag enables the ability for dreams to handle being obscured"
+ bug: "337302237"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d174bef90f9c..95897855586d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1025,7 +1025,8 @@ public abstract class WallpaperService extends Service {
mWallpaperDimAmount = (!mShouldDimByDefault) ? mCustomDimAmount
: Math.max(mDefaultDimAmount, mCustomDimAmount);
- if (!ENABLE_WALLPAPER_DIMMING || mBbqSurfaceControl == null
+ if (!ENABLE_WALLPAPER_DIMMING
+ || mBbqSurfaceControl == null || !mBbqSurfaceControl.isValid()
|| mWallpaperDimAmount == mPreviousWallpaperDimAmount) {
return;
}
diff --git a/core/java/android/tracing/perfetto/DataSource.java b/core/java/android/tracing/perfetto/DataSource.java
index b9ab82cb63a9..aa84173983e0 100644
--- a/core/java/android/tracing/perfetto/DataSource.java
+++ b/core/java/android/tracing/perfetto/DataSource.java
@@ -130,7 +130,8 @@ public abstract class DataSource<DataSourceInstanceType extends DataSourceInstan
* @param params Params to initialize the datasource with.
*/
public void register(DataSourceParams params) {
- nativeRegisterDataSource(this.mNativeObj, params.bufferExhaustedPolicy);
+ nativeRegisterDataSource(this.mNativeObj, params.bufferExhaustedPolicy,
+ params.willNotifyOnStop, params.noFlush);
}
/**
@@ -163,8 +164,8 @@ public abstract class DataSource<DataSourceInstanceType extends DataSourceInstan
return this.createInstance(inputStream, instanceIndex);
}
- private static native void nativeRegisterDataSource(
- long dataSourcePtr, int bufferExhaustedPolicy);
+ private static native void nativeRegisterDataSource(long dataSourcePtr,
+ int bufferExhaustedPolicy, boolean willNotifyOnStop, boolean noFlush);
private static native long nativeCreate(DataSource thiz, String name);
private static native void nativeFlushAll(long nativeDataSourcePointer);
diff --git a/core/java/android/tracing/perfetto/DataSourceParams.java b/core/java/android/tracing/perfetto/DataSourceParams.java
index 6cd04e3d9a8b..e50f9d722fad 100644
--- a/core/java/android/tracing/perfetto/DataSourceParams.java
+++ b/core/java/android/tracing/perfetto/DataSourceParams.java
@@ -46,12 +46,67 @@ public class DataSourceParams {
// after a while.
public static final int PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT = 1;
- public static DataSourceParams DEFAULTS =
- new DataSourceParams(PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP);
+ public static DataSourceParams DEFAULTS = new DataSourceParams.Builder().build();
- public DataSourceParams(@PerfettoDsBufferExhausted int bufferExhaustedPolicy) {
+ private DataSourceParams(@PerfettoDsBufferExhausted int bufferExhaustedPolicy,
+ boolean willNotifyOnStop, boolean noFlush) {
this.bufferExhaustedPolicy = bufferExhaustedPolicy;
+ this.willNotifyOnStop = willNotifyOnStop;
+ this.noFlush = noFlush;
}
public final @PerfettoDsBufferExhausted int bufferExhaustedPolicy;
+ public final boolean willNotifyOnStop;
+ public final boolean noFlush;
+
+ /**
+ * DataSource Parameters builder
+ *
+ * @hide
+ */
+ public static final class Builder {
+ /**
+ * Specify behavior when running out of shared memory buffer space.
+ */
+ public Builder setBufferExhaustedPolicy(@PerfettoDsBufferExhausted int value) {
+ this.mBufferExhaustedPolicy = value;
+ return this;
+ }
+
+ /**
+ * If true, the data source is expected to ack the stop request through the
+ * NotifyDataSourceStopped() IPC. If false, the service won't wait for an ack.
+ * Set this parameter to false when dealing with potentially frozen producers
+ * that wouldn't be able to quickly ack the stop request.
+ *
+ * Default value: true
+ */
+ public Builder setWillNotifyOnStop(boolean value) {
+ this.mWillNotifyOnStop = value;
+ return this;
+ }
+
+ /**
+ * If true, the service won't emit flush requests for this data source. This
+ * allows the service to reduce the flush-related IPC traffic and better deal
+ * with frozen producers (see go/perfetto-frozen).
+ */
+ public Builder setNoFlush(boolean value) {
+ this.mNoFlush = value;
+ return this;
+ }
+
+ /**
+ * Build the DataSource parameters.
+ */
+ public DataSourceParams build() {
+ return new DataSourceParams(
+ this.mBufferExhaustedPolicy, this.mWillNotifyOnStop, this.mNoFlush);
+ }
+
+ private @PerfettoDsBufferExhausted int mBufferExhaustedPolicy =
+ PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP;
+ private boolean mWillNotifyOnStop = true;
+ private boolean mNoFlush = false;
+ }
}
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 9ff29a81a5c6..4837ee5a797c 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -26,11 +26,13 @@ import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFI
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
+import android.app.Activity;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -299,6 +301,11 @@ public class GestureDetector {
private VelocityTracker mVelocityTracker;
/**
+ * Determines strategy for velocity calculation
+ */
+ private @VelocityTracker.VelocityTrackerStrategy int mVelocityTrackerStrategy;
+
+ /**
* Consistency verifier for debugging purposes.
*/
private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
@@ -347,17 +354,17 @@ public class GestureDetector {
/**
* Creates a GestureDetector with the supplied listener.
- * This variant of the constructor should be used from a non-UI thread
+ * This variant of the constructor should be used from a non-UI thread
* (as it allows specifying the Handler).
- *
+ *
* @param listener the listener invoked for all the callbacks, this must
* not be null.
* @param handler the handler to use
*
* @throws NullPointerException if {@code listener} is null.
*
- * @deprecated Use {@link #GestureDetector(android.content.Context,
- * android.view.GestureDetector.OnGestureListener, android.os.Handler)} instead.
+ * @deprecated Use {@link #GestureDetector(Context, GestureDetector.OnGestureListener, Handler)}
+ * instead.
*/
@Deprecated
public GestureDetector(@NonNull OnGestureListener listener, @Nullable Handler handler) {
@@ -367,15 +374,14 @@ public class GestureDetector {
/**
* Creates a GestureDetector with the supplied listener.
* You may only use this constructor from a UI thread (this is the usual situation).
- * @see android.os.Handler#Handler()
- *
+ * @see Handler#Handler()
+ *
* @param listener the listener invoked for all the callbacks, this must
* not be null.
- *
+ *
* @throws NullPointerException if {@code listener} is null.
*
- * @deprecated Use {@link #GestureDetector(android.content.Context,
- * android.view.GestureDetector.OnGestureListener)} instead.
+ * @deprecated Use {@link #GestureDetector(Context, GestureDetector.OnGestureListener)} instead.
*/
@Deprecated
public GestureDetector(@NonNull OnGestureListener listener) {
@@ -384,10 +390,10 @@ public class GestureDetector {
/**
* Creates a GestureDetector with the supplied listener.
- * You may only use this constructor from a {@link android.os.Looper} thread.
- * @see android.os.Handler#Handler()
+ * You may only use this constructor from a {@link Looper} thread.
+ * @see Handler#Handler()
*
- * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * @param context An {@link Activity} or a {@link Context} created from
* {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null. If the listener implements the {@link OnDoubleTapListener} or
@@ -404,10 +410,10 @@ public class GestureDetector {
/**
* Creates a GestureDetector with the supplied listener that runs deferred events on the
- * thread associated with the supplied {@link android.os.Handler}.
- * @see android.os.Handler#Handler()
+ * thread associated with the supplied {@link Handler}.
+ * @see Handler#Handler()
*
- * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * @param context An {@link Activity} or a {@link Context} created from
* {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null. If the listener implements the {@link OnDoubleTapListener} or
@@ -419,6 +425,31 @@ public class GestureDetector {
*/
public GestureDetector(@Nullable @UiContext Context context,
@NonNull OnGestureListener listener, @Nullable Handler handler) {
+ this(context, listener, handler, VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT);
+ }
+
+ /**
+ * Creates a GestureDetector with the supplied listener that runs deferred events on the
+ * thread associated with the supplied {@link Handler}.
+ * @see Handler#Handler()
+ *
+ * @param context An {@link Activity} or a {@link Context} created from
+ * {@link Context#createWindowContext(int, Bundle)}
+ * @param listener the listener invoked for all the callbacks, this must
+ * not be null. If the listener implements the {@link OnDoubleTapListener} or
+ * {@link OnContextClickListener} then it will also be set as the listener for
+ * these callbacks (for example when using the {@link SimpleOnGestureListener}).
+ * @param handler the handler to use for running deferred listener events.
+ * @param velocityTrackerStrategy strategy to use for velocity calculation of scroll/fling
+ * events.
+ *
+ * @throws NullPointerException if {@code listener} is null.
+ *
+ * @hide
+ */
+ public GestureDetector(@Nullable @UiContext Context context,
+ @NonNull OnGestureListener listener, @Nullable Handler handler,
+ @VelocityTracker.VelocityTrackerStrategy int velocityTrackerStrategy) {
if (handler != null) {
mHandler = new GestureHandler(handler);
} else {
@@ -431,15 +462,16 @@ public class GestureDetector {
if (listener instanceof OnContextClickListener) {
setContextClickListener((OnContextClickListener) listener);
}
+ mVelocityTrackerStrategy = velocityTrackerStrategy;
init(context);
}
-
+
/**
* Creates a GestureDetector with the supplied listener that runs deferred events on the
- * thread associated with the supplied {@link android.os.Handler}.
- * @see android.os.Handler#Handler()
+ * thread associated with the supplied {@link Handler}.
+ * @see Handler#Handler()
*
- * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * @param context An {@link Activity} or a {@link Context} created from
* {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null.
@@ -547,7 +579,7 @@ public class GestureDetector {
mCurrentMotionEvent = MotionEvent.obtain(ev);
if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker = VelocityTracker.obtain(mVelocityTrackerStrategy);
}
mVelocityTracker.addMovement(ev);
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index d31f82398cdf..27176a4c2094 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -264,7 +264,6 @@ public final class VelocityTracker {
/**
* Obtains a velocity tracker with the specified strategy.
- * For testing and comparison purposes only.
*
* @param strategy The strategy Id, VELOCITY_TRACKER_STRATEGY_DEFAULT to use the default.
* @return The velocity tracker.
@@ -272,6 +271,9 @@ public final class VelocityTracker {
* @hide
*/
public static VelocityTracker obtain(int strategy) {
+ if (strategy == VELOCITY_TRACKER_STRATEGY_DEFAULT) {
+ return obtain();
+ }
return new VelocityTracker(strategy);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 155c0537b5b5..fb0c0a30414e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8609,48 +8609,55 @@ public final class ViewRootImpl implements ViewParent,
private int mPendingKeyMetaState;
- private final GestureDetector mGestureDetector = new GestureDetector(mContext,
- new GestureDetector.OnGestureListener() {
- @Override
- public boolean onDown(@NonNull MotionEvent e) {
- // This can be ignored since it's not clear what KeyEvent this will
- // belong to.
- return true;
- }
-
- @Override
- public void onShowPress(@NonNull MotionEvent e) {
+ private final GestureDetector mGestureDetector;
- }
+ SyntheticTouchNavigationHandler() {
+ super(true);
+ int gestureDetectorVelocityStrategy =
+ android.companion.virtual.flags.Flags
+ .impulseVelocityStrategyForTouchNavigation()
+ ? VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE
+ : VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT;
+ mGestureDetector = new GestureDetector(mContext,
+ new GestureDetector.OnGestureListener() {
+ @Override
+ public boolean onDown(@NonNull MotionEvent e) {
+ // This can be ignored since it's not clear what KeyEvent this will
+ // belong to.
+ return true;
+ }
- @Override
- public boolean onSingleTapUp(@NonNull MotionEvent e) {
- dispatchTap(e.getEventTime());
- return true;
- }
+ @Override
+ public void onShowPress(@NonNull MotionEvent e) {
+ }
- @Override
- public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
- float distanceX, float distanceY) {
- // Scroll doesn't translate to DPAD events so should be ignored.
- return true;
- }
+ @Override
+ public boolean onSingleTapUp(@NonNull MotionEvent e) {
+ dispatchTap(e.getEventTime());
+ return true;
+ }
- @Override
- public void onLongPress(@NonNull MotionEvent e) {
- // Long presses don't translate to DPAD events so should be ignored.
- }
+ @Override
+ public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
+ float distanceX, float distanceY) {
+ // Scroll doesn't translate to DPAD events so should be ignored.
+ return true;
+ }
- @Override
- public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
- float velocityX, float velocityY) {
- dispatchFling(velocityX, velocityY, e2.getEventTime());
- return true;
- }
- });
+ @Override
+ public void onLongPress(@NonNull MotionEvent e) {
+ // Long presses don't translate to DPAD events so should be ignored.
+ }
- SyntheticTouchNavigationHandler() {
- super(true);
+ @Override
+ public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
+ float velocityX, float velocityY) {
+ dispatchFling(velocityX, velocityY, e2.getEventTime());
+ return true;
+ }
+ },
+ /* handler= */ null,
+ gestureDetectorVelocityStrategy);
}
public void process(MotionEvent event) {
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 7885cd95ca25..11ee286652a1 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -54,6 +54,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -431,6 +432,14 @@ public final class InputMethodInfo implements Parcelable {
* @hide
*/
public InputMethodInfo(InputMethodInfo source) {
+ this(source, Collections.emptyList());
+ }
+
+ /**
+ * @hide
+ */
+ public InputMethodInfo(@NonNull InputMethodInfo source,
+ @NonNull List<InputMethodSubtype> additionalSubtypes) {
mId = source.mId;
mSettingsActivityName = source.mSettingsActivityName;
mLanguageSettingsActivityName = source.mLanguageSettingsActivityName;
@@ -445,7 +454,19 @@ public final class InputMethodInfo implements Parcelable {
mIsVrOnly = source.mIsVrOnly;
mIsVirtualDeviceOnly = source.mIsVirtualDeviceOnly;
mService = source.mService;
- mSubtypes = source.mSubtypes;
+ if (additionalSubtypes.isEmpty()) {
+ mSubtypes = source.mSubtypes;
+ } else {
+ final ArrayList<InputMethodSubtype> subtypes = source.mSubtypes.toList();
+ final int additionalSubtypeCount = additionalSubtypes.size();
+ for (int i = 0; i < additionalSubtypeCount; ++i) {
+ final InputMethodSubtype additionalSubtype = additionalSubtypes.get(i);
+ if (!subtypes.contains(additionalSubtype)) {
+ subtypes.add(additionalSubtype);
+ }
+ }
+ mSubtypes = new InputMethodSubtypeArray(subtypes);
+ }
mHandledConfigChanges = source.mHandledConfigChanges;
mSupportsStylusHandwriting = source.mSupportsStylusHandwriting;
mSupportsConnectionlessStylusHandwriting = source.mSupportsConnectionlessStylusHandwriting;
diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
index c243a22b27b1..e2d343f45e5d 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
@@ -25,6 +25,7 @@ import android.util.Slog;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -163,6 +164,18 @@ public class InputMethodSubtypeArray {
}
/**
+ * @return A list of {@link InputMethodInfo} copied from this array.
+ */
+ @NonNull
+ public ArrayList<InputMethodSubtype> toList() {
+ final ArrayList<InputMethodSubtype> list = new ArrayList<>(mCount);
+ for (int i = 0; i < mCount; ++i) {
+ list.add(get(i));
+ }
+ return list;
+ }
+
+ /**
* Return the number of {@link InputMethodSubtype} objects.
*/
public int getCount() {
diff --git a/core/java/android/widget/flags/notification_widget_flags.aconfig b/core/java/android/widget/flags/notification_widget_flags.aconfig
index 3a39631f8c81..503e542f715a 100644
--- a/core/java/android/widget/flags/notification_widget_flags.aconfig
+++ b/core/java/android/widget/flags/notification_widget_flags.aconfig
@@ -47,3 +47,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "messaging_child_request_layout"
+ namespace: "systemui"
+ description: "MessagingChild always needs to be measured during MessagingLinearLayout onMeasure."
+ bug: "324537506"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 31e3a342d21a..af3d7eb87f71 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -56,6 +56,8 @@ import com.android.internal.R;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.policy.DecorView;
+import java.io.Closeable;
+import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.function.Consumer;
@@ -568,6 +570,12 @@ public final class SplashScreenView extends FrameLayout {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
releaseAnimationSurfaceHost();
+ if (mIconView instanceof ImageView imageView
+ && imageView.getDrawable() instanceof Closeable closeableDrawable) {
+ try {
+ closeableDrawable.close();
+ } catch (IOException ignore) { }
+ }
}
@Override
diff --git a/core/java/com/android/internal/inputmethod/ImeTracingPerfettoImpl.java b/core/java/com/android/internal/inputmethod/ImeTracingPerfettoImpl.java
index 91b80ddaa836..24cd1c9cd7de 100644
--- a/core/java/com/android/internal/inputmethod/ImeTracingPerfettoImpl.java
+++ b/core/java/com/android/internal/inputmethod/ImeTracingPerfettoImpl.java
@@ -52,8 +52,14 @@ final class ImeTracingPerfettoImpl extends ImeTracing {
ImeTracingPerfettoImpl() {
Producer.init(InitArguments.DEFAULTS);
- mDataSource.register(
- new DataSourceParams(PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT));
+ DataSourceParams params =
+ new DataSourceParams.Builder()
+ .setBufferExhaustedPolicy(
+ PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT)
+ .setNoFlush(true)
+ .setWillNotifyOnStop(false)
+ .build();
+ mDataSource.register(params);
}
diff --git a/core/java/com/android/internal/inputmethod/InlineSuggestionsRequestCallback.java b/core/java/com/android/internal/inputmethod/InlineSuggestionsRequestCallback.java
new file mode 100644
index 000000000000..92d453ba0e9f
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/InlineSuggestionsRequestCallback.java
@@ -0,0 +1,81 @@
+/*
+ * 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.internal.inputmethod;
+
+import android.annotation.BinderThread;
+import android.view.autofill.AutofillId;
+import android.view.inputmethod.InlineSuggestionsRequest;
+
+/**
+ * An internal interface that mirrors {@link IInlineSuggestionsRequestCallback}.
+ *
+ * <p>This interface is used to forward incoming IPCs from
+ * {@link com.android.server.inputmethod.AutofillSuggestionsController} to
+ * {@link com.android.server.autofill.AutofillInlineSuggestionsRequestSession}.</p>
+ */
+public interface InlineSuggestionsRequestCallback {
+
+ /**
+ * Forwards {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsUnsupported()}.
+ */
+ @BinderThread
+ void onInlineSuggestionsUnsupported();
+
+ /**
+ * Forwards {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsRequest(
+ * InlineSuggestionsRequest, IInlineSuggestionsResponseCallback)}.
+ */
+ @BinderThread
+ void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
+ IInlineSuggestionsResponseCallback callback);
+
+ /**
+ * Forwards {@link IInlineSuggestionsRequestCallback#onInputMethodStartInput(AutofillId)}.
+ */
+ @BinderThread
+ void onInputMethodStartInput(AutofillId imeFieldId);
+
+ /**
+ * Forwards {@link IInlineSuggestionsRequestCallback#onInputMethodShowInputRequested(boolean)}.
+ */
+ @BinderThread
+ void onInputMethodShowInputRequested(boolean requestResult);
+
+ /**
+ * Forwards {@link IInlineSuggestionsRequestCallback#onInputMethodStartInputView()}.
+ */
+ @BinderThread
+ void onInputMethodStartInputView();
+
+ /**
+ * Forwards {@link IInlineSuggestionsRequestCallback#onInputMethodFinishInputView()}.
+ */
+ @BinderThread
+ void onInputMethodFinishInputView();
+
+ /**
+ * Forwards {@link IInlineSuggestionsRequestCallback#onInputMethodFinishInput()}.
+ */
+ @BinderThread
+ void onInputMethodFinishInput();
+
+ /**
+ * Forwards {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsSessionInvalidated()}.
+ */
+ @BinderThread
+ void onInlineSuggestionsSessionInvalidated();
+}
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index ee33eb4f014b..efe6ab349903 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -131,8 +131,13 @@ public class PerfettoProtoLogImpl implements IProtoLog {
Runnable cacheUpdater
) {
Producer.init(InitArguments.DEFAULTS);
- mDataSource.register(new DataSourceParams(
- DataSourceParams.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT));
+ DataSourceParams params =
+ new DataSourceParams.Builder()
+ .setBufferExhaustedPolicy(
+ DataSourceParams
+ .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT)
+ .build();
+ mDataSource.register(params);
this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider;
this.mViewerConfigReader = viewerConfigReader;
this.mLogGroups = logGroups;
diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
new file mode 100644
index 000000000000..1340156321b2
--- /dev/null
+++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
@@ -0,0 +1,55 @@
+/*
+ * 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.internal.ravenwood;
+
+/**
+ * Class to interact with the Ravenwood environment.
+ */
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+public class RavenwoodEnvironment {
+ private static RavenwoodEnvironment sInstance = new RavenwoodEnvironment();
+
+ private RavenwoodEnvironment() {
+ }
+
+ /**
+ * @return the singleton instance.
+ */
+ public static RavenwoodEnvironment getInstance() {
+ return sInstance;
+ }
+
+ /**
+ * USE IT SPARINGLY! Returns true if it's running on Ravenwood, hostside test environment.
+ *
+ * <p>Using this allows code to behave differently on a real device and on Ravenwood, but
+ * generally speaking, that's a bad idea because we want the test target code to behave
+ * differently.
+ *
+ * <p>This should be only used when different behavior is absolutely needed.
+ *
+ * <p>If someone needs it without having access to the SDK, the following hack would work too.
+ * <code>System.getProperty("java.class.path").contains("ravenwood")</code>
+ */
+ @android.ravenwood.annotation.RavenwoodReplace
+ public boolean isRunningOnRavenwood() {
+ return false;
+ }
+
+ public boolean isRunningOnRavenwood$ravenwood() {
+ return true;
+ }
+}
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index e07acac52f2c..3d8237ea5389 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -16,6 +16,8 @@
package com.android.internal.widget;
+import static android.widget.flags.Flags.messagingChildRequestLayout;
+
import android.annotation.Nullable;
import android.annotation.Px;
import android.content.Context;
@@ -92,6 +94,10 @@ public class MessagingLinearLayout extends ViewGroup {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.hide = true;
+ // Child always needs to be measured to calculate hide property correctly in onMeasure.
+ if (messagingChildRequestLayout()) {
+ child.requestLayout();
+ }
if (child instanceof MessagingChild) {
MessagingChild messagingChild = (MessagingChild) child;
// Whenever we encounter the message first, it's always first in the layout
diff --git a/core/jni/android_tracing_PerfettoDataSource.cpp b/core/jni/android_tracing_PerfettoDataSource.cpp
index f82ebfe8c947..243155257b4d 100644
--- a/core/jni/android_tracing_PerfettoDataSource.cpp
+++ b/core/jni/android_tracing_PerfettoDataSource.cpp
@@ -256,10 +256,12 @@ void nativeFlushAll(JNIEnv* env, jclass clazz, jlong ptr) {
}
void nativeRegisterDataSource(JNIEnv* env, jclass clazz, jlong datasource_ptr,
- jint buffer_exhausted_policy) {
+ jint buffer_exhausted_policy, jboolean will_notify_on_stop,
+ jboolean no_flush) {
sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(datasource_ptr);
struct PerfettoDsParams params = PerfettoDsParamsDefault();
+ params.will_notify_on_stop = will_notify_on_stop;
params.buffer_exhausted_policy = (PerfettoDsBufferExhaustedPolicy)buffer_exhausted_policy;
params.user_arg = reinterpret_cast<void*>(datasource.get());
@@ -325,13 +327,15 @@ void nativeRegisterDataSource(JNIEnv* env, jclass clazz, jlong datasource_ptr,
datasource_instance->onStart(env);
};
- params.on_flush_cb = [](struct PerfettoDsImpl*, PerfettoDsInstanceIndex, void*, void* inst_ctx,
- struct PerfettoDsOnFlushArgs*) {
- JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
+ if (!no_flush) {
+ params.on_flush_cb = [](struct PerfettoDsImpl*, PerfettoDsInstanceIndex, void*,
+ void* inst_ctx, struct PerfettoDsOnFlushArgs*) {
+ JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
- auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
- datasource_instance->onFlush(env);
- };
+ auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
+ datasource_instance->onFlush(env);
+ };
+ }
params.on_stop_cb = [](struct PerfettoDsImpl*, PerfettoDsInstanceIndex inst_id, void* user_arg,
void* inst_ctx, struct PerfettoDsOnStopArgs*) {
@@ -422,7 +426,7 @@ const JNINativeMethod gMethods[] = {
(void*)nativeCreate},
{"nativeFlushAll", "(J)V", (void*)nativeFlushAll},
{"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer},
- {"nativeRegisterDataSource", "(JI)V", (void*)nativeRegisterDataSource},
+ {"nativeRegisterDataSource", "(JIZZ)V", (void*)nativeRegisterDataSource},
{"nativeGetPerfettoInstanceLocked", "(JI)Landroid/tracing/perfetto/DataSourceInstance;",
(void*)nativeGetPerfettoInstanceLocked},
{"nativeReleasePerfettoInstanceLocked", "(JI)V",
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index bf2fddab3d41..acef609448ad 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -330,7 +330,7 @@ static void init_keyboard(JNIEnv* env, const vector<string>& keyboardPaths) {
InputDeviceInfo info = InputDeviceInfo();
info.initialize(keyboardId, 0, 0, InputDeviceIdentifier(),
"keyboard " + std::to_string(keyboardId), true, false,
- ui::ADISPLAY_ID_DEFAULT);
+ ui::LogicalDisplayId::DEFAULT);
info.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
info.setKeyCharacterMap(*charMap);
diff --git a/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml b/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml
index 7c45c20a758b..c692967d36b3 100644
--- a/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml
@@ -22,11 +22,11 @@
<path
android:fillColor="@android:color/white"
android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
- <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+ <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
<!-- 1 bar. move to higher ground. -->
<path
android:name="ic_signal_cellular_1_4_bar"
android:fillColor="@android:color/white"
- android:pathData="M6,0 H11 V20 H6 z" />
+ android:pathData="M0,0 H11 V24 H0 z" />
</clip-path>
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml
index 02b646d310e5..b01c26972ac8 100644
--- a/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml
@@ -22,11 +22,11 @@
<path
android:fillColor="@android:color/white"
android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
- <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+ <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
<!-- 1 bar. might have to call you back. -->
<path
android:name="ic_signal_cellular_1_5_bar"
android:fillColor="@android:color/white"
- android:pathData="M6,0 H12 V20 H6 z" />
+ android:pathData="M0,0 H12 V24 H0 z" />
</clip-path>
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml b/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml
index 514d1690abcf..982623d41060 100644
--- a/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml
@@ -22,11 +22,11 @@
<path
android:fillColor="@android:color/white"
android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
- <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+ <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
<!-- 2 bars. 2 out of 4 ain't bad. -->
<path
android:name="ic_signal_cellular_2_4_bar"
android:fillColor="@android:color/white"
- android:pathData="M6,0 H14 V20 H6 z" />
+ android:pathData="M0,0 H14 V24 H0 z" />
</clip-path>
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml
index a97f771a6632..75daadd213dc 100644
--- a/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml
@@ -23,11 +23,11 @@
<path
android:fillColor="@android:color/white"
android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
- <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+ <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
<!-- 2 bars. hanging in there. -->
<path
android:name="ic_signal_cellular_2_5_bar"
android:fillColor="@android:color/white"
- android:pathData="M6,0 H14 V20 H6 z" />
+ android:pathData="M0,0 H14 V24 H0 z" />
</clip-path>
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml b/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml
index 1bacf4ad678f..4e4bea397d26 100644
--- a/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml
@@ -22,11 +22,11 @@
<path
android:fillColor="@android:color/white"
android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
- <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+ <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
<!-- 3 bars. quite nice. -->
<path
android:name="ic_signal_cellular_3_4_bar"
android:fillColor="@android:color/white"
- android:pathData="M6,0 H17 V20 H6 z" />
+ android:pathData="M0,0 H17 V24 H0 z" />
</clip-path>
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml
index 2789d3e9305c..9a98c2982574 100644
--- a/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml
@@ -22,11 +22,11 @@
<path
android:fillColor="@android:color/white"
android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
- <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+ <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
<!-- 3 bars. not great, not terrible. -->
<path
android:name="ic_signal_cellular_3_5_bar"
android:fillColor="@android:color/white"
- android:pathData="M6,0 H16 V20 H6 z" />
+ android:pathData="M0,0 H16 V24 H0 z" />
</clip-path>
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml
index 8286dbb5576f..2a37d011c650 100644
--- a/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml
@@ -22,11 +22,11 @@
<path
android:fillColor="@android:color/white"
android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
- <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+ <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
<!-- 4 bars. extremely respectable. -->
<path
android:name="ic_signal_cellular_4_5_bar"
android:fillColor="@android:color/white"
- android:pathData="M6,0 H18 V20 H6 z" />
+ android:pathData="M0,0 H18 V24 H0 z" />
</clip-path>
</vector> \ No newline at end of file
diff --git a/core/res/res/layout/side_fps_toast.xml b/core/res/res/layout/side_fps_toast.xml
index 2c35c9b888cf..78299ab0ea99 100644
--- a/core/res/res/layout/side_fps_toast.xml
+++ b/core/res/res/layout/side_fps_toast.xml
@@ -25,6 +25,7 @@
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="6"
+ android:paddingBottom="10dp"
android:text="@string/fp_power_button_enrollment_title"
android:textColor="@color/side_fps_text_color"
android:paddingLeft="20dp"/>
@@ -36,6 +37,7 @@
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="3"
+ android:paddingBottom="10dp"
android:text="@string/fp_power_button_enrollment_button_text"
style="?android:attr/buttonBarNegativeButtonStyle"
android:textColor="@color/side_fps_button_color"
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 31acd9af164c..52662149b23a 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -93,4 +93,7 @@
<!-- If this is true, allow wake from theater mode from motion. -->
<bool name="config_allowTheaterModeWakeFromMotion">true</bool>
+
+ <!-- True if the device supports system decorations on secondary displays. -->
+ <bool name="config_supportsSystemDecorsOnSecondaryDisplays">false</bool>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 37d39a752c65..5fa13bab7b0c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1346,6 +1346,51 @@
<attr name="materialColorTertiary" format="color"/>
<!-- The error color for the app, intended to draw attention to error conditions. @hide -->
<attr name="materialColorError" format="color"/>
+
+ <!-- System Custom Tokens-->
+ <!-- @hide -->
+ <attr name="customColorWidgetBackground" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorClockHour" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorClockMinute" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorClockSecond" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorThemeApp" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorOnThemeApp" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorThemeAppRing" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorOnThemeAppRing" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorBrandA" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorBrandB" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorBrandC" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorBrandD" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorUnderSurface" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorShadeActive" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorOnShadeActive" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorOnShadeActiveVariant" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorShadeInactive" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorOnShadeInactive" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorOnShadeInactiveVariant" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorShadeDisabled" format="color"/>
+ <!-- @hide -->
+ <attr name="customColorOverviewBackground" format="color"/>
+
</declare-styleable>
<!-- **************************************************************** -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index e6719195565e..5e039b5e958d 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -581,6 +581,51 @@
<color name="system_on_tertiary_fixed">#FFFFFF</color>
<color name="system_on_tertiary_fixed_variant">#FFFFFF</color>
+ <!--Colors used in Android system, from design system. These values can be overlaid at runtime
+ by OverlayManager RROs.-->
+ <color name="system_widget_background_light">#EEF0FF</color>
+ <color name="system_clock_hour_light">#1D2435</color>
+ <color name="system_clock_minute_light">#20386A</color>
+ <color name="system_clock_second_light">#000000</color>
+ <color name="system_theme_app_light">#2F4578</color>
+ <color name="system_on_theme_app_light">#D6DFFF</color>
+ <color name="system_theme_app_ring_light">#94AAE4</color>
+ <color name="system_on_theme_app_ring_light">#FDD7FA</color>
+ <color name="system_brand_a_light">#3A5084</color>
+ <color name="system_brand_b_light">#6E7488</color>
+ <color name="system_brand_c_light">#6076AC</color>
+ <color name="system_brand_d_light">#8C6D8C</color>
+ <color name="system_under_surface_light">#000000</color>
+ <color name="system_shade_active_light">#D9E2FF</color>
+ <color name="system_on_shade_active_light">#152E60</color>
+ <color name="system_on_shade_active_variant_light">#2F4578</color>
+ <color name="system_shade_inactive_light">#2F3036</color>
+ <color name="system_on_shade_inactive_light">#E1E2EC</color>
+ <color name="system_on_shade_inactive_variant_light">#C5C6D0</color>
+ <color name="system_shade_disabled_light">#0C0E13</color>
+ <color name="system_overview_background_light">#50525A</color>
+ <color name="system_widget_background_dark">#152E60</color>
+ <color name="system_clock_hour_dark">#9AA0B6</color>
+ <color name="system_clock_minute_dark">#D8E1FF</color>
+ <color name="system_clock_second_dark">#FFFFFF</color>
+ <color name="system_theme_app_dark">#D9E2FF</color>
+ <color name="system_on_theme_app_dark">#304679</color>
+ <color name="system_theme_app_ring_dark">#94AAE4</color>
+ <color name="system_on_theme_app_ring_dark">#E0BBDD</color>
+ <color name="system_brand_a_dark">#90A6DF</color>
+ <color name="system_brand_b_dark">#A4ABC1</color>
+ <color name="system_brand_c_dark">#7A90C8</color>
+ <color name="system_brand_d_dark">#A886A6</color>
+ <color name="system_under_surface_dark">#000000</color>
+ <color name="system_shade_active_dark">#D9E2FF</color>
+ <color name="system_on_shade_active_dark">#001945</color>
+ <color name="system_on_shade_active_variant_dark">#2F4578</color>
+ <color name="system_shade_inactive_dark">#2F3036</color>
+ <color name="system_on_shade_inactive_dark">#E1E2EC</color>
+ <color name="system_on_shade_inactive_variant_dark">#C5C6D0</color>
+ <color name="system_shade_disabled_dark">#0C0E13</color>
+ <color name="system_overview_background_dark">#C5C6D0</color>
+
<!-- Accessibility shortcut icon background color -->
<color name="accessibility_feature_background">#5F6368</color> <!-- Google grey 700 -->
<color name="accessibility_magnification_background">#F50D60</color>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ae79a4c68f9e..d004b050fae8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5292,6 +5292,71 @@
<java-symbol name="materialColorTertiary" type="attr"/>
<java-symbol name="materialColorError" type="attr"/>
+ <java-symbol name="customColorWidgetBackground" type="attr"/>
+ <java-symbol name="customColorClockHour" type="attr"/>
+ <java-symbol name="customColorClockMinute" type="attr"/>
+ <java-symbol name="customColorClockSecond" type="attr"/>
+ <java-symbol name="customColorThemeApp" type="attr"/>
+ <java-symbol name="customColorOnThemeApp" type="attr"/>
+ <java-symbol name="customColorThemeAppRing" type="attr"/>
+ <java-symbol name="customColorOnThemeAppRing" type="attr"/>
+ <java-symbol name="customColorBrandA" type="attr"/>
+ <java-symbol name="customColorBrandB" type="attr"/>
+ <java-symbol name="customColorBrandC" type="attr"/>
+ <java-symbol name="customColorBrandD" type="attr"/>
+ <java-symbol name="customColorUnderSurface" type="attr"/>
+ <java-symbol name="customColorShadeActive" type="attr"/>
+ <java-symbol name="customColorOnShadeActive" type="attr"/>
+ <java-symbol name="customColorOnShadeActiveVariant" type="attr"/>
+ <java-symbol name="customColorShadeInactive" type="attr"/>
+ <java-symbol name="customColorOnShadeInactive" type="attr"/>
+ <java-symbol name="customColorOnShadeInactiveVariant" type="attr"/>
+ <java-symbol name="customColorShadeDisabled" type="attr"/>
+ <java-symbol name="customColorOverviewBackground" type="attr"/>
+
+ <java-symbol name="system_widget_background_light" type="color"/>
+ <java-symbol name="system_clock_hour_light" type="color"/>
+ <java-symbol name="system_clock_minute_light" type="color"/>
+ <java-symbol name="system_clock_second_light" type="color"/>
+ <java-symbol name="system_theme_app_light" type="color"/>
+ <java-symbol name="system_on_theme_app_light" type="color"/>
+ <java-symbol name="system_theme_app_ring_light" type="color"/>
+ <java-symbol name="system_on_theme_app_ring_light" type="color"/>
+ <java-symbol name="system_brand_a_light" type="color"/>
+ <java-symbol name="system_brand_b_light" type="color"/>
+ <java-symbol name="system_brand_c_light" type="color"/>
+ <java-symbol name="system_brand_d_light" type="color"/>
+ <java-symbol name="system_under_surface_light" type="color"/>
+ <java-symbol name="system_shade_active_light" type="color"/>
+ <java-symbol name="system_on_shade_active_light" type="color"/>
+ <java-symbol name="system_on_shade_active_variant_light" type="color"/>
+ <java-symbol name="system_shade_inactive_light" type="color"/>
+ <java-symbol name="system_on_shade_inactive_light" type="color"/>
+ <java-symbol name="system_on_shade_inactive_variant_light" type="color"/>
+ <java-symbol name="system_shade_disabled_light" type="color"/>
+ <java-symbol name="system_overview_background_light" type="color"/>
+ <java-symbol name="system_widget_background_dark" type="color"/>
+ <java-symbol name="system_clock_hour_dark" type="color"/>
+ <java-symbol name="system_clock_minute_dark" type="color"/>
+ <java-symbol name="system_clock_second_dark" type="color"/>
+ <java-symbol name="system_theme_app_dark" type="color"/>
+ <java-symbol name="system_on_theme_app_dark" type="color"/>
+ <java-symbol name="system_theme_app_ring_dark" type="color"/>
+ <java-symbol name="system_on_theme_app_ring_dark" type="color"/>
+ <java-symbol name="system_brand_a_dark" type="color"/>
+ <java-symbol name="system_brand_b_dark" type="color"/>
+ <java-symbol name="system_brand_c_dark" type="color"/>
+ <java-symbol name="system_brand_d_dark" type="color"/>
+ <java-symbol name="system_under_surface_dark" type="color"/>
+ <java-symbol name="system_shade_active_dark" type="color"/>
+ <java-symbol name="system_on_shade_active_dark" type="color"/>
+ <java-symbol name="system_on_shade_active_variant_dark" type="color"/>
+ <java-symbol name="system_shade_inactive_dark" type="color"/>
+ <java-symbol name="system_on_shade_inactive_dark" type="color"/>
+ <java-symbol name="system_on_shade_inactive_variant_dark" type="color"/>
+ <java-symbol name="system_shade_disabled_dark" type="color"/>
+ <java-symbol name="system_overview_background_dark" type="color"/>
+
<java-symbol type="attr" name="actionModeUndoDrawable" />
<java-symbol type="attr" name="actionModeRedoDrawable" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index ee191449ac35..24d493867906 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -284,6 +284,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" />
@@ -380,6 +402,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
@@ -475,6 +519,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -572,6 +638,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -668,6 +756,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -772,6 +882,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -867,6 +999,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -961,6 +1115,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -1056,6 +1232,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -1167,6 +1365,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -1263,6 +1483,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -1357,6 +1599,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -1453,6 +1717,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -1548,6 +1834,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -1643,6 +1951,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -1738,6 +2068,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -1833,6 +2185,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
@@ -1928,6 +2302,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- Theme for the dialog shown when an app crashes or ANRs. -->
@@ -2028,6 +2424,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -2121,6 +2539,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -2352,6 +2792,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
@@ -2447,6 +2909,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -2541,6 +3025,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -2636,6 +3142,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -2733,6 +3261,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -2829,6 +3379,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -2931,6 +3503,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
@@ -3029,6 +3623,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -3126,6 +3742,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -3224,6 +3862,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -3303,6 +3963,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
@@ -3382,6 +4064,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
@@ -3480,6 +4184,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -3579,6 +4305,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -3676,6 +4424,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -3772,6 +4542,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -3867,6 +4659,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="Theme.DeviceDefault.Light.Dialog.Alert" />
@@ -3962,6 +4776,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -4055,6 +4891,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
@@ -4156,6 +5014,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.SystemUI" parent="Theme.DeviceDefault.Light">
@@ -4238,6 +5118,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.SystemUI.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -4312,6 +5214,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -4407,6 +5331,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<style name="Theme.DeviceDefault.Settings.DialogBase" parent="Theme.Material.Light.BaseDialog">
@@ -4486,6 +5432,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Settings.DialogBase">
@@ -4605,6 +5573,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -4702,6 +5692,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
@@ -4825,6 +5837,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<style name="ThemeOverlay.DeviceDefault.Accent.Light">
@@ -4878,6 +5912,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. -->
@@ -4935,6 +5991,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen">
@@ -4988,6 +6066,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_light</item>
<item name="materialColorTertiary">@color/system_tertiary_light</item>
<item name="materialColorError">@color/system_error_light</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
+ <item name="customColorClockHour">@color/system_clock_hour_light</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+ <item name="customColorClockSecond">@color/system_clock_second_light</item>
+ <item name="customColorThemeApp">@color/system_theme_app_light</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item>
+ <item name="customColorBrandA">@color/system_brand_a_light</item>
+ <item name="customColorBrandB">@color/system_brand_b_light</item>
+ <item name="customColorBrandC">@color/system_brand_c_light</item>
+ <item name="customColorBrandD">@color/system_brand_d_light</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+ <item name="customColorShadeActive">@color/system_shade_active_light</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
</style>
<style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification">
@@ -5052,6 +6152,28 @@ easier.
<item name="materialColorSecondary">@color/system_secondary_dark</item>
<item name="materialColorTertiary">@color/system_tertiary_dark</item>
<item name="materialColorError">@color/system_error_dark</item>
+
+ <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
+ <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+ <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+ <item name="customColorClockSecond">@color/system_clock_second_dark</item>
+ <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+ <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
+ <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+ <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item>
+ <item name="customColorBrandA">@color/system_brand_a_dark</item>
+ <item name="customColorBrandB">@color/system_brand_b_dark</item>
+ <item name="customColorBrandC">@color/system_brand_c_dark</item>
+ <item name="customColorBrandD">@color/system_brand_d_dark</item>
+ <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+ <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+ <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
+ <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
+ <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
+ <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
+ <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+ <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
</style>
<style name="Theme.DeviceDefault.AutofillHalfScreenDialogList" parent="Theme.DeviceDefault.DayNight">
<item name="colorListDivider">@color/list_divider_opacity_device_default_light</item>
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 436ba15235c9..eb3c84a3ba0c 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -260,6 +260,7 @@ android_ravenwood_test {
"src/com/android/internal/os/**/*.java",
"src/com/android/internal/util/**/*.java",
"src/com/android/internal/power/EnergyConsumerStatsTest.java",
+ "src/com/android/internal/ravenwood/**/*.java",
// Pull in R.java from FrameworksCoreTests-resonly, not from FrameworksCoreTests,
// to avoid having a dependency to FrameworksCoreTests.
diff --git a/core/tests/coretests/src/android/net/OWNERS b/core/tests/coretests/src/android/net/OWNERS
index a779c00814cb..beb77dc8f4fd 100644
--- a/core/tests/coretests/src/android/net/OWNERS
+++ b/core/tests/coretests/src/android/net/OWNERS
@@ -1,4 +1,5 @@
include /services/core/java/com/android/server/net/OWNERS
-per-file SSL*,Uri*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com
+per-file SSL*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com
per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS
+per-file Uri* = varunshah@google.com
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 2a4ca79d997e..57cb1586bcd0 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -18,6 +18,7 @@ package android.net;
import android.content.ContentUris;
import android.os.Parcel;
+import android.platform.test.annotations.AsbSecurityTest;
import androidx.test.filters.SmallTest;
@@ -86,6 +87,16 @@ public class UriTest extends TestCase {
assertNull(u.getHost());
}
+ @AsbSecurityTest(cveBugId = 261721900)
+ @SmallTest
+ public void testSchemeSanitization() {
+ Uri uri = new Uri.Builder()
+ .scheme("http://https://evil.com:/te:st/")
+ .authority("google.com").path("one/way").build();
+ assertEquals("httphttpsevil.com:/te:st/", uri.getScheme());
+ assertEquals("httphttpsevil.com:/te:st/://google.com/one/way", uri.toString());
+ }
+
@SmallTest
public void testStringUri() {
assertEquals("bob lee",
diff --git a/core/tests/coretests/src/com/android/internal/ravenwood/RavenwoodEnvironmentTest.java b/core/tests/coretests/src/com/android/internal/ravenwood/RavenwoodEnvironmentTest.java
new file mode 100644
index 000000000000..d1ef61b2e365
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/ravenwood/RavenwoodEnvironmentTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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.internal.ravenwood;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodEnvironmentTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ @Test
+ public void testIsRunningOnRavenwood() {
+ assertEquals(RavenwoodRule.isUnderRavenwood(),
+ RavenwoodEnvironment.getInstance().isRunningOnRavenwood());
+ }
+}
diff --git a/data/fonts/font_fallback_cjkvf.xml b/data/fonts/font_fallback_cjkvf.xml
index ac1b06495832..a4ee82544b37 100644
--- a/data/fonts/font_fallback_cjkvf.xml
+++ b/data/fonts/font_fallback_cjkvf.xml
@@ -768,7 +768,7 @@
<font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
</family>
<family lang="zh-Hans">
- <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin"
+ <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular"
supportedAxes="wght">
NotoSansCJK-Regular.ttc
<!-- The default instance of NotoSansCJK-Regular.ttc is wght=100, so specify wght=400
@@ -780,7 +780,7 @@
</font>
</family>
<family lang="zh-Hant,zh-Bopo">
- <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin"
+ <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular"
supportedAxes="wght">
NotoSansCJK-Regular.ttc
<!-- The default instance of NotoSansCJK-Regular.ttc is wght=100, so specify wght=400
@@ -792,7 +792,7 @@
</font>
</family>
<family lang="ja">
- <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin"
+ <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular"
supportedAxes="wght">
NotoSansCJK-Regular.ttc
<!-- The default instance of NotoSansCJK-Regular.ttc is wght=100, so specify wght=400
@@ -810,7 +810,7 @@
</font>
</family>
<family lang="ko">
- <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin"
+ <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular"
supportedAxes="wght">
NotoSansCJK-Regular.ttc
<!-- The default instance of NotoSansCJK-Regular.ttc is wght=100, so specify wght=400
diff --git a/data/fonts/fonts_cjkvf.xml b/data/fonts/fonts_cjkvf.xml
index 9545ae718574..8cbc3000c250 100644
--- a/data/fonts/fonts_cjkvf.xml
+++ b/data/fonts/fonts_cjkvf.xml
@@ -1409,39 +1409,39 @@
<font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
</family>
<family lang="zh-Hans">
- <font weight="100" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="100" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="100"/>
</font>
- <font weight="200" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="200" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="200"/>
</font>
- <font weight="300" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="300" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="300"/>
</font>
- <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="500" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="600" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="700" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="800" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="800" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="800"/>
</font>
- <font weight="900" style="normal" index="2" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="900" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="900"/>
</font>
@@ -1450,39 +1450,39 @@
</font>
</family>
<family lang="zh-Hant,zh-Bopo">
- <font weight="100" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="100" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="100"/>
</font>
- <font weight="200" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="200" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="200"/>
</font>
- <font weight="300" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="300" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="300"/>
</font>
- <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="500" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="600" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="700" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="800" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="800" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="800"/>
</font>
- <font weight="900" style="normal" index="3" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="900" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="900"/>
</font>
@@ -1491,39 +1491,39 @@
</font>
</family>
<family lang="ja">
- <font weight="100" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="100" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="100"/>
</font>
- <font weight="200" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="200" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="200"/>
</font>
- <font weight="300" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="300" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="300"/>
</font>
- <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="500" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="600" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="700" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="800" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="800" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="800"/>
</font>
- <font weight="900" style="normal" index="0" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="900" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="900"/>
</font>
@@ -1542,39 +1542,39 @@
</font>
</family>
<family lang="ko">
- <font weight="100" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="100" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="100"/>
</font>
- <font weight="200" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="200" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="200"/>
</font>
- <font weight="300" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="300" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="300"/>
</font>
- <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="500" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="600" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="700" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="800" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="800" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="800"/>
</font>
- <font weight="900" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
+ <font weight="900" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
NotoSansCJK-Regular.ttc
<axis tag="wght" stylevalue="900"/>
</font>
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index fe68123513ca..8977d5cad780 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -71,3 +71,10 @@ flag {
description: "Hides the bubble overflow if there aren't any overflowed bubbles"
bug: "334175587"
}
+
+flag {
+ name: "enable_retrievable_bubbles"
+ namespace: "multitasking"
+ description: "Allow opening bubbles overflow UI without bubbles being visible"
+ bug: "340337839"
+}
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 163a896e2659..5600664a8f47 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
@@ -646,7 +646,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private void tryDispatchOnBackCancelled(IOnBackInvokedCallback callback) {
if (!mOnBackStartDispatched) {
- Log.e(TAG, "Skipping dispatching onBackCancelled. Start was never dispatched.");
+ Log.d(TAG, "Skipping dispatching onBackCancelled. Start was never dispatched.");
return;
}
if (callback == null) {
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 037b1ec9247c..c988c2fb5103 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
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.wm.shell.back
import android.animation.Animator
@@ -34,6 +35,7 @@ import android.view.RemoteAnimationTarget
import android.view.SurfaceControl
import android.view.animation.DecelerateInterpolator
import android.view.animation.Interpolator
+import android.view.animation.Transformation
import android.window.BackEvent
import android.window.BackMotionEvent
import android.window.BackNavigationInfo
@@ -46,52 +48,45 @@ import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.animation.Interpolators
import com.android.wm.shell.protolog.ShellProtoLogGroup
-import com.android.wm.shell.shared.annotations.ShellMainThread
-import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
-/** Class that defines cross-activity animation. */
-@ShellMainThread
-class CrossActivityBackAnimation @Inject constructor(
+abstract class CrossActivityBackAnimation(
private val context: Context,
private val background: BackAnimationBackground,
- private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+ private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
+ protected val transaction: SurfaceControl.Transaction,
+ private val choreographer: Choreographer
) : ShellBackAnimation() {
- private val startClosingRect = RectF()
- private val targetClosingRect = RectF()
- private val currentClosingRect = RectF()
+ protected val startClosingRect = RectF()
+ protected val targetClosingRect = RectF()
+ protected val currentClosingRect = RectF()
- private val startEnteringRect = RectF()
- private val targetEnteringRect = RectF()
- private val currentEnteringRect = RectF()
+ protected val startEnteringRect = RectF()
+ protected val targetEnteringRect = RectF()
+ protected val currentEnteringRect = RectF()
- private val backAnimRect = Rect()
+ protected val backAnimRect = Rect()
private val cropRect = Rect()
private var cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
- private val backAnimationRunner = BackAnimationRunner(
- Callback(), Runner(), context, Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY
- )
+ private val backAnimationRunner =
+ BackAnimationRunner(Callback(), Runner(), context, Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY)
private val initialTouchPos = PointF()
private val transformMatrix = Matrix()
private val tmpFloat9 = FloatArray(9)
- private var enteringTarget: RemoteAnimationTarget? = null
- private var closingTarget: RemoteAnimationTarget? = null
- private val transaction = SurfaceControl.Transaction()
+ protected var enteringTarget: RemoteAnimationTarget? = null
+ protected var closingTarget: RemoteAnimationTarget? = null
private var triggerBack = false
private var finishCallback: IRemoteAnimationFinishedCallback? = null
private val progressAnimator = BackProgressAnimator()
private val displayBoundsMargin =
context.resources.getDimension(R.dimen.cross_task_back_vertical_margin)
- private val enteringStartOffset =
- context.resources.getDimension(R.dimen.cross_activity_back_entering_start_offset)
private val gestureInterpolator = Interpolators.BACK_GESTURE
- private val postCommitInterpolator = Interpolators.FAST_OUT_SLOW_IN
private val verticalMoveInterpolator: Interpolator = DecelerateInterpolator()
private var scrimLayer: SurfaceControl? = null
@@ -103,13 +98,42 @@ class CrossActivityBackAnimation @Inject constructor(
private var rightLetterboxLayer: SurfaceControl? = null
private var letterboxColor: Int = 0
+ /** Background color to be used during the animation, also see [getBackgroundColor] */
+ protected var customizedBackgroundColor = 0
+
+ /**
+ * Whether the entering target should be shifted vertically with the user gesture in pre-commit
+ */
+ abstract val allowEnteringYShift: Boolean
+
+ /**
+ * Subclasses must set the [startEnteringRect] and [targetEnteringRect] to define the movement
+ * of the enteringTarget during pre-commit phase.
+ */
+ abstract fun preparePreCommitEnteringRectMovement()
+
+ /**
+ * Returns a base transformation to apply to the entering target during pre-commit. The system
+ * will apply the default animation on top of it.
+ */
+ protected open fun getPreCommitEnteringBaseTransformation(progress: Float): Transformation? =
+ null
+
override fun onConfigurationChanged(newConfiguration: Configuration) {
cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
}
override fun getRunner() = backAnimationRunner
- private fun startBackAnimation(backMotionEvent: BackMotionEvent) {
+ private fun getBackgroundColor(): Int =
+ when {
+ customizedBackgroundColor != 0 -> customizedBackgroundColor
+ isLetterboxed -> letterboxColor
+ enteringTarget != null -> enteringTarget!!.taskInfo.taskDescription!!.backgroundColor
+ else -> 0
+ }
+
+ protected open fun startBackAnimation(backMotionEvent: BackMotionEvent) {
if (enteringTarget == null || closingTarget == null) {
ProtoLog.d(
ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW,
@@ -122,8 +146,8 @@ class CrossActivityBackAnimation @Inject constructor(
transaction.setAnimationTransaction()
isLetterboxed = closingTarget!!.taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed
- enteringHasSameLetterbox = isLetterboxed &&
- closingTarget!!.localBounds.equals(enteringTarget!!.localBounds)
+ enteringHasSameLetterbox =
+ isLetterboxed && closingTarget!!.localBounds.equals(enteringTarget!!.localBounds)
if (isLetterboxed && !enteringHasSameLetterbox) {
// Play animation with letterboxes, if closing and entering target have mismatching
@@ -143,32 +167,27 @@ class CrossActivityBackAnimation @Inject constructor(
targetClosingRect.scaleCentered(MAX_SCALE)
if (backMotionEvent.swipeEdge != BackEvent.EDGE_RIGHT) {
targetClosingRect.offset(
- startClosingRect.right - targetClosingRect.right - displayBoundsMargin, 0f
+ startClosingRect.right - targetClosingRect.right - displayBoundsMargin,
+ 0f
)
}
- // the entering target starts 96dp to the left of the screen edge...
- startEnteringRect.set(startClosingRect)
- startEnteringRect.offset(-enteringStartOffset, 0f)
-
- // ...and gets scaled in sync with the closing target
- targetEnteringRect.set(startEnteringRect)
- targetEnteringRect.scaleCentered(MAX_SCALE)
+ preparePreCommitEnteringRectMovement()
- // Draw background with task background color (or letterbox color).
- val backgroundColor = if (isLetterboxed) {
- letterboxColor
- } else {
- enteringTarget!!.taskInfo.taskDescription!!.backgroundColor
- }
background.ensureBackground(
- closingTarget!!.windowConfiguration.bounds, backgroundColor, transaction
+ closingTarget!!.windowConfiguration.bounds,
+ getBackgroundColor(),
+ transaction
)
ensureScrimLayer()
if (isLetterboxed && enteringHasSameLetterbox) {
// crop left and right letterboxes
- cropRect.set(closingTarget!!.localBounds.left, 0, closingTarget!!.localBounds.right,
- closingTarget!!.windowConfiguration.bounds.height())
+ cropRect.set(
+ closingTarget!!.localBounds.left,
+ 0,
+ closingTarget!!.localBounds.right,
+ closingTarget!!.windowConfiguration.bounds.height()
+ )
// and add fake letterbox square surfaces instead
ensureLetterboxes()
} else {
@@ -185,8 +204,14 @@ class CrossActivityBackAnimation @Inject constructor(
currentClosingRect.offset(0f, yOffset)
applyTransform(closingTarget?.leash, currentClosingRect, 1f)
currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress)
- currentEnteringRect.offset(0f, yOffset)
- applyTransform(enteringTarget?.leash, currentEnteringRect, 1f)
+ if (allowEnteringYShift) currentEnteringRect.offset(0f, yOffset)
+ val enteringTransformation = getPreCommitEnteringBaseTransformation(progress)
+ applyTransform(
+ enteringTarget?.leash,
+ currentEnteringRect,
+ enteringTransformation?.alpha ?: 1f,
+ enteringTransformation
+ )
applyTransaction()
}
@@ -199,30 +224,25 @@ class CrossActivityBackAnimation @Inject constructor(
val deltaYRatio = min(screenHeight / 2f, abs(rawYDelta)) / (screenHeight / 2f)
val interpolatedYRatio: Float = verticalMoveInterpolator.getInterpolation(deltaYRatio)
// limit y-shift so surface never passes 8dp screen margin
- val deltaY = yDirection * interpolatedYRatio * max(
- 0f, (screenHeight - centeredRect.height()) / 2f - displayBoundsMargin
- )
+ val deltaY =
+ max(0f, (screenHeight - centeredRect.height()) / 2f - displayBoundsMargin) *
+ interpolatedYRatio *
+ yDirection
return deltaY
}
- private fun onGestureCommitted() {
- if (closingTarget?.leash == null || enteringTarget?.leash == null ||
- !enteringTarget!!.leash.isValid || !closingTarget!!.leash.isValid
+ protected open fun onGestureCommitted() {
+ if (
+ closingTarget?.leash == null ||
+ enteringTarget?.leash == null ||
+ !enteringTarget!!.leash.isValid ||
+ !closingTarget!!.leash.isValid
) {
finishAnimation()
return
}
- // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current
- // coordinate of the gesture driven phase. Let's update the start and target rects and kick
- // off the animator
- startClosingRect.set(currentClosingRect)
- startEnteringRect.set(currentEnteringRect)
- targetEnteringRect.set(backAnimRect)
- targetClosingRect.set(backAnimRect)
- targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f)
-
- val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_ANIMATION_DURATION)
+ val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_COMMIT_DURATION)
valueAnimator.addUpdateListener { animation: ValueAnimator ->
val progress = animation.animatedFraction
onPostCommitProgress(progress)
@@ -230,27 +250,22 @@ class CrossActivityBackAnimation @Inject constructor(
background.resetStatusBarCustomization()
}
}
- valueAnimator.addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- background.resetStatusBarCustomization()
- finishAnimation()
+ valueAnimator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ background.resetStatusBarCustomization()
+ finishAnimation()
+ }
}
- })
+ )
valueAnimator.start()
}
- private fun onPostCommitProgress(linearProgress: Float) {
- val closingAlpha = max(1f - linearProgress * 2, 0f)
- val progress = postCommitInterpolator.getInterpolation(linearProgress)
+ protected open fun onPostCommitProgress(linearProgress: Float) {
scrimLayer?.let { transaction.setAlpha(it, maxScrimAlpha * (1f - linearProgress)) }
- currentClosingRect.setInterpolatedRectF(startClosingRect, targetClosingRect, progress)
- applyTransform(closingTarget?.leash, currentClosingRect, closingAlpha)
- currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress)
- applyTransform(enteringTarget?.leash, currentEnteringRect, 1f)
- applyTransaction()
}
- private fun finishAnimation() {
+ protected open fun finishAnimation() {
enteringTarget?.let {
if (it.leash != null && it.leash.isValid) {
transaction.setCornerRadius(it.leash, 0f)
@@ -278,47 +293,56 @@ class CrossActivityBackAnimation @Inject constructor(
enteringHasSameLetterbox = false
}
- private fun applyTransform(leash: SurfaceControl?, rect: RectF, alpha: Float) {
+ protected fun applyTransform(
+ leash: SurfaceControl?,
+ rect: RectF,
+ alpha: Float,
+ baseTransformation: Transformation? = null
+ ) {
if (leash == null || !leash.isValid) return
val scale = rect.width() / backAnimRect.width()
- transformMatrix.reset()
- val scalePivotX = if (isLetterboxed && enteringHasSameLetterbox) {
- closingTarget!!.localBounds.left.toFloat()
- } else {
- 0f
- }
- transformMatrix.setScale(scale, scale, scalePivotX, 0f)
- transformMatrix.postTranslate(rect.left, rect.top)
- transaction.setAlpha(leash, alpha)
- .setMatrix(leash, transformMatrix, tmpFloat9)
+ val matrix = baseTransformation?.matrix ?: transformMatrix.apply { reset() }
+ val scalePivotX =
+ if (isLetterboxed && enteringHasSameLetterbox) {
+ closingTarget!!.localBounds.left.toFloat()
+ } else {
+ 0f
+ }
+ matrix.postScale(scale, scale, scalePivotX, 0f)
+ matrix.postTranslate(rect.left, rect.top)
+ transaction
+ .setAlpha(leash, keepMinimumAlpha(alpha))
+ .setMatrix(leash, matrix, tmpFloat9)
.setCrop(leash, cropRect)
.setCornerRadius(leash, cornerRadius)
}
- private fun applyTransaction() {
- transaction.setFrameTimelineVsync(Choreographer.getInstance().vsyncId)
+ protected fun applyTransaction() {
+ transaction.setFrameTimelineVsync(choreographer.vsyncId)
transaction.apply()
}
private fun ensureScrimLayer() {
if (scrimLayer != null) return
val isDarkTheme: Boolean = isDarkMode(context)
- val scrimBuilder = SurfaceControl.Builder()
- .setName("Cross-Activity back animation scrim")
- .setCallsite("CrossActivityBackAnimation")
- .setColorLayer()
- .setOpaque(false)
- .setHidden(false)
+ val scrimBuilder =
+ SurfaceControl.Builder()
+ .setName("Cross-Activity back animation scrim")
+ .setCallsite("CrossActivityBackAnimation")
+ .setColorLayer()
+ .setOpaque(false)
+ .setHidden(false)
rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, scrimBuilder)
scrimLayer = scrimBuilder.build()
val colorComponents = floatArrayOf(0f, 0f, 0f)
maxScrimAlpha = if (isDarkTheme) MAX_SCRIM_ALPHA_DARK else MAX_SCRIM_ALPHA_LIGHT
- val scrimCrop = if (isLetterboxed) {
- closingTarget!!.windowConfiguration.bounds
- } else {
- closingTarget!!.localBounds
- }
+ val scrimCrop =
+ if (isLetterboxed) {
+ closingTarget!!.windowConfiguration.bounds
+ } else {
+ closingTarget!!.localBounds
+ }
transaction
.setColor(scrimLayer, colorComponents)
.setAlpha(scrimLayer!!, maxScrimAlpha)
@@ -339,21 +363,34 @@ class CrossActivityBackAnimation @Inject constructor(
private fun ensureLetterboxes() {
closingTarget?.let { t ->
if (t.localBounds.left != 0 && leftLetterboxLayer == null) {
- val bounds = Rect(0, t.windowConfiguration.bounds.top, t.localBounds.left,
- t.windowConfiguration.bounds.bottom)
+ val bounds =
+ Rect(
+ 0,
+ t.windowConfiguration.bounds.top,
+ t.localBounds.left,
+ t.windowConfiguration.bounds.bottom
+ )
leftLetterboxLayer = ensureLetterbox(bounds)
}
- if (t.localBounds.right != t.windowConfiguration.bounds.right &&
- rightLetterboxLayer == null) {
- val bounds = Rect(t.localBounds.right, t.windowConfiguration.bounds.top,
- t.windowConfiguration.bounds.right, t.windowConfiguration.bounds.bottom)
+ if (
+ t.localBounds.right != t.windowConfiguration.bounds.right &&
+ rightLetterboxLayer == null
+ ) {
+ val bounds =
+ Rect(
+ t.localBounds.right,
+ t.windowConfiguration.bounds.top,
+ t.windowConfiguration.bounds.right,
+ t.windowConfiguration.bounds.bottom
+ )
rightLetterboxLayer = ensureLetterbox(bounds)
}
}
}
private fun ensureLetterbox(bounds: Rect): SurfaceControl {
- val letterboxBuilder = SurfaceControl.Builder()
+ val letterboxBuilder =
+ SurfaceControl.Builder()
.setName("Cross-Activity back animation letterbox")
.setCallsite("CrossActivityBackAnimation")
.setColorLayer()
@@ -362,13 +399,17 @@ class CrossActivityBackAnimation @Inject constructor(
rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, letterboxBuilder)
val layer = letterboxBuilder.build()
- val colorComponents = floatArrayOf(Color.red(letterboxColor) / 255f,
- Color.green(letterboxColor) / 255f, Color.blue(letterboxColor) / 255f)
+ val colorComponents =
+ floatArrayOf(
+ Color.red(letterboxColor) / 255f,
+ Color.green(letterboxColor) / 255f,
+ Color.blue(letterboxColor) / 255f
+ )
transaction
- .setColor(layer, colorComponents)
- .setCrop(layer, bounds)
- .setRelativeLayer(layer, closingTarget!!.leash, 1)
- .show(layer)
+ .setColor(layer, colorComponents)
+ .setCrop(layer, bounds)
+ .setRelativeLayer(layer, closingTarget!!.leash, 1)
+ .show(layer)
return layer
}
@@ -389,8 +430,8 @@ class CrossActivityBackAnimation @Inject constructor(
}
override fun prepareNextAnimation(
- animationInfo: BackNavigationInfo.CustomAnimationInfo?,
- letterboxColor: Int
+ animationInfo: BackNavigationInfo.CustomAnimationInfo?,
+ letterboxColor: Int
): Boolean {
this.letterboxColor = letterboxColor
return false
@@ -415,9 +456,7 @@ class CrossActivityBackAnimation @Inject constructor(
}
override fun onBackCancelled() {
- progressAnimator.onBackCancelled {
- finishAnimation()
- }
+ progressAnimator.onBackCancelled { finishAnimation() }
}
override fun onBackInvoked() {
@@ -435,7 +474,8 @@ class CrossActivityBackAnimation @Inject constructor(
finishedCallback: IRemoteAnimationFinishedCallback
) {
ProtoLog.d(
- ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, "Start back to activity animation."
+ ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW,
+ "Start back to activity animation."
)
for (a in apps) {
when (a.mode) {
@@ -452,23 +492,25 @@ class CrossActivityBackAnimation @Inject constructor(
}
companion object {
- /** Max scale of the entering/closing window.*/
- private const val MAX_SCALE = 0.9f
-
- /** Duration of post animation after gesture committed. */
- private const val POST_ANIMATION_DURATION = 300L
-
+ /** Max scale of the closing window. */
+ internal const val MAX_SCALE = 0.9f
private const val MAX_SCRIM_ALPHA_DARK = 0.8f
private const val MAX_SCRIM_ALPHA_LIGHT = 0.2f
+ private const val POST_COMMIT_DURATION = 300L
}
}
+// The target will loose focus when alpha == 0, so keep a minimum value for it.
+private fun keepMinimumAlpha(transAlpha: Float): Float {
+ return max(transAlpha.toDouble(), 0.005).toFloat()
+}
+
private fun isDarkMode(context: Context): Boolean {
return context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
- Configuration.UI_MODE_NIGHT_YES
+ Configuration.UI_MODE_NIGHT_YES
}
-private fun RectF.setInterpolatedRectF(start: RectF, target: RectF, progress: Float) {
+internal fun RectF.setInterpolatedRectF(start: RectF, target: RectF, progress: Float) {
require(!(progress < 0 || progress > 1)) { "Progress value must be between 0 and 1" }
left = start.left + (target.left - start.left) * progress
top = start.top + (target.top - start.top) * progress
@@ -476,7 +518,7 @@ private fun RectF.setInterpolatedRectF(start: RectF, target: RectF, progress: Fl
bottom = start.bottom + (target.bottom - start.bottom) * progress
}
-private fun RectF.scaleCentered(
+internal fun RectF.scaleCentered(
scale: Float,
pivotX: Float = left + width() / 2,
pivotY: Float = top + height() / 2
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
new file mode 100644
index 000000000000..e6ec2b449616
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.back
+
+import android.content.Context
+import android.graphics.Rect
+import android.graphics.RectF
+import android.util.MathUtils
+import android.view.Choreographer
+import android.view.SurfaceControl
+import android.view.animation.Animation
+import android.view.animation.Transformation
+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.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import javax.inject.Inject
+
+/** Class that handles customized predictive cross activity back animations. */
+@ShellMainThread
+class CustomCrossActivityBackAnimation(
+ context: Context,
+ background: BackAnimationBackground,
+ rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
+ transaction: SurfaceControl.Transaction,
+ choreographer: Choreographer,
+ private val customAnimationLoader: CustomAnimationLoader
+) :
+ CrossActivityBackAnimation(
+ context,
+ background,
+ rootTaskDisplayAreaOrganizer,
+ transaction,
+ choreographer
+ ) {
+
+ private var enterAnimation: Animation? = null
+ private var closeAnimation: Animation? = null
+ private val transformation = Transformation()
+ private var gestureProgress = 0f
+
+ override val allowEnteringYShift = false
+
+ @Inject
+ constructor(
+ context: Context,
+ background: BackAnimationBackground,
+ rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+ ) : this(
+ context,
+ background,
+ rootTaskDisplayAreaOrganizer,
+ SurfaceControl.Transaction(),
+ Choreographer.getInstance(),
+ CustomAnimationLoader(
+ TransitionAnimation(context, false /* debug */, "CustomCrossActivityBackAnimation")
+ )
+ )
+
+ override fun preparePreCommitEnteringRectMovement() {
+ // No movement for the entering rect
+ startEnteringRect.set(startClosingRect)
+ targetEnteringRect.set(startClosingRect)
+ }
+
+ override fun getPreCommitEnteringBaseTransformation(progress: Float): Transformation {
+ gestureProgress = progress
+ transformation.clear()
+ enterAnimation!!.getTransformationAt(progress * PRE_COMMIT_MAX_PROGRESS, transformation)
+ return transformation
+ }
+
+ override fun startBackAnimation(backMotionEvent: BackMotionEvent) {
+ super.startBackAnimation(backMotionEvent)
+ if (
+ closeAnimation == null ||
+ enterAnimation == null ||
+ closingTarget == null ||
+ enteringTarget == null
+ ) {
+ ProtoLog.d(
+ ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW,
+ "Enter animation or close animation is null."
+ )
+ return
+ }
+ initializeAnimation(closeAnimation!!, closingTarget!!.localBounds)
+ initializeAnimation(enterAnimation!!, enteringTarget!!.localBounds)
+ }
+
+ override fun onPostCommitProgress(linearProgress: Float) {
+ super.onPostCommitProgress(linearProgress)
+ if (closingTarget == null || enteringTarget == null) return
+
+ // TODO: Should we use the duration from the custom xml spec for the post-commit animation?
+ applyTransform(closingTarget!!.leash, currentClosingRect, linearProgress, closeAnimation!!)
+ val enteringProgress =
+ MathUtils.lerp(gestureProgress * PRE_COMMIT_MAX_PROGRESS, 1f, linearProgress)
+ applyTransform(
+ enteringTarget!!.leash,
+ currentEnteringRect,
+ enteringProgress,
+ enterAnimation!!
+ )
+ applyTransaction()
+ }
+
+ private fun applyTransform(
+ leash: SurfaceControl,
+ rect: RectF,
+ progress: Float,
+ animation: Animation
+ ) {
+ transformation.clear()
+ animation.getTransformationAt(progress, transformation)
+ applyTransform(leash, rect, transformation.alpha, transformation)
+ }
+
+ override fun finishAnimation() {
+ closeAnimation?.reset()
+ closeAnimation = null
+ enterAnimation?.reset()
+ enterAnimation = null
+ transformation.clear()
+ gestureProgress = 0f
+ super.finishAnimation()
+ }
+
+ /** Load customize animation before animation start. */
+ override fun prepareNextAnimation(
+ animationInfo: BackNavigationInfo.CustomAnimationInfo?,
+ letterboxColor: Int
+ ): Boolean {
+ super.prepareNextAnimation(animationInfo, letterboxColor)
+ if (animationInfo == null) return false
+ customAnimationLoader.loadAll(animationInfo)?.let { result ->
+ closeAnimation = result.closeAnimation
+ enterAnimation = result.enterAnimation
+ customizedBackgroundColor = result.backgroundColor
+ return true
+ }
+ return false
+ }
+
+ class AnimationLoadResult {
+ var closeAnimation: Animation? = null
+ var enterAnimation: Animation? = null
+ var backgroundColor = 0
+ }
+
+ companion object {
+ private const val PRE_COMMIT_MAX_PROGRESS = 0.2f
+ }
+}
+
+/** Helper class to load custom animation. */
+class CustomAnimationLoader(private val transitionAnimation: TransitionAnimation) {
+
+ /**
+ * Load both enter and exit animation for the close activity transition. Note that the result is
+ * only valid if the exit animation has set and loaded success. If the entering animation has
+ * not set(i.e. 0), here will load the default entering animation for it.
+ *
+ * @param animationInfo The information of customize animation, which can be set from
+ * [Activity.overrideActivityTransition] and/or [LayoutParams.windowAnimations]
+ */
+ fun loadAll(
+ animationInfo: BackNavigationInfo.CustomAnimationInfo
+ ): CustomCrossActivityBackAnimation.AnimationLoadResult? {
+ if (animationInfo.packageName.isEmpty()) return null
+ val close = loadAnimation(animationInfo, false) ?: return null
+ val open = loadAnimation(animationInfo, true)
+ val result = CustomCrossActivityBackAnimation.AnimationLoadResult()
+ result.closeAnimation = close
+ result.enterAnimation = open
+ result.backgroundColor = animationInfo.customBackground
+ return result
+ }
+
+ /**
+ * Load enter or exit animation from CustomAnimationInfo
+ *
+ * @param animationInfo The information for customize animation.
+ * @param enterAnimation true when load for enter animation, false for exit animation.
+ * @return Loaded animation.
+ */
+ fun loadAnimation(
+ animationInfo: BackNavigationInfo.CustomAnimationInfo,
+ enterAnimation: Boolean
+ ): Animation? {
+ var a: Animation? = null
+ // Activity#overrideActivityTransition has higher priority than windowAnimations
+ // Try to get animation from Activity#overrideActivityTransition
+ if (
+ enterAnimation && animationInfo.customEnterAnim != 0 ||
+ !enterAnimation && animationInfo.customExitAnim != 0
+ ) {
+ a =
+ transitionAnimation.loadAppTransitionAnimation(
+ animationInfo.packageName,
+ if (enterAnimation) animationInfo.customEnterAnim
+ else animationInfo.customExitAnim
+ )
+ } else if (animationInfo.windowAnimations != 0) {
+ // try to get animation from LayoutParams#windowAnimations
+ a =
+ transitionAnimation.loadAnimationAttr(
+ animationInfo.packageName,
+ animationInfo.windowAnimations,
+ if (enterAnimation) R.styleable.WindowAnimation_activityCloseEnterAnimation
+ else R.styleable.WindowAnimation_activityCloseExitAnimation,
+ false /* translucent */
+ )
+ }
+ // Only allow to load default animation for opening target.
+ if (a == null && enterAnimation) {
+ a = loadDefaultOpenAnimation()
+ }
+ if (a != null) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, "custom animation loaded %s", a)
+ } else {
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, "No custom animation loaded")
+ }
+ return a
+ }
+
+ private fun loadDefaultOpenAnimation(): Animation? {
+ return transitionAnimation.loadDefaultAnimationAttr(
+ R.styleable.WindowAnimation_activityCloseEnterAnimation,
+ false /* translucent */
+ )
+ }
+}
+
+private fun initializeAnimation(animation: Animation, bounds: Rect) {
+ val width = bounds.width()
+ val height = bounds.height()
+ animation.initialize(width, height, width, height)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
deleted file mode 100644
index e27b40e58591..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.back;
-
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-import static android.view.RemoteAnimationTarget.MODE_OPENING;
-
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY;
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.FloatProperty;
-import android.view.Choreographer;
-import android.view.IRemoteAnimationFinishedCallback;
-import android.view.IRemoteAnimationRunner;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.WindowManager.LayoutParams;
-import android.view.animation.Animation;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Transformation;
-import android.window.BackEvent;
-import android.window.BackMotionEvent;
-import android.window.BackNavigationInfo;
-import android.window.BackProgressAnimator;
-import android.window.IOnBackInvokedCallback;
-
-import com.android.internal.R;
-import com.android.internal.dynamicanimation.animation.SpringAnimation;
-import com.android.internal.dynamicanimation.animation.SpringForce;
-import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.shared.annotations.ShellMainThread;
-
-import javax.inject.Inject;
-
-/** Class that handle customized close activity transition animation. */
-@ShellMainThread
-public class CustomizeActivityAnimation extends ShellBackAnimation {
- private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
- private final BackAnimationRunner mBackAnimationRunner;
- private float mCornerRadius;
- private final SurfaceControl.Transaction mTransaction;
- private final BackAnimationBackground mBackground;
- private RemoteAnimationTarget mEnteringTarget;
- private RemoteAnimationTarget mClosingTarget;
- private IRemoteAnimationFinishedCallback mFinishCallback;
- /** Duration of post animation after gesture committed. */
- private static final int POST_ANIMATION_DURATION = 250;
-
- private static final int SCALE_FACTOR = 1000;
- private final SpringAnimation mProgressSpring;
- private float mLatestProgress = 0.0f;
-
- private static final float TARGET_COMMIT_PROGRESS = 0.5f;
-
- private final float[] mTmpFloat9 = new float[9];
- private final DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator();
-
- final CustomAnimationLoader mCustomAnimationLoader;
- private Animation mEnterAnimation;
- private Animation mCloseAnimation;
- private int mNextBackgroundColor;
- final Transformation mTransformation = new Transformation();
-
- private final Choreographer mChoreographer;
- private final Context mContext;
-
- @Inject
- public CustomizeActivityAnimation(Context context, BackAnimationBackground background) {
- this(context, background, new SurfaceControl.Transaction(), null);
- }
-
- CustomizeActivityAnimation(Context context, BackAnimationBackground background,
- SurfaceControl.Transaction transaction, Choreographer choreographer) {
- mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
- mBackground = background;
- mBackAnimationRunner = new BackAnimationRunner(
- new Callback(), new Runner(), context, CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY);
- mCustomAnimationLoader = new CustomAnimationLoader(context);
-
- mProgressSpring = new SpringAnimation(this, ENTER_PROGRESS_PROP);
- mProgressSpring.setSpring(new SpringForce()
- .setStiffness(SpringForce.STIFFNESS_MEDIUM)
- .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY));
- mTransaction = transaction == null ? new SurfaceControl.Transaction() : transaction;
- mChoreographer = choreographer != null ? choreographer : Choreographer.getInstance();
- mContext = context;
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext);
- }
-
- private float getLatestProgress() {
- return mLatestProgress * SCALE_FACTOR;
- }
- private void setLatestProgress(float value) {
- mLatestProgress = value / SCALE_FACTOR;
- applyTransformTransaction(mLatestProgress);
- }
-
- private static final FloatProperty<CustomizeActivityAnimation> ENTER_PROGRESS_PROP =
- new FloatProperty<>("enter") {
- @Override
- public void setValue(CustomizeActivityAnimation anim, float value) {
- anim.setLatestProgress(value);
- }
-
- @Override
- public Float get(CustomizeActivityAnimation object) {
- return object.getLatestProgress();
- }
- };
-
- // The target will lose focus when alpha == 0, so keep a minimum value for it.
- private static float keepMinimumAlpha(float transAlpha) {
- return Math.max(transAlpha, 0.005f);
- }
-
- private static void initializeAnimation(Animation animation, Rect bounds) {
- final int width = bounds.width();
- final int height = bounds.height();
- animation.initialize(width, height, width, height);
- }
-
- private void startBackAnimation() {
- if (mEnteringTarget == null || mClosingTarget == null
- || mCloseAnimation == null || mEnterAnimation == null) {
- ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Entering target or closing target is null.");
- return;
- }
- initializeAnimation(mCloseAnimation, mClosingTarget.localBounds);
- initializeAnimation(mEnterAnimation, mEnteringTarget.localBounds);
-
- // Draw background with task background color.
- if (mEnteringTarget.taskInfo != null && mEnteringTarget.taskInfo.taskDescription != null) {
- mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(),
- mNextBackgroundColor == Color.TRANSPARENT
- ? mEnteringTarget.taskInfo.taskDescription.getBackgroundColor()
- : mNextBackgroundColor,
- mTransaction);
- }
- }
-
- private void applyTransformTransaction(float progress) {
- if (mClosingTarget == null || mEnteringTarget == null) {
- return;
- }
- applyTransform(mClosingTarget.leash, progress, mCloseAnimation);
- applyTransform(mEnteringTarget.leash, progress, mEnterAnimation);
- mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
- mTransaction.apply();
- }
-
- private void applyTransform(SurfaceControl leash, float progress, Animation animation) {
- mTransformation.clear();
- animation.getTransformationAt(progress, mTransformation);
- mTransaction.setMatrix(leash, mTransformation.getMatrix(), mTmpFloat9);
- mTransaction.setAlpha(leash, keepMinimumAlpha(mTransformation.getAlpha()));
- mTransaction.setCornerRadius(leash, mCornerRadius);
- }
-
- void finishAnimation() {
- if (mCloseAnimation != null) {
- mCloseAnimation.reset();
- mCloseAnimation = null;
- }
- if (mEnterAnimation != null) {
- mEnterAnimation.reset();
- mEnterAnimation = null;
- }
- if (mEnteringTarget != null) {
- mEnteringTarget.leash.release();
- mEnteringTarget = null;
- }
- if (mClosingTarget != null) {
- mClosingTarget.leash.release();
- mClosingTarget = null;
- }
- if (mBackground != null) {
- mBackground.removeBackground(mTransaction);
- }
- mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
- mTransaction.apply();
- mTransformation.clear();
- mLatestProgress = 0;
- mNextBackgroundColor = Color.TRANSPARENT;
- if (mFinishCallback != null) {
- try {
- mFinishCallback.onAnimationFinished();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- mFinishCallback = null;
- }
- mProgressSpring.animateToFinalPosition(0);
- mProgressSpring.skipToEnd();
- }
-
- void onGestureProgress(@NonNull BackEvent backEvent) {
- if (mEnteringTarget == null || mClosingTarget == null
- || mCloseAnimation == null || mEnterAnimation == null) {
- return;
- }
-
- final float progress = backEvent.getProgress();
-
- float springProgress = (progress > 0.1f
- ? mapLinear(progress, 0.1f, 1f, TARGET_COMMIT_PROGRESS, 1f)
- : mapLinear(progress, 0, 1f, 0f, TARGET_COMMIT_PROGRESS)) * SCALE_FACTOR;
-
- mProgressSpring.animateToFinalPosition(springProgress);
- }
-
- static float mapLinear(float x, float a1, float a2, float b1, float b2) {
- return b1 + (x - a1) * (b2 - b1) / (a2 - a1);
- }
-
- void onGestureCommitted() {
- if (mEnteringTarget == null || mClosingTarget == null
- || mCloseAnimation == null || mEnterAnimation == null) {
- finishAnimation();
- return;
- }
- mProgressSpring.cancel();
-
- // Enter phase 2 of the animation
- final ValueAnimator valueAnimator = ValueAnimator.ofFloat(mLatestProgress, 1f)
- .setDuration(POST_ANIMATION_DURATION);
- valueAnimator.setInterpolator(mDecelerateInterpolator);
- valueAnimator.addUpdateListener(animation -> {
- float progress = (float) animation.getAnimatedValue();
- applyTransformTransaction(progress);
- });
-
- valueAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finishAnimation();
- }
- });
- valueAnimator.start();
- }
-
- /** Load customize animation before animation start. */
- @Override
- public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo,
- int letterboxColor) {
- if (animationInfo == null) {
- return false;
- }
- final AnimationLoadResult result = mCustomAnimationLoader.loadAll(animationInfo);
- if (result != null) {
- mCloseAnimation = result.mCloseAnimation;
- mEnterAnimation = result.mEnterAnimation;
- mNextBackgroundColor = result.mBackgroundColor;
- return true;
- }
- return false;
- }
-
- @Override
- public BackAnimationRunner getRunner() {
- return mBackAnimationRunner;
- }
-
- private final class Callback extends IOnBackInvokedCallback.Default {
- @Override
- public void onBackStarted(BackMotionEvent backEvent) {
- // in case we're still animating an onBackCancelled event, let's remove the finish-
- // callback from the progress animator to prevent calling finishAnimation() before
- // restarting a new animation
- mProgressAnimator.removeOnBackCancelledFinishCallback();
-
- mProgressAnimator.onBackStarted(backEvent,
- CustomizeActivityAnimation.this::onGestureProgress);
- }
-
- @Override
- public void onBackProgressed(@NonNull BackMotionEvent backEvent) {
- mProgressAnimator.onBackProgressed(backEvent);
- }
-
- @Override
- public void onBackCancelled() {
- mProgressAnimator.onBackCancelled(CustomizeActivityAnimation.this::finishAnimation);
- }
-
- @Override
- public void onBackInvoked() {
- mProgressAnimator.reset();
- onGestureCommitted();
- }
- }
-
- private final class Runner extends IRemoteAnimationRunner.Default {
- @Override
- public void onAnimationStart(
- int transit,
- RemoteAnimationTarget[] apps,
- RemoteAnimationTarget[] wallpapers,
- RemoteAnimationTarget[] nonApps,
- IRemoteAnimationFinishedCallback finishedCallback) {
- ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Start back to customize animation.");
- for (RemoteAnimationTarget a : apps) {
- if (a.mode == MODE_CLOSING) {
- mClosingTarget = a;
- }
- if (a.mode == MODE_OPENING) {
- mEnteringTarget = a;
- }
- }
- if (mCloseAnimation == null || mEnterAnimation == null) {
- ProtoLog.d(WM_SHELL_BACK_PREVIEW,
- "No animation loaded, should choose cross-activity animation?");
- }
-
- startBackAnimation();
- mFinishCallback = finishedCallback;
- }
-
- @Override
- public void onAnimationCancelled() {
- finishAnimation();
- }
- }
-
-
- static final class AnimationLoadResult {
- Animation mCloseAnimation;
- Animation mEnterAnimation;
- int mBackgroundColor;
- }
-
- /**
- * Helper class to load custom animation.
- */
- static class CustomAnimationLoader {
- final TransitionAnimation mTransitionAnimation;
-
- CustomAnimationLoader(Context context) {
- mTransitionAnimation = new TransitionAnimation(
- context, false /* debug */, "CustomizeBackAnimation");
- }
-
- /**
- * Load both enter and exit animation for the close activity transition.
- * Note that the result is only valid if the exit animation has set and loaded success.
- * If the entering animation has not set(i.e. 0), here will load the default entering
- * animation for it.
- *
- * @param animationInfo The information of customize animation, which can be set from
- * {@link Activity#overrideActivityTransition} and/or
- * {@link LayoutParams#windowAnimations}
- */
- AnimationLoadResult loadAll(BackNavigationInfo.CustomAnimationInfo animationInfo) {
- if (animationInfo.getPackageName().isEmpty()) {
- return null;
- }
- final Animation close = loadAnimation(animationInfo, false);
- if (close == null) {
- return null;
- }
- final Animation open = loadAnimation(animationInfo, true);
- AnimationLoadResult result = new AnimationLoadResult();
- result.mCloseAnimation = close;
- result.mEnterAnimation = open;
- result.mBackgroundColor = animationInfo.getCustomBackground();
- return result;
- }
-
- /**
- * Load enter or exit animation from CustomAnimationInfo
- * @param animationInfo The information for customize animation.
- * @param enterAnimation true when load for enter animation, false for exit animation.
- * @return Loaded animation.
- */
- @Nullable
- Animation loadAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo,
- boolean enterAnimation) {
- Animation a = null;
- // Activity#overrideActivityTransition has higher priority than windowAnimations
- // Try to get animation from Activity#overrideActivityTransition
- if ((enterAnimation && animationInfo.getCustomEnterAnim() != 0)
- || (!enterAnimation && animationInfo.getCustomExitAnim() != 0)) {
- a = mTransitionAnimation.loadAppTransitionAnimation(
- animationInfo.getPackageName(),
- enterAnimation ? animationInfo.getCustomEnterAnim()
- : animationInfo.getCustomExitAnim());
- } else if (animationInfo.getWindowAnimations() != 0) {
- // try to get animation from LayoutParams#windowAnimations
- a = mTransitionAnimation.loadAnimationAttr(animationInfo.getPackageName(),
- animationInfo.getWindowAnimations(), enterAnimation
- ? R.styleable.WindowAnimation_activityCloseEnterAnimation
- : R.styleable.WindowAnimation_activityCloseExitAnimation,
- false /* translucent */);
- }
- // Only allow to load default animation for opening target.
- if (a == null && enterAnimation) {
- a = loadDefaultOpenAnimation();
- }
- if (a != null) {
- ProtoLog.d(WM_SHELL_BACK_PREVIEW, "custom animation loaded %s", a);
- } else {
- ProtoLog.e(WM_SHELL_BACK_PREVIEW, "No custom animation loaded");
- }
- return a;
- }
-
- private Animation loadDefaultOpenAnimation() {
- return mTransitionAnimation.loadDefaultAnimationAttr(
- R.styleable.WindowAnimation_activityCloseEnterAnimation,
- false /* translucent */);
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
new file mode 100644
index 000000000000..f33c5b9bd183
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.back
+
+import android.content.Context
+import android.view.Choreographer
+import android.view.SurfaceControl
+import com.android.wm.shell.R
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import javax.inject.Inject
+import kotlin.math.max
+
+/** Class that defines cross-activity animation. */
+@ShellMainThread
+class DefaultCrossActivityBackAnimation
+@Inject
+constructor(
+ context: Context,
+ background: BackAnimationBackground,
+ rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+) :
+ CrossActivityBackAnimation(
+ context,
+ background,
+ rootTaskDisplayAreaOrganizer,
+ SurfaceControl.Transaction(),
+ Choreographer.getInstance()
+ ) {
+
+ private val postCommitInterpolator = Interpolators.FAST_OUT_SLOW_IN
+ private val enteringStartOffset =
+ context.resources.getDimension(R.dimen.cross_activity_back_entering_start_offset)
+ override val allowEnteringYShift = true
+
+ override fun preparePreCommitEnteringRectMovement() {
+ // the entering target starts 96dp to the left of the screen edge...
+ startEnteringRect.set(startClosingRect)
+ startEnteringRect.offset(-enteringStartOffset, 0f)
+ // ...and gets scaled in sync with the closing target
+ targetEnteringRect.set(startEnteringRect)
+ targetEnteringRect.scaleCentered(MAX_SCALE)
+ }
+
+ override fun onGestureCommitted() {
+ // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current
+ // coordinate of the gesture driven phase. Let's update the start and target rects and kick
+ // off the animator in the superclass
+ startClosingRect.set(currentClosingRect)
+ startEnteringRect.set(currentEnteringRect)
+ targetEnteringRect.set(backAnimRect)
+ targetClosingRect.set(backAnimRect)
+ targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f)
+ super.onGestureCommitted()
+ }
+
+ override fun onPostCommitProgress(linearProgress: Float) {
+ super.onPostCommitProgress(linearProgress)
+ val closingAlpha = max(1f - linearProgress * 2, 0f)
+ val progress = postCommitInterpolator.getInterpolation(linearProgress)
+ currentClosingRect.setInterpolatedRectF(startClosingRect, targetClosingRect, progress)
+ applyTransform(closingTarget?.leash, currentClosingRect, closingAlpha)
+ currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress)
+ applyTransform(enteringTarget?.leash, currentEnteringRect, 1f)
+ applyTransaction()
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java
index 795bc1a7113b..d2895b149b2c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java
@@ -16,9 +16,9 @@
package com.android.wm.shell.dagger.back;
-import com.android.wm.shell.back.CrossActivityBackAnimation;
import com.android.wm.shell.back.CrossTaskBackAnimation;
-import com.android.wm.shell.back.CustomizeActivityAnimation;
+import com.android.wm.shell.back.CustomCrossActivityBackAnimation;
+import com.android.wm.shell.back.DefaultCrossActivityBackAnimation;
import com.android.wm.shell.back.ShellBackAnimation;
import com.android.wm.shell.back.ShellBackAnimationRegistry;
@@ -47,7 +47,7 @@ public interface ShellBackAnimationModule {
@Binds
@ShellBackAnimation.CrossActivity
ShellBackAnimation bindCrossActivityShellBackAnimation(
- CrossActivityBackAnimation crossActivityBackAnimation);
+ DefaultCrossActivityBackAnimation defaultCrossActivityBackAnimation);
/** Default cross task back animation */
@Binds
@@ -59,5 +59,5 @@ public interface ShellBackAnimationModule {
@Binds
@ShellBackAnimation.CustomizeActivity
ShellBackAnimation provideCustomizeActivityShellBackAnimation(
- CustomizeActivityAnimation customizeActivityAnimation);
+ CustomCrossActivityBackAnimation customCrossActivityBackAnimation);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index b2bdbfefb9aa..091685e72529 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -227,7 +227,7 @@ class DesktopTasksController(
bringDesktopAppsToFront(displayId, wct)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- // TODO(b/255649902): ensure remote transition is supplied once state is introduced
+ // TODO(b/309014605): ensure remote transition is supplied once state is introduced
val transitionType = if (remoteTransition == null) TRANSIT_NONE else TRANSIT_TO_FRONT
val handler = remoteTransition?.let {
OneShotRemoteHandler(transitions.mainExecutor, remoteTransition)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index e419462012e3..e07e1b460168 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -45,6 +45,7 @@ import android.window.SplashScreenView;
import com.android.internal.R;
+import java.io.Closeable;
import java.util.function.LongConsumer;
/**
@@ -100,7 +101,7 @@ public class SplashscreenIconDrawableFactory {
* Drawable pre-drawing the scaled icon in a separate thread to increase the speed of the
* final drawing.
*/
- private static class ImmobileIconDrawable extends Drawable {
+ private static class ImmobileIconDrawable extends Drawable implements Closeable {
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
| Paint.FILTER_BITMAP_FLAG);
private final Matrix mMatrix = new Matrix();
@@ -154,6 +155,16 @@ public class SplashscreenIconDrawableFactory {
public int getOpacity() {
return 1;
}
+
+ @Override
+ public void close() {
+ synchronized (mPaint) {
+ if (mIconBitmap != null) {
+ mIconBitmap.recycle();
+ mIconBitmap = null;
+ }
+ }
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java
index 1897560deed7..d558f953bc36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java
@@ -49,8 +49,12 @@ public class PerfettoTransitionTracer implements TransitionTracer {
public PerfettoTransitionTracer() {
Producer.init(InitArguments.DEFAULTS);
- mDataSource.register(
- new DataSourceParams(PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT));
+ DataSourceParams params =
+ new DataSourceParams.Builder()
+ .setBufferExhaustedPolicy(
+ PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT)
+ .build();
+ mDataSource.register(params);
}
/**
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
index bc486c277aa5..984abf8cf8b4 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
@@ -32,7 +32,7 @@ import org.junit.runners.Parameterized
/**
* Test launching a new activity from bubble.
*
- * To run this test: `atest WMShellFlickerTests:MultiBubblesScreen`
+ * To run this test: `atest WMShellFlickerTestsBubbles:ChangeActiveActivityFromBubbleTest`
*
* Actions:
* ```
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
index 2a9b1078afe3..886b70c5e464 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
@@ -35,7 +35,7 @@ import org.junit.runners.Parameterized
/**
* Test launching a new activity from bubble.
*
- * To run this test: `atest WMShellFlickerTests:DismissBubbleScreen`
+ * To run this test: `atest WMShellFlickerTestsBubbles:DragToDismissBubbleScreenTest`
*
* Actions:
* ```
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
index 9ef49c1c9e7e..2ee53f4fce66 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
@@ -38,7 +38,7 @@ import org.junit.runners.Parameterized
/**
* Test launching a new activity from bubble.
*
- * To run this test: `atest WMShellFlickerTests:OpenActivityFromBubbleOnLocksreenTest`
+ * To run this test: `atest WMShellFlickerTestsBubbles:OpenActivityFromBubbleOnLocksreenTest`
*
* Actions:
* ```
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
index ef7fbfb79beb..463fe0e60da3 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
@@ -29,7 +29,7 @@ import org.junit.runners.Parameterized
/**
* Test launching a new activity from bubble.
*
- * To run this test: `atest WMShellFlickerTests:ExpandBubbleScreen`
+ * To run this test: `atest WMShellFlickerTestsBubbles:OpenActivityFromBubbleTest`
*
* Actions:
* ```
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
index 87224b151b78..8df50567a29c 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
@@ -29,7 +29,7 @@ import org.junit.runners.Parameterized
/**
* Test creating a bubble notification
*
- * To run this test: `atest WMShellFlickerTests:LaunchBubbleScreen`
+ * To run this test: `atest WMShellFlickerTestsBubbles:SendBubbleNotificationTest`
*
* Actions:
* ```
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/DesktopModeFlickerScenarios.kt
index 17cace0da739..d485b82f5ddb 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/DesktopModeFlickerScenarios.kt
@@ -21,6 +21,7 @@ import android.tools.flicker.assertors.assertions.AppLayerIsInvisibleAtEnd
import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAlways
import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAtStart
import android.tools.flicker.assertors.assertions.AppWindowHasDesktopModeInitialBoundsAtTheEnd
+import android.tools.flicker.assertors.assertions.AppWindowIsVisibleAlways
import android.tools.flicker.assertors.assertions.AppWindowOnTopAtEnd
import android.tools.flicker.assertors.assertions.AppWindowOnTopAtStart
import android.tools.flicker.assertors.assertions.AppWindowRemainInsideDisplayBounds
@@ -133,9 +134,8 @@ class DesktopModeFlickerScenarios {
}
),
assertions =
- AssertionTemplates.COMMON_ASSERTIONS +
listOf(
- AppLayerIsVisibleAlways(Components.DESKTOP_MODE_APP),
+ AppWindowIsVisibleAlways(Components.DESKTOP_MODE_APP),
AppWindowOnTopAtEnd(Components.DESKTOP_MODE_APP),
AppWindowRemainInsideDisplayBounds(Components.DESKTOP_MODE_APP),
).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index f99b4b2beef0..f6f3aa49bc6e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -120,7 +120,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
private TestableContentResolver mContentResolver;
private TestableLooper mTestableLooper;
- private CrossActivityBackAnimation mCrossActivityBackAnimation;
+ private DefaultCrossActivityBackAnimation mDefaultCrossActivityBackAnimation;
private CrossTaskBackAnimation mCrossTaskBackAnimation;
private ShellBackAnimationRegistry mShellBackAnimationRegistry;
@@ -135,13 +135,14 @@ public class BackAnimationControllerTest extends ShellTestCase {
ANIMATION_ENABLED);
mTestableLooper = TestableLooper.get(this);
mShellInit = spy(new ShellInit(mShellExecutor));
- mCrossActivityBackAnimation = new CrossActivityBackAnimation(mContext, mAnimationBackground,
- mRootTaskDisplayAreaOrganizer);
+ mDefaultCrossActivityBackAnimation = new DefaultCrossActivityBackAnimation(mContext,
+ mAnimationBackground, mRootTaskDisplayAreaOrganizer);
mCrossTaskBackAnimation = new CrossTaskBackAnimation(mContext, mAnimationBackground);
mShellBackAnimationRegistry =
- new ShellBackAnimationRegistry(mCrossActivityBackAnimation, mCrossTaskBackAnimation,
- /* dialogCloseAnimation= */ null,
- new CustomizeActivityAnimation(mContext, mAnimationBackground),
+ new ShellBackAnimationRegistry(mDefaultCrossActivityBackAnimation,
+ mCrossTaskBackAnimation, /* dialogCloseAnimation= */ null,
+ new CustomCrossActivityBackAnimation(mContext, mAnimationBackground,
+ mRootTaskDisplayAreaOrganizer),
/* defaultBackToHomeAnimation= */ null);
mController =
new BackAnimationController(
@@ -582,7 +583,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
@Test
public void testBackToActivity() throws RemoteException {
verifySystemBackBehavior(BackNavigationInfo.TYPE_CROSS_ACTIVITY,
- mCrossActivityBackAnimation.getRunner());
+ mDefaultCrossActivityBackAnimation.getRunner());
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
new file mode 100644
index 000000000000..8bf011192347
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.f
+ */
+package com.android.wm.shell.back
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.AppCompatTaskInfo
+import android.app.WindowConfiguration
+import android.graphics.Color
+import android.graphics.Point
+import android.graphics.Rect
+import android.os.RemoteException
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.Choreographer
+import android.view.RemoteAnimationTarget
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import android.view.animation.Animation
+import android.window.BackEvent
+import android.window.BackMotionEvent
+import android.window.BackNavigationInfo
+import androidx.test.filters.SmallTest
+import com.android.internal.policy.TransitionAnimation
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.ShellTestCase
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import junit.framework.TestCase.assertEquals
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class CustomCrossActivityBackAnimationTest : ShellTestCase() {
+ @Mock private lateinit var backAnimationBackground: BackAnimationBackground
+ @Mock private lateinit var mockCloseAnimation: Animation
+ @Mock private lateinit var mockOpenAnimation: Animation
+ @Mock private lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+ @Mock private lateinit var transitionAnimation: TransitionAnimation
+ @Mock private lateinit var appCompatTaskInfo: AppCompatTaskInfo
+ @Mock private lateinit var transaction: Transaction
+
+ private lateinit var customCrossActivityBackAnimation: CustomCrossActivityBackAnimation
+ private lateinit var customAnimationLoader: CustomAnimationLoader
+
+ @Before
+ @Throws(Exception::class)
+ fun setUp() {
+ customAnimationLoader = CustomAnimationLoader(transitionAnimation)
+ customCrossActivityBackAnimation =
+ CustomCrossActivityBackAnimation(
+ context,
+ backAnimationBackground,
+ rootTaskDisplayAreaOrganizer,
+ transaction,
+ mock(Choreographer::class.java),
+ customAnimationLoader
+ )
+
+ whenever(transitionAnimation.loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(OPEN_RES_ID)))
+ .thenReturn(mockOpenAnimation)
+ whenever(transitionAnimation.loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(CLOSE_RES_ID)))
+ .thenReturn(mockCloseAnimation)
+ whenever(transaction.setColor(any(), any())).thenReturn(transaction)
+ whenever(transaction.setAlpha(any(), anyFloat())).thenReturn(transaction)
+ whenever(transaction.setCrop(any(), any())).thenReturn(transaction)
+ whenever(transaction.setRelativeLayer(any(), any(), anyInt())).thenReturn(transaction)
+ spy(customCrossActivityBackAnimation)
+ }
+
+ @Test
+ @Throws(InterruptedException::class)
+ fun receiveFinishAfterInvoke() {
+ val finishCalled = startCustomAnimation()
+ try {
+ customCrossActivityBackAnimation.getRunner().callback.onBackInvoked()
+ } catch (r: RemoteException) {
+ Assert.fail("onBackInvoked throw remote exception")
+ }
+ finishCalled.await(1, TimeUnit.SECONDS)
+ }
+
+ @Test
+ @Throws(InterruptedException::class)
+ fun receiveFinishAfterCancel() {
+ val finishCalled = startCustomAnimation()
+ try {
+ customCrossActivityBackAnimation.getRunner().callback.onBackCancelled()
+ } catch (r: RemoteException) {
+ Assert.fail("onBackCancelled throw remote exception")
+ }
+ finishCalled.await(1, TimeUnit.SECONDS)
+ }
+
+ @Test
+ @Throws(InterruptedException::class)
+ fun receiveFinishWithoutAnimationAfterInvoke() {
+ val finishCalled = startCustomAnimation(targets = arrayOf())
+ try {
+ customCrossActivityBackAnimation.getRunner().callback.onBackInvoked()
+ } catch (r: RemoteException) {
+ Assert.fail("onBackInvoked throw remote exception")
+ }
+ finishCalled.await(1, TimeUnit.SECONDS)
+ }
+
+ @Test
+ fun testLoadCustomAnimation() {
+ testLoadCustomAnimation(OPEN_RES_ID, CLOSE_RES_ID, 0)
+ }
+
+ @Test
+ fun testLoadCustomAnimationNoEnter() {
+ testLoadCustomAnimation(0, CLOSE_RES_ID, 0)
+ }
+
+ @Test
+ fun testLoadWindowAnimations() {
+ testLoadCustomAnimation(0, 0, 30)
+ }
+
+ @Test
+ fun testCustomAnimationHigherThanWindowAnimations() {
+ testLoadCustomAnimation(OPEN_RES_ID, CLOSE_RES_ID, 30)
+ }
+
+ private fun testLoadCustomAnimation(enterResId: Int, exitResId: Int, windowAnimations: Int) {
+ val builder =
+ BackNavigationInfo.Builder()
+ .setCustomAnimation(PACKAGE_NAME, enterResId, exitResId, Color.GREEN)
+ .setWindowAnimations(PACKAGE_NAME, windowAnimations)
+ val info = builder.build().customAnimationInfo!!
+ whenever(
+ transitionAnimation.loadAnimationAttr(
+ eq(PACKAGE_NAME),
+ eq(windowAnimations),
+ anyInt(),
+ anyBoolean()
+ )
+ )
+ .thenReturn(mockCloseAnimation)
+ whenever(transitionAnimation.loadDefaultAnimationAttr(anyInt(), anyBoolean()))
+ .thenReturn(mockOpenAnimation)
+ val result = customAnimationLoader.loadAll(info)!!
+ if (exitResId != 0) {
+ if (enterResId == 0) {
+ verify(transitionAnimation, never())
+ .loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(enterResId))
+ verify(transitionAnimation).loadDefaultAnimationAttr(anyInt(), anyBoolean())
+ } else {
+ assertEquals(result.enterAnimation, mockOpenAnimation)
+ }
+ assertEquals(result.backgroundColor.toLong(), Color.GREEN.toLong())
+ assertEquals(result.closeAnimation, mockCloseAnimation)
+ verify(transitionAnimation, never())
+ .loadAnimationAttr(eq(PACKAGE_NAME), anyInt(), anyInt(), anyBoolean())
+ } else if (windowAnimations != 0) {
+ verify(transitionAnimation, times(2))
+ .loadAnimationAttr(eq(PACKAGE_NAME), anyInt(), anyInt(), anyBoolean())
+ Assert.assertEquals(result.closeAnimation, mockCloseAnimation)
+ }
+ }
+
+ private fun startCustomAnimation(
+ targets: Array<RemoteAnimationTarget> =
+ arrayOf(createAnimationTarget(false), createAnimationTarget(true))
+ ): CountDownLatch {
+ val backNavigationInfo =
+ BackNavigationInfo.Builder()
+ .setCustomAnimation(PACKAGE_NAME, OPEN_RES_ID, CLOSE_RES_ID, /*backgroundColor*/ 0)
+ .build()
+ customCrossActivityBackAnimation.prepareNextAnimation(
+ backNavigationInfo.customAnimationInfo,
+ 0
+ )
+ val finishCalled = CountDownLatch(1)
+ val finishCallback = Runnable { finishCalled.countDown() }
+ customCrossActivityBackAnimation
+ .getRunner()
+ .startAnimation(targets, null, null, finishCallback)
+ customCrossActivityBackAnimation.runner.callback.onBackStarted(backMotionEventFrom(0f, 0f))
+ if (targets.isNotEmpty()) {
+ verify(mockCloseAnimation)
+ .initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE))
+ verify(mockOpenAnimation)
+ .initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE))
+ }
+ return finishCalled
+ }
+
+ private fun backMotionEventFrom(touchX: Float, progress: Float) =
+ BackMotionEvent(
+ /* touchX = */ touchX,
+ /* touchY = */ 0f,
+ /* progress = */ progress,
+ /* velocityX = */ 0f,
+ /* velocityY = */ 0f,
+ /* triggerBack = */ false,
+ /* swipeEdge = */ BackEvent.EDGE_LEFT,
+ /* departingAnimationTarget = */ null
+ )
+
+ private fun createAnimationTarget(open: Boolean): RemoteAnimationTarget {
+ val topWindowLeash = SurfaceControl()
+ val taskInfo = RunningTaskInfo()
+ taskInfo.appCompatTaskInfo = appCompatTaskInfo
+ taskInfo.taskDescription = ActivityManager.TaskDescription()
+ return RemoteAnimationTarget(
+ 1,
+ if (open) RemoteAnimationTarget.MODE_OPENING else RemoteAnimationTarget.MODE_CLOSING,
+ topWindowLeash,
+ false,
+ Rect(),
+ Rect(),
+ -1,
+ Point(0, 0),
+ Rect(0, 0, BOUND_SIZE, BOUND_SIZE),
+ Rect(),
+ WindowConfiguration(),
+ true,
+ null,
+ null,
+ taskInfo,
+ false,
+ -1
+ )
+ }
+
+ companion object {
+ private const val BOUND_SIZE = 100
+ private const val OPEN_RES_ID = 1000
+ private const val CLOSE_RES_ID = 1001
+ private const val PACKAGE_NAME = "TestPackage"
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java
deleted file mode 100644
index 158d640dca30..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.back;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.app.WindowConfiguration;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.Choreographer;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.animation.Animation;
-import android.window.BackNavigationInfo;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@SmallTest
-@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner.class)
-public class CustomizeActivityAnimationTest extends ShellTestCase {
- private static final int BOUND_SIZE = 100;
- @Mock
- private BackAnimationBackground mBackAnimationBackground;
- @Mock
- private Animation mMockCloseAnimation;
- @Mock
- private Animation mMockOpenAnimation;
-
- private CustomizeActivityAnimation mCustomizeActivityAnimation;
-
- @Before
- public void setUp() throws Exception {
- mCustomizeActivityAnimation = new CustomizeActivityAnimation(mContext,
- mBackAnimationBackground, mock(SurfaceControl.Transaction.class),
- mock(Choreographer.class));
- spyOn(mCustomizeActivityAnimation);
- spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation);
- }
-
- RemoteAnimationTarget createAnimationTarget(boolean open) {
- SurfaceControl topWindowLeash = new SurfaceControl();
- return new RemoteAnimationTarget(1,
- open ? RemoteAnimationTarget.MODE_OPENING : RemoteAnimationTarget.MODE_CLOSING,
- topWindowLeash, false, new Rect(), new Rect(), -1,
- new Point(0, 0), new Rect(0, 0, BOUND_SIZE, BOUND_SIZE), new Rect(),
- new WindowConfiguration(), true, null, null, null, false, -1);
- }
-
- @Test
- public void receiveFinishAfterInvoke() throws InterruptedException {
- spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader);
- doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader)
- .loadAnimation(any(), eq(false));
- doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader)
- .loadAnimation(any(), eq(true));
-
- mCustomizeActivityAnimation.prepareNextAnimation(
- new BackNavigationInfo.CustomAnimationInfo("TestPackage"), 0);
- final RemoteAnimationTarget close = createAnimationTarget(false);
- final RemoteAnimationTarget open = createAnimationTarget(true);
- // start animation with remote animation targets
- final CountDownLatch finishCalled = new CountDownLatch(1);
- final Runnable finishCallback = finishCalled::countDown;
- mCustomizeActivityAnimation
- .getRunner()
- .startAnimation(
- new RemoteAnimationTarget[] {close, open}, null, null, finishCallback);
- verify(mMockCloseAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE),
- eq(BOUND_SIZE), eq(BOUND_SIZE));
- verify(mMockOpenAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE),
- eq(BOUND_SIZE), eq(BOUND_SIZE));
-
- try {
- mCustomizeActivityAnimation.getRunner().getCallback().onBackInvoked();
- } catch (RemoteException r) {
- fail("onBackInvoked throw remote exception");
- }
- verify(mCustomizeActivityAnimation).onGestureCommitted();
- finishCalled.await(1, TimeUnit.SECONDS);
- }
-
- @Test
- public void receiveFinishAfterCancel() throws InterruptedException {
- spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader);
- doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader)
- .loadAnimation(any(), eq(false));
- doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader)
- .loadAnimation(any(), eq(true));
-
- mCustomizeActivityAnimation.prepareNextAnimation(
- new BackNavigationInfo.CustomAnimationInfo("TestPackage"), 0);
- final RemoteAnimationTarget close = createAnimationTarget(false);
- final RemoteAnimationTarget open = createAnimationTarget(true);
- // start animation with remote animation targets
- final CountDownLatch finishCalled = new CountDownLatch(1);
- final Runnable finishCallback = finishCalled::countDown;
- mCustomizeActivityAnimation
- .getRunner()
- .startAnimation(
- new RemoteAnimationTarget[] {close, open}, null, null, finishCallback);
- verify(mMockCloseAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE),
- eq(BOUND_SIZE), eq(BOUND_SIZE));
- verify(mMockOpenAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE),
- eq(BOUND_SIZE), eq(BOUND_SIZE));
-
- try {
- mCustomizeActivityAnimation.getRunner().getCallback().onBackCancelled();
- } catch (RemoteException r) {
- fail("onBackCancelled throw remote exception");
- }
- finishCalled.await(1, TimeUnit.SECONDS);
- }
-
- @Test
- public void receiveFinishWithoutAnimationAfterInvoke() throws InterruptedException {
- mCustomizeActivityAnimation.prepareNextAnimation(
- new BackNavigationInfo.CustomAnimationInfo("TestPackage"), 0);
- // start animation without any remote animation targets
- final CountDownLatch finishCalled = new CountDownLatch(1);
- final Runnable finishCallback = finishCalled::countDown;
- mCustomizeActivityAnimation
- .getRunner()
- .startAnimation(new RemoteAnimationTarget[] {}, null, null, finishCallback);
-
- try {
- mCustomizeActivityAnimation.getRunner().getCallback().onBackInvoked();
- } catch (RemoteException r) {
- fail("onBackInvoked throw remote exception");
- }
- verify(mCustomizeActivityAnimation).onGestureCommitted();
- finishCalled.await(1, TimeUnit.SECONDS);
- }
-
- @Test
- public void testLoadCustomAnimation() {
- testLoadCustomAnimation(10, 20, 0);
- }
-
- @Test
- public void testLoadCustomAnimationNoEnter() {
- testLoadCustomAnimation(0, 10, 0);
- }
-
- @Test
- public void testLoadWindowAnimations() {
- testLoadCustomAnimation(0, 0, 30);
- }
-
- @Test
- public void testCustomAnimationHigherThanWindowAnimations() {
- testLoadCustomAnimation(10, 20, 30);
- }
-
- private void testLoadCustomAnimation(int enterResId, int exitResId, int windowAnimations) {
- final String testPackage = "TestPackage";
- BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder()
- .setCustomAnimation(testPackage, enterResId, exitResId, Color.GREEN)
- .setWindowAnimations(testPackage, windowAnimations);
- final BackNavigationInfo.CustomAnimationInfo info = builder.build()
- .getCustomAnimationInfo();
-
- doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader
- .mTransitionAnimation)
- .loadAppTransitionAnimation(eq(testPackage), eq(enterResId));
- doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader
- .mTransitionAnimation)
- .loadAppTransitionAnimation(eq(testPackage), eq(exitResId));
- doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader
- .mTransitionAnimation)
- .loadAnimationAttr(eq(testPackage), eq(windowAnimations), anyInt(), anyBoolean());
- doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader
- .mTransitionAnimation).loadDefaultAnimationAttr(anyInt(), anyBoolean());
-
- CustomizeActivityAnimation.AnimationLoadResult result =
- mCustomizeActivityAnimation.mCustomAnimationLoader.loadAll(info);
-
- if (exitResId != 0) {
- if (enterResId == 0) {
- verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation,
- never()).loadAppTransitionAnimation(eq(testPackage), eq(enterResId));
- verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation)
- .loadDefaultAnimationAttr(anyInt(), anyBoolean());
- } else {
- assertEquals(result.mEnterAnimation, mMockOpenAnimation);
- }
- assertEquals(result.mBackgroundColor, Color.GREEN);
- assertEquals(result.mCloseAnimation, mMockCloseAnimation);
- verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation, never())
- .loadAnimationAttr(eq(testPackage), anyInt(), anyInt(), anyBoolean());
- } else if (windowAnimations != 0) {
- verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation,
- times(2)).loadAnimationAttr(eq(testPackage), anyInt(), anyInt(), anyBoolean());
- assertEquals(result.mCloseAnimation, mMockCloseAnimation);
- }
- }
-}
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 5cf5a1d00815..f1ee3256dbee 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -467,10 +467,10 @@ void MouseCursorController::startAnimationLocked() REQUIRES(mLock) {
std::function<bool(nsecs_t)> func = std::bind(&MouseCursorController::doAnimations, this, _1);
/*
- * Using ui::ADISPLAY_ID_NONE for displayId here to avoid removing the callback
+ * Using ui::LogicalDisplayId::INVALID for displayId here to avoid removing the callback
* if a TouchSpotController with the same display is removed.
*/
- mContext.addAnimationCallback(ui::ADISPLAY_ID_NONE, func);
+ mContext.addAnimationCallback(ui::LogicalDisplayId::INVALID, func);
}
} // namespace android
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 70e5c2455d81..c6430f7f36ff 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -109,7 +109,7 @@ private:
struct Locked {
Presentation presentation;
- ui::LogicalDisplayId pointerDisplayId = ui::ADISPLAY_ID_NONE;
+ ui::LogicalDisplayId pointerDisplayId = ui::LogicalDisplayId::INVALID;
std::vector<gui::DisplayInfo> mDisplayInfos;
std::unordered_map<ui::LogicalDisplayId, TouchSpotController> spotControllers;
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 070c90c372ff..e147c567ae2d 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -174,7 +174,7 @@ private:
int32_t layer{0};
float alpha{1.0f};
SpriteTransformationMatrix transformationMatrix;
- ui::LogicalDisplayId displayId{ui::ADISPLAY_ID_DEFAULT};
+ ui::LogicalDisplayId displayId{ui::LogicalDisplayId::DEFAULT};
sp<SurfaceControl> surfaceControl;
int32_t surfaceWidth{0};
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index 7a133801f514..2dcb1f1d1650 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -166,7 +166,7 @@ protected:
PointerControllerTest();
~PointerControllerTest();
- void ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_DEFAULT);
+ void ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT);
sp<MockSprite> mPointerSprite;
sp<MockPointerControllerPolicyInterface> mPolicy;
@@ -335,23 +335,23 @@ TEST_F(PointerControllerTest, updatesSkipScreenshotFlagForTouchSpots) {
// Update spots to sync state with sprite
mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
- ui::ADISPLAY_ID_DEFAULT);
+ ui::LogicalDisplayId::DEFAULT);
testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
// Marking the display to skip screenshot should update sprite as well
- mPointerController->setSkipScreenshot(ui::ADISPLAY_ID_DEFAULT, true);
+ mPointerController->setSkipScreenshot(ui::LogicalDisplayId::DEFAULT, true);
EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(true));
// Update spots to sync state with sprite
mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
- ui::ADISPLAY_ID_DEFAULT);
+ ui::LogicalDisplayId::DEFAULT);
testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
// Reset flag and verify again
- mPointerController->setSkipScreenshot(ui::ADISPLAY_ID_DEFAULT, false);
+ mPointerController->setSkipScreenshot(ui::LogicalDisplayId::DEFAULT, false);
EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(false));
mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
- ui::ADISPLAY_ID_DEFAULT);
+ ui::LogicalDisplayId::DEFAULT);
testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
}
diff --git a/packages/PrintSpooler/res/values-night/themes.xml b/packages/PrintSpooler/res/values-night/themes.xml
index 3cc64a6ef266..76fa7b921e77 100644
--- a/packages/PrintSpooler/res/values-night/themes.xml
+++ b/packages/PrintSpooler/res/values-night/themes.xml
@@ -24,6 +24,7 @@
<style name="Theme.SelectPrinterActivity"
parent="android:style/Theme.DeviceDefault">
<item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item>
+ <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
</style>
<style name="Theme.PrintActivity" parent="@android:style/Theme.DeviceDefault">
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index bd9602540878..22842f724036 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -24,6 +24,7 @@
parent="android:style/Theme.DeviceDefault.Light">
<item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item>
<item name="android:windowLightStatusBar">true</item>
+ <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
</style>
<style name="Theme.PrintActivity" parent="@android:style/Theme.DeviceDefault.Light">
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index 05507e0ea11d..493818b2e74f 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -80,14 +80,15 @@ public class FooterPreference extends Preference {
continue;
}
final URLSpan urlSpan = (URLSpan) clickable;
- if (!urlSpan.getURL().startsWith(INTENT_URL_PREFIX)) {
+ final String url = urlSpan.getURL();
+ if (url == null || !url.startsWith(INTENT_URL_PREFIX)) {
continue;
}
final int start = spannable.getSpanStart(urlSpan);
final int end = spannable.getSpanEnd(urlSpan);
spannable.removeSpan(urlSpan);
try {
- final Intent intent = Intent.parseUri(urlSpan.getURL(), Intent.URI_INTENT_SCHEME);
+ final Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
final ClickableSpan clickableSpan =
new ClickableSpan() {
@Override
@@ -98,7 +99,7 @@ public class FooterPreference extends Preference {
};
spannable.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (URISyntaxException e) {
- Log.e(TAG, "Invalid URI " + urlSpan.getURL(), e);
+ Log.e(TAG, "Invalid URI " + url, e);
}
}
title.setText(spannable);
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 89f54d9b3b3b..9c0d29df420f 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -62,3 +62,10 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "allow_all_widgets_on_lockscreen_by_default"
+ namespace: "systemui"
+ description: "Allow all widgets on the lock screen by default."
+ bug: "328261690"
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index be3f4108fdd1..888e39593a2e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -274,6 +274,9 @@ public class SecureSettings {
Settings.Secure.SCREEN_RESOLUTION_MODE,
Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS,
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
- Settings.Secure.CHARGE_OPTIMIZATION_MODE
+ Settings.Secure.CHARGE_OPTIMIZATION_MODE,
+ Settings.Secure.ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS,
+ Settings.Secure.ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS,
+ Settings.Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index b1feede57506..b992ddc8a397 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -18,6 +18,7 @@ package android.provider.settings.validators;
import static android.provider.settings.validators.SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.ANY_LONG_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.AUTOFILL_SERVICE_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
@@ -433,5 +434,8 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
new InclusiveIntegerRangeValidator(0, 10));
VALIDATORS.put(Secure.CHARGE_OPTIMIZATION_MODE, new InclusiveIntegerRangeValidator(0, 10));
+ VALIDATORS.put(Secure.ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS, ANY_LONG_VALIDATOR);
+ VALIDATORS.put(Secure.ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS, ANY_LONG_VALIDATOR);
+ VALIDATORS.put(Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS, NONE_NEGATIVE_LONG_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 677c81ad9271..255b1ad3b3d2 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -239,6 +239,18 @@ public class SettingsValidators {
}
};
+ static final Validator ANY_LONG_VALIDATOR = value -> {
+ if (value == null) {
+ return true;
+ }
+ try {
+ Long.parseLong(value);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ };
+
static final Validator CREDENTIAL_SERVICE_VALIDATOR = new Validator() {
@Override
public boolean validate(String value) {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 92167ee4d423..ab9a30b65e08 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -233,6 +233,7 @@ public class SettingsBackupTest {
Settings.Global.ENHANCED_4G_MODE_ENABLED,
Settings.Global.ENABLE_16K_PAGES, // Added for 16K developer option
Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
+ Settings.Global.ERROR_KERNEL_LOG_PREFIX,
Settings.Global.ERROR_LOGCAT_PREFIX,
Settings.Global.EUICC_PROVISIONED,
Settings.Global.EUICC_SUPPORTED_COUNTRIES,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index c04ec4f61c89..d2ca11207084 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -78,11 +78,23 @@ filegroup {
visibility: ["//visibility:private"],
}
+filegroup {
+ name: "SystemUI-tests-broken-robofiles-run",
+ srcs: [
+ "tests/src/**/systemui/util/LifecycleFragmentTest.java",
+ "tests/src/**/systemui/util/TestableAlertDialogTest.kt",
+ "tests/src/**/systemui/util/kotlin/PairwiseFlowTest",
+ "tests/src/**/systemui/util/sensors/AsyncManagerTest.java",
+ "tests/src/**/systemui/util/sensors/ThresholdSensorImplTest.java",
+ "tests/src/**/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java",
+ ],
+}
+
// We are running robolectric tests in the tests directory as well as
// multivalent tests. If you add a test, and it doesn't run in robolectric,
// it should be added to this exclusion list. go/multivalent-tests
filegroup {
- name: "SystemUI-tests-broken-robofiles",
+ name: "SystemUI-tests-broken-robofiles-compile",
srcs: [
"tests/src/**/*DeviceOnlyTest.java",
"tests/src/**/*DeviceOnlyTest.kt",
@@ -703,7 +715,8 @@ android_robolectric_test {
":SystemUI-tests-robofiles",
],
exclude_srcs: [
- ":SystemUI-tests-broken-robofiles",
+ ":SystemUI-tests-broken-robofiles-compile",
+ ":SystemUI-tests-broken-robofiles-run",
],
static_libs: [
"RoboTestLibraries",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 0dd956c7a3ae..1f23748397cb 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -34,6 +34,13 @@ flag {
}
flag {
+ name: "priority_people_section"
+ namespace: "systemui"
+ description: "Add a new section for priority people (aka important conversations)."
+ bug: "340294566"
+}
+
+flag {
name: "notification_minimalism_prototype"
namespace: "systemui"
description: "Prototype of notification minimalism; the new 'Intermediate' lockscreen customization proposal."
@@ -470,6 +477,17 @@ flag {
}
flag {
+ name: "fix_screenshot_action_dismiss_system_windows"
+ namespace: "systemui"
+ description: "Dismiss existing system windows when starting action from screenshot UI"
+ bug: "309933761"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+
+flag {
name: "screenshot_private_profile_behavior_fix"
namespace: "systemui"
description: "Private profile support for screenshots"
@@ -844,6 +862,9 @@ flag {
namespace: "systemui"
description: "Enforce BaseUserRestriction for DISALLOW_CONFIG_BRIGHTNESS."
bug: "329205638"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt
new file mode 100644
index 000000000000..94620c4c73b4
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt
@@ -0,0 +1,97 @@
+/*
+ * 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.internal.systemui.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UFile
+import org.jetbrains.uast.UImportStatement
+
+class CollectAsStateDetector : Detector(), SourceCodeScanner {
+
+ override fun getApplicableUastTypes(): List<Class<out UElement>> {
+ return listOf(UFile::class.java)
+ }
+
+ override fun createUastHandler(context: JavaContext): UElementHandler {
+ return object : UElementHandler() {
+ override fun visitFile(node: UFile) {
+ node.imports.forEach { importStatement ->
+ visitImportStatement(context, importStatement)
+ }
+ }
+ }
+ }
+
+ private fun visitImportStatement(
+ context: JavaContext,
+ importStatement: UImportStatement,
+ ) {
+ val importText = importStatement.importReference?.asSourceString() ?: return
+ if (ILLEGAL_IMPORT == importText) {
+ context.report(
+ issue = ISSUE,
+ scope = importStatement,
+ location = context.getLocation(importStatement),
+ message = "collectAsState considered harmful",
+ )
+ }
+ }
+
+ companion object {
+ @JvmField
+ val ISSUE =
+ Issue.create(
+ id = "OverlyEagerCollectAsState",
+ briefDescription = "collectAsState considered harmful",
+ explanation =
+ """
+ go/sysui-compose#collect-as-state
+
+ Don't use collectAsState as it will set up a coroutine that keeps collecting from a
+ flow until its coroutine scope becomes inactive. This prevents the work from being
+ properly paused while the surrounding lifecycle becomes paused or stopped and is
+ therefore considered harmful.
+
+ Instead, use Flow.collectAsStateWithLifecycle(initial: T) or
+ StateFlow.collectAsStateWithLifecycle(). These APIs correctly pause the collection
+ coroutine while the lifecycle drops below the specified minActiveState (which
+ defaults to STARTED meaning that it will pause when the Compose-hosting window
+ becomes invisible).
+ """
+ .trimIndent(),
+ category = Category.PERFORMANCE,
+ priority = 8,
+ severity = Severity.ERROR,
+ implementation =
+ Implementation(
+ CollectAsStateDetector::class.java,
+ Scope.JAVA_FILE_SCOPE,
+ ),
+ )
+
+ private val ILLEGAL_IMPORT = "androidx.compose.runtime.collectAsState"
+ }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index cecbc474a18a..73ac6ccf8f76 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -32,6 +32,7 @@ class SystemUIIssueRegistry : IssueRegistry() {
BindServiceOnMainThreadDetector.ISSUE,
BroadcastSentViaContextDetector.ISSUE,
CleanArchitectureDependencyViolationDetector.ISSUE,
+ CollectAsStateDetector.ISSUE,
DumpableNotRegisteredDetector.ISSUE,
FlowDetector.SHARED_FLOW_CREATION,
SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt
new file mode 100644
index 000000000000..6962b4eb31e6
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class CollectAsStateDetectorTest : SystemUILintDetectorTest() {
+
+ override fun getDetector(): Detector {
+ return CollectAsStateDetector()
+ }
+
+ override fun getIssues(): List<Issue> {
+ return listOf(
+ CollectAsStateDetector.ISSUE,
+ )
+ }
+
+ @Test
+ fun testViolation() {
+ lint()
+ .files(COLLECT_AS_STATE_STUB, COLLECT_WITH_LIFECYCLE_AS_STATE_STUB, GOOD_FILE, BAD_FILE)
+ .issues(CollectAsStateDetector.ISSUE)
+ .run()
+ .expect(
+ """
+src/com/android/internal/systemui/lint/Bad.kt:3: Error: collectAsState considered harmful [OverlyEagerCollectAsState]
+import androidx.compose.runtime.collectAsState
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+1 errors, 0 warnings
+ """
+ .trimIndent()
+ )
+ }
+
+ @Test
+ fun testNoViolation() {
+ lint()
+ .files(COLLECT_AS_STATE_STUB, COLLECT_WITH_LIFECYCLE_AS_STATE_STUB, GOOD_FILE)
+ .issues(CollectAsStateDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ companion object {
+ private val COLLECT_AS_STATE_STUB =
+ TestFiles.kotlin(
+ """
+ package androidx.compose.runtime
+
+ fun collectAsState() {}
+ """
+ .trimIndent()
+ )
+ private val COLLECT_WITH_LIFECYCLE_AS_STATE_STUB =
+ TestFiles.kotlin(
+ """
+ package androidx.lifecycle.compose
+
+ fun collectAsStateWithLifecycle() {}
+ """
+ .trimIndent()
+ )
+
+ private val BAD_FILE =
+ TestFiles.kotlin(
+ """
+ package com.android.internal.systemui.lint
+
+ import androidx.compose.runtime.collectAsState
+
+ class Bad
+ """
+ .trimIndent()
+ )
+
+ private val GOOD_FILE =
+ TestFiles.kotlin(
+ """
+ package com.android.internal.systemui.lint
+
+ import androidx.lifecycle.compose.collectAsStateWithLifecycle
+
+ class Good
+ """
+ .trimIndent()
+ )
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index c22b50d9dd64..fa01a4bf46c5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -56,7 +56,6 @@ import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -77,6 +76,7 @@ import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.times
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformButton
import com.android.compose.animation.Easings
import com.android.compose.animation.scene.ElementKey
@@ -111,7 +111,7 @@ fun BouncerContent(
dialogFactory: BouncerDialogFactory,
modifier: Modifier = Modifier,
) {
- val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsState()
+ val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsStateWithLifecycle()
val layout = calculateLayout(isSideBySideSupported = isSideBySideSupported)
Box(
@@ -220,7 +220,7 @@ private fun SplitLayout(
viewModel: BouncerViewModel,
modifier: Modifier = Modifier,
) {
- val authMethod by viewModel.authMethodViewModel.collectAsState()
+ val authMethod by viewModel.authMethodViewModel.collectAsStateWithLifecycle()
Row(
modifier =
@@ -316,7 +316,7 @@ private fun BesideUserSwitcherLayout(
val (isSwapped, setSwapped) = rememberSaveable(isLeftToRight) { mutableStateOf(!isLeftToRight) }
val isHeightExpanded =
LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Expanded
- val authMethod by viewModel.authMethodViewModel.collectAsState()
+ val authMethod by viewModel.authMethodViewModel.collectAsStateWithLifecycle()
Row(
modifier =
@@ -480,7 +480,7 @@ private fun FoldAware(
modifier: Modifier = Modifier,
) {
val foldPosture: FoldPosture by foldPosture()
- val isSplitAroundTheFoldRequired by viewModel.isFoldSplitRequired.collectAsState()
+ val isSplitAroundTheFoldRequired by viewModel.isFoldSplitRequired.collectAsStateWithLifecycle()
val isSplitAroundTheFold = foldPosture == FoldPosture.Tabletop && isSplitAroundTheFoldRequired
val currentSceneKey =
if (isSplitAroundTheFold) SceneKeys.SplitSceneKey else SceneKeys.ContiguousSceneKey
@@ -562,7 +562,7 @@ private fun StatusMessage(
viewModel: BouncerMessageViewModel,
modifier: Modifier = Modifier,
) {
- val message: MessageViewModel? by viewModel.message.collectAsState()
+ val message: MessageViewModel? by viewModel.message.collectAsStateWithLifecycle()
DisposableEffect(Unit) {
viewModel.onShown()
@@ -612,7 +612,7 @@ private fun OutputArea(
modifier: Modifier = Modifier,
) {
val authMethodViewModel: AuthMethodBouncerViewModel? by
- viewModel.authMethodViewModel.collectAsState()
+ viewModel.authMethodViewModel.collectAsStateWithLifecycle()
when (val nonNullViewModel = authMethodViewModel) {
is PinBouncerViewModel ->
@@ -642,7 +642,7 @@ private fun InputArea(
modifier: Modifier = Modifier,
) {
val authMethodViewModel: AuthMethodBouncerViewModel? by
- viewModel.authMethodViewModel.collectAsState()
+ viewModel.authMethodViewModel.collectAsStateWithLifecycle()
when (val nonNullViewModel = authMethodViewModel) {
is PinBouncerViewModel -> {
@@ -668,7 +668,8 @@ private fun ActionArea(
viewModel: BouncerViewModel,
modifier: Modifier = Modifier,
) {
- val actionButton: BouncerActionButtonModel? by viewModel.actionButton.collectAsState()
+ val actionButton: BouncerActionButtonModel? by
+ viewModel.actionButton.collectAsStateWithLifecycle()
val appearFadeInAnimatable = remember { Animatable(0f) }
val appearMoveAnimatable = remember { Animatable(0f) }
val appearAnimationInitialOffset = with(LocalDensity.current) { 80.dp.toPx() }
@@ -735,7 +736,7 @@ private fun Dialog(
bouncerViewModel: BouncerViewModel,
dialogFactory: BouncerDialogFactory,
) {
- val dialogViewModel by bouncerViewModel.dialogViewModel.collectAsState()
+ val dialogViewModel by bouncerViewModel.dialogViewModel.collectAsStateWithLifecycle()
var dialog: AlertDialog? by remember { mutableStateOf(null) }
dialogViewModel?.let { viewModel ->
@@ -772,8 +773,8 @@ private fun UserSwitcher(
return
}
- val selectedUserImage by viewModel.selectedUserImage.collectAsState(null)
- val dropdownItems by viewModel.userSwitcherDropdown.collectAsState(emptyList())
+ val selectedUserImage by viewModel.selectedUserImage.collectAsStateWithLifecycle(null)
+ val dropdownItems by viewModel.userSwitcherDropdown.collectAsStateWithLifecycle(emptyList())
Column(
horizontalAlignment = Alignment.CenterHorizontally,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
index 2dcd0ff05c73..203bd7a69a7a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
@@ -27,7 +27,6 @@ import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
@@ -49,6 +48,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformIconButton
import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
import com.android.systemui.common.ui.compose.SelectedUserAwareInputConnection
@@ -62,18 +62,20 @@ internal fun PasswordBouncer(
modifier: Modifier = Modifier,
) {
val focusRequester = remember { FocusRequester() }
- val isTextFieldFocusRequested by viewModel.isTextFieldFocusRequested.collectAsState()
+ val isTextFieldFocusRequested by
+ viewModel.isTextFieldFocusRequested.collectAsStateWithLifecycle()
LaunchedEffect(isTextFieldFocusRequested) {
if (isTextFieldFocusRequested) {
focusRequester.requestFocus()
}
}
- val password: String by viewModel.password.collectAsState()
- val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
- val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
- val isImeSwitcherButtonVisible by viewModel.isImeSwitcherButtonVisible.collectAsState()
- val selectedUserId by viewModel.selectedUserId.collectAsState()
+ val password: String by viewModel.password.collectAsStateWithLifecycle()
+ val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsStateWithLifecycle()
+ val animateFailure: Boolean by viewModel.animateFailure.collectAsStateWithLifecycle()
+ val isImeSwitcherButtonVisible by
+ viewModel.isImeSwitcherButtonVisible.collectAsStateWithLifecycle()
+ val selectedUserId by viewModel.selectedUserId.collectAsStateWithLifecycle()
DisposableEffect(Unit) { onDispose { viewModel.onHidden() } }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
index d7e9c10e7224..9c2fd64052b4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
@@ -30,7 +30,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -47,6 +46,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.integerResource
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.Easings
import com.android.compose.modifiers.thenIf
import com.android.internal.R
@@ -86,14 +86,15 @@ internal fun PatternBouncer(
val lineStrokeWidth = with(density) { LINE_STROKE_WIDTH_DP.dp.toPx() }
// All dots that should be rendered on the grid.
- val dots: List<PatternDotViewModel> by viewModel.dots.collectAsState()
+ val dots: List<PatternDotViewModel> by viewModel.dots.collectAsStateWithLifecycle()
// The most recently selected dot, if the user is currently dragging.
- val currentDot: PatternDotViewModel? by viewModel.currentDot.collectAsState()
+ val currentDot: PatternDotViewModel? by viewModel.currentDot.collectAsStateWithLifecycle()
// The dots selected so far, if the user is currently dragging.
- val selectedDots: List<PatternDotViewModel> by viewModel.selectedDots.collectAsState()
- val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
- val isAnimationEnabled: Boolean by viewModel.isPatternVisible.collectAsState()
- val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
+ val selectedDots: List<PatternDotViewModel> by
+ viewModel.selectedDots.collectAsStateWithLifecycle()
+ val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsStateWithLifecycle()
+ val isAnimationEnabled: Boolean by viewModel.isPatternVisible.collectAsStateWithLifecycle()
+ val animateFailure: Boolean by viewModel.animateFailure.collectAsStateWithLifecycle()
// Map of animatables for the scale of each dot, keyed by dot.
val dotScalingAnimatables = remember(dots) { dots.associateWith { Animatable(1f) } }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index 5651a4646b2d..64ace2f18372 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -33,7 +33,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -49,6 +48,7 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.Easings
import com.android.compose.grid.VerticalGrid
import com.android.compose.modifiers.thenIf
@@ -74,12 +74,13 @@ fun PinPad(
) {
DisposableEffect(Unit) { onDispose { viewModel.onHidden() } }
- val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
- val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState()
- val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState()
- val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
+ val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsStateWithLifecycle()
+ val backspaceButtonAppearance by
+ viewModel.backspaceButtonAppearance.collectAsStateWithLifecycle()
+ val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsStateWithLifecycle()
+ val animateFailure: Boolean by viewModel.animateFailure.collectAsStateWithLifecycle()
val isDigitButtonAnimationEnabled: Boolean by
- viewModel.isDigitButtonAnimationEnabled.collectAsState()
+ viewModel.isDigitButtonAnimationEnabled.collectAsStateWithLifecycle()
val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } }
LaunchedEffect(animateFailure) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
index 1a97912c77bb..465eade4e169 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
@@ -42,7 +42,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateListOf
@@ -65,6 +64,7 @@ import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformOutlinedButton
import com.android.compose.animation.Easings
import com.android.keyguard.PinShapeAdapter
@@ -86,7 +86,7 @@ fun PinInputDisplay(
viewModel: PinBouncerViewModel,
modifier: Modifier = Modifier,
) {
- val hintedPinLength: Int? by viewModel.hintedPinLength.collectAsState()
+ val hintedPinLength: Int? by viewModel.hintedPinLength.collectAsStateWithLifecycle()
val shapeAnimations = rememberShapeAnimations(viewModel.pinShapes)
// The display comes in two different flavors:
@@ -119,7 +119,7 @@ private fun HintingPinInputDisplay(
hintedPinLength: Int,
modifier: Modifier = Modifier,
) {
- val pinInput: PinInputViewModel by viewModel.pinInput.collectAsState()
+ val pinInput: PinInputViewModel by viewModel.pinInput.collectAsStateWithLifecycle()
// [ClearAll] marker pointing at the beginning of the current pin input.
// When a new [ClearAll] token is added to the [pinInput], the clear-all animation is played
// and the marker is advanced manually to the most recent marker. See LaunchedEffect below.
@@ -257,9 +257,10 @@ private fun RegularPinInputDisplay(
@Composable
private fun SimArea(viewModel: PinBouncerViewModel) {
- val isLockedEsim by viewModel.isLockedEsim.collectAsState()
- val isSimUnlockingDialogVisible by viewModel.isSimUnlockingDialogVisible.collectAsState()
- val errorDialogMessage by viewModel.errorDialogMessage.collectAsState()
+ val isLockedEsim by viewModel.isLockedEsim.collectAsStateWithLifecycle()
+ val isSimUnlockingDialogVisible by
+ viewModel.isSimUnlockingDialogVisible.collectAsStateWithLifecycle()
+ val errorDialogMessage by viewModel.errorDialogMessage.collectAsStateWithLifecycle()
var unlockDialog: Dialog? by remember { mutableStateOf(null) }
var errorDialog: Dialog? by remember { mutableStateOf(null) }
val context = LocalView.current.context
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt
index c8e145034551..694326d0549c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt
@@ -35,7 +35,7 @@ import androidx.compose.ui.platform.PlatformTextInputMethodRequest
* ```
* @Composable
* fun YourFunction(viewModel: YourViewModel) {
- * val selectedUserId by viewModel.selectedUserId.collectAsState()
+ * val selectedUserId by viewModel.selectedUserId.collectAsStateWithLifecycle()
*
* SelectedUserAwareInputConnection(selectedUserId) {
* TextField(...)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt
index 8144d15020fa..296fc27ac0ff 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt
@@ -22,12 +22,12 @@ import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.systemBars
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.flow.StateFlow
/** The bounds and [CutoutLocation] of the current display. */
@@ -45,7 +45,7 @@ fun ScreenDecorProvider(
screenCornerRadius: Float,
content: @Composable () -> Unit,
) {
- val cutout by displayCutout.collectAsState()
+ val cutout by displayCutout.collectAsStateWithLifecycle()
val screenCornerRadiusDp = with(LocalDensity.current) { screenCornerRadius.toDp() }
val density = LocalDensity.current
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 08e452cd0bd1..8ee8ea4b4f4c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -6,13 +6,13 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.dimensionResource
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.ElementMatcher
@@ -85,8 +85,9 @@ fun CommunalContainer(
content: CommunalContent,
) {
val coroutineScope = rememberCoroutineScope()
- val currentSceneKey: SceneKey by viewModel.currentScene.collectAsState(CommunalScenes.Blank)
- val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false)
+ val currentSceneKey: SceneKey by
+ viewModel.currentScene.collectAsStateWithLifecycle(CommunalScenes.Blank)
+ val touchesAllowed by viewModel.touchesAllowed.collectAsStateWithLifecycle(initialValue = false)
val state: MutableSceneTransitionLayoutState = remember {
MutableSceneTransitionLayoutState(
initialScene = currentSceneKey,
@@ -149,7 +150,8 @@ private fun SceneScope.CommunalScene(
content: CommunalContent,
modifier: Modifier = Modifier,
) {
- val backgroundColor by colors.backgroundColor.collectAsState()
+ val backgroundColor by colors.backgroundColor.collectAsStateWithLifecycle()
+
Box(
modifier =
Modifier.element(Communal.Elements.Scrim)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 02621f6c84f8..2a52c60c820e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -78,7 +78,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -124,6 +123,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.window.Popup
import androidx.core.view.setPadding
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.layout.WindowMetricsCalculator
import com.android.compose.modifiers.thenIf
import com.android.compose.theme.LocalAndroidColorScheme
@@ -156,20 +156,21 @@ fun CommunalHub(
onOpenWidgetPicker: (() -> Unit)? = null,
onEditDone: (() -> Unit)? = null,
) {
- val communalContent by viewModel.communalContent.collectAsState(initial = emptyList())
- val currentPopup by viewModel.currentPopup.collectAsState(initial = null)
+ val communalContent by
+ viewModel.communalContent.collectAsStateWithLifecycle(initialValue = emptyList())
+ val currentPopup by viewModel.currentPopup.collectAsStateWithLifecycle(initialValue = null)
var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
var toolbarSize: IntSize? by remember { mutableStateOf(null) }
var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
var isDraggingToRemove by remember { mutableStateOf(false) }
val gridState = rememberLazyGridState()
val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel)
- val reorderingWidgets by viewModel.reorderingWidgets.collectAsState()
- val selectedKey = viewModel.selectedKey.collectAsState()
+ val reorderingWidgets by viewModel.reorderingWidgets.collectAsStateWithLifecycle()
+ val selectedKey = viewModel.selectedKey.collectAsStateWithLifecycle()
val removeButtonEnabled by remember {
derivedStateOf { selectedKey.value != null || reorderingWidgets }
}
- val isEmptyState by viewModel.isEmptyState.collectAsState(initial = false)
+ val isEmptyState by viewModel.isEmptyState.collectAsStateWithLifecycle(initialValue = false)
val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
val contentOffset = beforeContentPadding(contentPadding).toOffset()
@@ -303,9 +304,9 @@ fun CommunalHub(
if (viewModel is CommunalViewModel && dialogFactory != null) {
val isEnableWidgetDialogShowing by
- viewModel.isEnableWidgetDialogShowing.collectAsState(false)
+ viewModel.isEnableWidgetDialogShowing.collectAsStateWithLifecycle(false)
val isEnableWorkProfileDialogShowing by
- viewModel.isEnableWorkProfileDialogShowing.collectAsState(false)
+ viewModel.isEnableWorkProfileDialogShowing.collectAsStateWithLifecycle(false)
EnableWidgetDialog(
isEnableWidgetDialogVisible = isEnableWidgetDialogShowing,
@@ -860,7 +861,7 @@ private fun WidgetContent(
contentListState: ContentListState,
) {
val context = LocalContext.current
- val isFocusable by viewModel.isFocusable.collectAsState(initial = false)
+ val isFocusable by viewModel.isFocusable.collectAsStateWithLifecycle(initialValue = false)
val accessibilityLabel =
remember(model, context) {
model.providerInfo.loadLabel(context.packageManager).toString().trim()
@@ -868,7 +869,7 @@ private fun WidgetContent(
val clickActionLabel = stringResource(R.string.accessibility_action_label_select_widget)
val removeWidgetActionLabel = stringResource(R.string.accessibility_action_label_remove_widget)
val placeWidgetActionLabel = stringResource(R.string.accessibility_action_label_place_widget)
- val selectedKey by viewModel.selectedKey.collectAsState()
+ val selectedKey by viewModel.selectedKey.collectAsStateWithLifecycle()
val selectedIndex =
selectedKey?.let { key -> contentListState.list.indexOfFirst { it.key == key } }
Box(
@@ -1109,7 +1110,7 @@ private fun Umo(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier)
@Composable
fun AccessibilityContainer(viewModel: BaseCommunalViewModel, content: @Composable () -> Unit) {
val context = LocalContext.current
- val isFocusable by viewModel.isFocusable.collectAsState(initial = false)
+ val isFocusable by viewModel.isFocusable.collectAsStateWithLifecycle(initialValue = false)
Box(
modifier =
Modifier.fillMaxWidth().wrapContentHeight().thenIf(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt b/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt
index e77ade91a93b..17dac7e2e6d5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt
@@ -18,11 +18,11 @@ package com.android.systemui.fold.ui.composable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.layout.WindowInfoTracker
import com.android.systemui.fold.ui.helper.FoldPosture
import com.android.systemui.fold.ui.helper.foldPostureInternal
@@ -32,7 +32,8 @@ import com.android.systemui.fold.ui.helper.foldPostureInternal
fun foldPosture(): State<FoldPosture> {
val context = LocalContext.current
val infoTracker = remember(context) { WindowInfoTracker.getOrCreate(context) }
- val layoutInfo by infoTracker.windowLayoutInfo(context).collectAsState(initial = null)
+ val layoutInfo by
+ infoTracker.windowLayoutInfo(context).collectAsStateWithLifecycle(initialValue = null)
return produceState<FoldPosture>(
initialValue = FoldPosture.Folded,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
index a8d801abdcd0..67840c7fc696 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
@@ -29,7 +29,6 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
@@ -37,6 +36,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.theme.PlatformTheme
import com.android.systemui.keyboard.stickykeys.shared.model.Locked
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey
@@ -57,7 +57,7 @@ fun createStickyKeyIndicatorView(context: Context, viewModel: StickyKeysIndicato
@Composable
fun StickyKeysIndicator(viewModel: StickyKeysIndicatorViewModel) {
- val stickyKeys by viewModel.indicatorContent.collectAsState(emptyMap())
+ val stickyKeys by viewModel.indicatorContent.collectAsStateWithLifecycle(emptyMap())
StickyKeysIndicator(stickyKeys)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index 4bef9efe79d1..6d8c47d84850 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -18,11 +18,11 @@ package com.android.systemui.keyguard.ui.composable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
@@ -51,7 +51,7 @@ constructor(
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
- val blueprintId by viewModel.blueprintId(coroutineScope).collectAsState()
+ val blueprintId by viewModel.blueprintId(coroutineScope).collectAsStateWithLifecycle()
val view = LocalView.current
DisposableEffect(view) {
clockInteractor.clockEventController.registerListeners(view)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt
index 472484aa74d9..4555f13a1a2c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt
@@ -26,13 +26,13 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
/** Container for lockscreen content that handles long-press to bring up the settings menu. */
@@ -42,7 +42,8 @@ fun LockscreenLongPress(
modifier: Modifier = Modifier,
content: @Composable BoxScope.(onSettingsMenuPlaces: (coordinates: Rect?) -> Unit) -> Unit,
) {
- val isEnabled: Boolean by viewModel.isLongPressHandlingEnabled.collectAsState(initial = false)
+ val isEnabled: Boolean by
+ viewModel.isLongPressHandlingEnabled.collectAsStateWithLifecycle(initialValue = false)
val (settingsMenuBounds, setSettingsMenuBounds) = remember { mutableStateOf<Rect?>(null) }
val interactionSource = remember { MutableInteractionSource() }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
index 8129e41b4977..ba25719f1d60 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
@@ -21,11 +21,11 @@ import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.union
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalDensity
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
import com.android.systemui.plugins.clocks.ClockController
@@ -37,7 +37,7 @@ import kotlin.math.roundToInt
fun rememberBurnIn(
clockInteractor: KeyguardClockInteractor,
): BurnInState {
- val clock by clockInteractor.currentClock.collectAsState()
+ val clock by clockInteractor.currentClock.collectAsStateWithLifecycle()
val (smartspaceTop, onSmartspaceTopChanged) = remember { mutableStateOf<Float?>(null) }
val (smallClockTop, onSmallClockTopChanged) = remember { mutableStateOf<Float?>(null) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 315253524b61..abff93d15c55 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -22,13 +22,13 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.unit.IntRect
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
@@ -67,8 +67,8 @@ constructor(
override fun SceneScope.Content(modifier: Modifier) {
val isUdfpsVisible = viewModel.isUdfpsVisible
val shouldUseSplitNotificationShade by
- viewModel.shouldUseSplitNotificationShade.collectAsState()
- val unfoldTranslations by viewModel.unfoldTranslations.collectAsState()
+ viewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle()
+ val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
LockscreenLongPress(
viewModel = viewModel.longPress,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
index 9d31955122eb..c83f62c4281c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
@@ -22,13 +22,13 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.unit.IntRect
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
@@ -70,8 +70,8 @@ constructor(
override fun SceneScope.Content(modifier: Modifier) {
val isUdfpsVisible = viewModel.isUdfpsVisible
val shouldUseSplitNotificationShade by
- viewModel.shouldUseSplitNotificationShade.collectAsState()
- val unfoldTranslations by viewModel.unfoldTranslations.collectAsState()
+ viewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle()
+ val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
LockscreenLongPress(
viewModel = viewModel.longPress,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
index abbf0ea892ec..aaf49ff00aca 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
@@ -17,7 +17,6 @@
package com.android.systemui.keyguard.ui.composable.modifier
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -25,6 +24,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onPlaced
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
import com.android.systemui.keyguard.ui.viewmodel.BurnInScaleViewModel
@@ -44,8 +44,10 @@ fun Modifier.burnInAware(
val translationYState = remember { mutableStateOf(0F) }
val copiedParams = params.copy(translationY = { translationYState.value })
val burnIn = viewModel.movement(copiedParams)
- val translationX by burnIn.map { it.translationX.toFloat() }.collectAsState(initial = 0f)
- val translationY by burnIn.map { it.translationY.toFloat() }.collectAsState(initial = 0f)
+ val translationX by
+ burnIn.map { it.translationX.toFloat() }.collectAsStateWithLifecycle(initialValue = 0f)
+ val translationY by
+ burnIn.map { it.translationY.toFloat() }.collectAsStateWithLifecycle(initialValue = 0f)
translationYState.value = translationY
val scaleViewModel by
burnIn
@@ -55,7 +57,7 @@ fun Modifier.burnInAware(
scaleClockOnly = it.scaleClockOnly,
)
}
- .collectAsState(initial = BurnInScaleViewModel())
+ .collectAsStateWithLifecycle(initialValue = BurnInScaleViewModel())
return this.graphicsLayer {
this.translationX = if (isClock) 0F else translationX
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index 09ec76df3aea..218779da20b9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -25,13 +25,13 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.contains
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.customization.R
@@ -59,9 +59,11 @@ constructor(
onTopChanged: (top: Float?) -> Unit,
modifier: Modifier = Modifier,
) {
- val currentClock by viewModel.currentClock.collectAsState()
+ val currentClock by viewModel.currentClock.collectAsStateWithLifecycle()
val smallTopMargin by
- viewModel.smallClockTopMargin.collectAsState(viewModel.getSmallClockTopMargin())
+ viewModel.smallClockTopMargin.collectAsStateWithLifecycle(
+ viewModel.getSmallClockTopMargin()
+ )
if (currentClock?.smallClock?.view == null) {
return
}
@@ -89,7 +91,7 @@ constructor(
@Composable
fun SceneScope.LargeClock(burnInParams: BurnInParameters, modifier: Modifier = Modifier) {
- val currentClock by viewModel.currentClock.collectAsState()
+ val currentClock by viewModel.currentClock.collectAsStateWithLifecycle()
if (currentClock?.largeClock?.view == null) {
return
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
index c37d626ca8c5..3ca2b9c1d86c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
@@ -18,9 +18,9 @@ package com.android.systemui.keyguard.ui.composable.section
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel
import com.android.systemui.media.controls.ui.composable.MediaCarousel
@@ -40,7 +40,7 @@ constructor(
@Composable
fun SceneScope.KeyguardMediaCarousel() {
- val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsState()
+ val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsStateWithLifecycle()
MediaCarousel(
isVisible = isMediaVisible,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index f48fa88b9722..7f80dfa703bc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -20,13 +20,13 @@ import android.view.ViewGroup
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.thenIf
import com.android.systemui.Flags
@@ -40,16 +40,19 @@ import com.android.systemui.notifications.ui.composable.ConstrainedNotificationS
import com.android.systemui.res.R
import com.android.systemui.shade.LargeScreenHeaderHelper
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
+import dagger.Lazy
import javax.inject.Inject
@SysUISingleton
class NotificationSection
@Inject
constructor(
+ private val stackScrollView: Lazy<NotificationScrollView>,
private val viewModel: NotificationsPlaceholderViewModel,
private val aodBurnInViewModel: AodBurnInViewModel,
sharedNotificationContainer: SharedNotificationContainer,
@@ -88,9 +91,9 @@ constructor(
@Composable
fun SceneScope.Notifications(burnInParams: BurnInParameters?, modifier: Modifier = Modifier) {
val shouldUseSplitNotificationShade by
- lockscreenContentViewModel.shouldUseSplitNotificationShade.collectAsState()
+ lockscreenContentViewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle()
val areNotificationsVisible by
- lockscreenContentViewModel.areNotificationsVisible.collectAsState()
+ lockscreenContentViewModel.areNotificationsVisible.collectAsStateWithLifecycle()
val splitShadeTopMargin: Dp =
if (Flags.centralizedStatusBarHeightFix()) {
LargeScreenHeaderHelper.getLargeScreenHeaderHeight(LocalContext.current).dp
@@ -103,6 +106,7 @@ constructor(
}
ConstrainedNotificationStack(
+ stackScrollView = stackScrollView.get(),
viewModel = viewModel,
modifier =
modifier
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
index fc8b3b9009ce..44bda956b9f6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
@@ -26,7 +26,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -34,6 +33,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
@@ -160,7 +160,7 @@ constructor(
private fun Weather(
modifier: Modifier = Modifier,
) {
- val isVisible by keyguardSmartspaceViewModel.isWeatherVisible.collectAsState()
+ val isVisible by keyguardSmartspaceViewModel.isWeatherVisible.collectAsStateWithLifecycle()
if (!isVisible) {
return
}
@@ -187,7 +187,7 @@ constructor(
private fun Date(
modifier: Modifier = Modifier,
) {
- val isVisible by keyguardSmartspaceViewModel.isDateVisible.collectAsState()
+ val isVisible by keyguardSmartspaceViewModel.isDateVisible.collectAsStateWithLifecycle()
if (!isVisible) {
return
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 63c70c97ed07..88b8298335aa 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
@@ -33,6 +32,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.modifiers.thenIf
@@ -62,9 +62,9 @@ constructor(
fun DefaultClockLayout(
modifier: Modifier = Modifier,
) {
- val currentClockLayout by clockViewModel.currentClockLayout.collectAsState()
+ val currentClockLayout by clockViewModel.currentClockLayout.collectAsStateWithLifecycle()
val hasCustomPositionUpdatedAnimation by
- clockViewModel.hasCustomPositionUpdatedAnimation.collectAsState()
+ clockViewModel.hasCustomPositionUpdatedAnimation.collectAsStateWithLifecycle()
val currentScene =
when (currentClockLayout) {
KeyguardClockViewModel.ClockLayout.SPLIT_SHADE_LARGE_CLOCK ->
@@ -133,7 +133,7 @@ constructor(
@Composable
private fun SceneScope.LargeClockWithSmartSpace(shouldOffSetClockToOneHalf: Boolean = false) {
val burnIn = rememberBurnIn(clockInteractor)
- val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsState()
+ val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsStateWithLifecycle()
LaunchedEffect(isLargeClockVisible) {
if (isLargeClockVisible) {
@@ -170,8 +170,8 @@ constructor(
@Composable
private fun SceneScope.WeatherLargeClockWithSmartSpace(modifier: Modifier = Modifier) {
val burnIn = rememberBurnIn(clockInteractor)
- val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsState()
- val currentClockState = clockViewModel.currentClock.collectAsState()
+ val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsStateWithLifecycle()
+ val currentClockState = clockViewModel.currentClock.collectAsStateWithLifecycle()
LaunchedEffect(isLargeClockVisible) {
if (isLargeClockVisible) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 01d62a36fc62..cf2e895b044b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -38,7 +38,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
@@ -64,6 +63,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.NestedScrollBehavior
import com.android.compose.animation.scene.SceneScope
@@ -112,7 +112,7 @@ fun SceneScope.HeadsUpNotificationSpace(
modifier: Modifier = Modifier,
isPeekFromBottom: Boolean = false,
) {
- val headsUpHeight = viewModel.headsUpHeight.collectAsState()
+ val headsUpHeight = viewModel.headsUpHeight.collectAsStateWithLifecycle()
Element(
Notifications.Elements.HeadsUpNotificationPlaceholder,
@@ -138,6 +138,7 @@ fun SceneScope.HeadsUpNotificationSpace(
/** Adds the space where notification stack should appear in the scene. */
@Composable
fun SceneScope.ConstrainedNotificationStack(
+ stackScrollView: NotificationScrollView,
viewModel: NotificationsPlaceholderViewModel,
modifier: Modifier = Modifier,
) {
@@ -146,6 +147,7 @@ fun SceneScope.ConstrainedNotificationStack(
modifier.onSizeChanged { viewModel.onConstrainedAvailableSpaceChanged(it.height) }
) {
NotificationPlaceholder(
+ stackScrollView = stackScrollView,
viewModel = viewModel,
modifier = Modifier.fillMaxSize(),
)
@@ -178,9 +180,10 @@ fun SceneScope.NotificationScrollingStack(
shadeSession.rememberSaveableSession(saver = ScrollState.Saver, key = null) {
ScrollState(initial = 0)
}
- val syntheticScroll = viewModel.syntheticScroll.collectAsState(0f)
- val isCurrentGestureOverscroll = viewModel.isCurrentGestureOverscroll.collectAsState(false)
- val expansionFraction by viewModel.expandFraction.collectAsState(0f)
+ val syntheticScroll = viewModel.syntheticScroll.collectAsStateWithLifecycle(0f)
+ val isCurrentGestureOverscroll =
+ viewModel.isCurrentGestureOverscroll.collectAsStateWithLifecycle(false)
+ val expansionFraction by viewModel.expandFraction.collectAsStateWithLifecycle(0f)
val navBarHeight =
with(density) { WindowInsets.systemBars.asPaddingValues().calculateBottomPadding().toPx() }
@@ -193,7 +196,8 @@ fun SceneScope.NotificationScrollingStack(
*/
val stackHeight = remember { mutableIntStateOf(0) }
- val scrimRounding = viewModel.shadeScrimRounding.collectAsState(ShadeScrimRounding())
+ val scrimRounding =
+ viewModel.shadeScrimRounding.collectAsStateWithLifecycle(ShadeScrimRounding())
// the offset for the notifications scrim. Its upper bound is 0, and its lower bound is
// calculated in minScrimOffset. The scrim is the same height as the screen minus the
@@ -334,6 +338,7 @@ fun SceneScope.NotificationScrollingStack(
.debugBackground(viewModel, DEBUG_BOX_COLOR)
) {
NotificationPlaceholder(
+ stackScrollView = stackScrollView,
viewModel = viewModel,
modifier =
Modifier.verticalNestedScrollToScene(
@@ -390,6 +395,7 @@ fun SceneScope.NotificationShelfSpace(
@Composable
private fun SceneScope.NotificationPlaceholder(
+ stackScrollView: NotificationScrollView,
viewModel: NotificationsPlaceholderViewModel,
modifier: Modifier = Modifier,
) {
@@ -408,10 +414,8 @@ private fun SceneScope.NotificationPlaceholder(
" bounds=${coordinates.boundsInWindow()}"
}
// NOTE: positionInWindow.y scrolls off screen, but boundsInWindow.top will not
- viewModel.onStackBoundsChanged(
- top = positionInWindow.y,
- bottom = positionInWindow.y + coordinates.size.height,
- )
+ stackScrollView.setStackTop(positionInWindow.y)
+ stackScrollView.setStackBottom(positionInWindow.y + coordinates.size.height)
}
) {
content {}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
index 73cb72ca062e..b808044b76ce 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
@@ -36,7 +36,6 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
@@ -46,6 +45,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel
@@ -64,8 +64,8 @@ fun PeopleScreen(
viewModel: PeopleViewModel,
onResult: (PeopleViewModel.Result) -> Unit,
) {
- val priorityTiles by viewModel.priorityTiles.collectAsState()
- val recentTiles by viewModel.recentTiles.collectAsState()
+ val priorityTiles by viewModel.priorityTiles.collectAsStateWithLifecycle()
+ val recentTiles by viewModel.recentTiles.collectAsStateWithLifecycle()
// Call [onResult] this activity when the ViewModel tells us so.
LaunchedEffect(viewModel.result) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index 2f241cec37ee..e8da4bd2d2cd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -44,7 +44,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -69,6 +68,7 @@ import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.compose.animation.Expandable
import com.android.compose.animation.scene.SceneScope
@@ -132,8 +132,8 @@ fun FooterActions(
val context = LocalContext.current
// Collect alphas as soon as we are composed, even when not visible.
- val alpha by viewModel.alpha.collectAsState()
- val backgroundAlpha = viewModel.backgroundAlpha.collectAsState()
+ val alpha by viewModel.alpha.collectAsStateWithLifecycle()
+ val backgroundAlpha = viewModel.backgroundAlpha.collectAsStateWithLifecycle()
var security by remember { mutableStateOf<FooterActionsSecurityButtonViewModel?>(null) }
var foregroundServices by remember {
@@ -181,7 +181,6 @@ fun FooterActions(
val horizontalPadding = dimensionResource(R.dimen.qs_content_horizontal_padding)
Row(
modifier
- .sysuiResTag("qs_footer_actions")
.fillMaxWidth()
.graphicsLayer { this.alpha = alpha }
.then(backgroundModifier)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt
index ca6b3434d90e..73a624a030fe 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt
@@ -21,13 +21,13 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.modifiers.height
import com.android.compose.modifiers.width
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
@@ -40,13 +40,13 @@ fun BrightnessMirror(
qsSceneAdapter: QSSceneAdapter,
modifier: Modifier = Modifier,
) {
- val isShowing by viewModel.isShowing.collectAsState()
+ val isShowing by viewModel.isShowing.collectAsStateWithLifecycle()
val mirrorAlpha by
animateFloatAsState(
targetValue = if (isShowing) 1f else 0f,
label = "alphaAnimationBrightnessMirrorShowing",
)
- val mirrorOffsetAndSize by viewModel.locationAndSize.collectAsState()
+ val mirrorOffsetAndSize by viewModel.locationAndSize.collectAsStateWithLifecycle()
val offset = IntOffset(0, mirrorOffsetAndSize.yOffset)
Box(modifier = modifier.fillMaxSize().graphicsLayer { alpha = mirrorAlpha }) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index 46be6b898b8d..d1099883c5e5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -22,18 +22,19 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.MovableElementScenePicker
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.TransitionState
import com.android.compose.animation.scene.ValueKey
import com.android.compose.modifiers.thenIf
+import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Companion.Collapsing
import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Expanding
@@ -143,7 +144,9 @@ fun SceneScope.QuickSettings(
MovableElement(
key = QuickSettings.Elements.Content,
modifier =
- modifier.fillMaxWidth().layout { measurable, constraints ->
+ modifier.sysuiResTag("quick_settings_panel").fillMaxWidth().layout {
+ measurable,
+ constraints ->
val placeable = measurable.measure(constraints)
// Use the height of the correct view based on the scene it is being composed in
val height = heightProvider().coerceAtLeast(0)
@@ -161,9 +164,11 @@ private fun QuickSettingsContent(
state: QSSceneAdapter.State,
modifier: Modifier = Modifier,
) {
- val qsView by qsSceneAdapter.qsView.collectAsState(null)
+ val qsView by qsSceneAdapter.qsView.collectAsStateWithLifecycle(null)
val isCustomizing by
- qsSceneAdapter.isCustomizerShowing.collectAsState(qsSceneAdapter.isCustomizerShowing.value)
+ qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle(
+ qsSceneAdapter.isCustomizerShowing.value
+ )
QuickSettingsTheme {
val context = LocalContext.current
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 6ae0efa46d19..d76b19f3fa82 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -51,7 +51,6 @@ import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@@ -63,6 +62,7 @@ import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.TransitionState
import com.android.compose.animation.scene.animateSceneFloatAsState
@@ -163,7 +163,8 @@ private fun SceneScope.QuickSettingsScene(
) {
val cutoutLocation = LocalDisplayCutout.current.location
- val brightnessMirrorShowing by viewModel.brightnessMirrorViewModel.isShowing.collectAsState()
+ val brightnessMirrorShowing by
+ viewModel.brightnessMirrorViewModel.isShowing.collectAsStateWithLifecycle()
val contentAlpha by
animateFloatAsState(
targetValue = if (brightnessMirrorShowing) 0f else 1f,
@@ -198,10 +199,11 @@ private fun SceneScope.QuickSettingsScene(
Modifier.displayCutoutPadding()
},
) {
- val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
- val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState()
+ val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle()
+ val isCustomizerShowing by
+ viewModel.qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle()
val customizingAnimationDuration by
- viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsState()
+ viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle()
val screenHeight = LocalRawScreenHeight.current
BackHandler(
@@ -343,10 +345,10 @@ private fun SceneScope.QuickSettingsScene(
viewModel.qsSceneAdapter,
{ viewModel.qsSceneAdapter.qsHeight },
isSplitShade = false,
- modifier = Modifier.sysuiResTag("quick_settings_panel")
+ modifier = Modifier
)
- val isMediaVisible by viewModel.isMediaVisible.collectAsState()
+ val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
MediaCarousel(
isVisible = isMediaVisible,
@@ -362,7 +364,8 @@ private fun SceneScope.QuickSettingsScene(
isCustomizing = isCustomizing,
customizingAnimationDuration = customizingAnimationDuration,
lifecycleOwner = lifecycleOwner,
- modifier = Modifier.align(Alignment.CenterHorizontally),
+ modifier =
+ Modifier.align(Alignment.CenterHorizontally).sysuiResTag("qs_footer_actions"),
)
}
NotificationScrollingStack(
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 7af9b7bb90e9..92b2b4e886b9 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
@@ -23,7 +23,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -34,6 +33,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.motionEventSpy
import androidx.compose.ui.input.pointer.pointerInput
+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
@@ -68,8 +68,9 @@ fun SceneContainer(
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
- val currentSceneKey: SceneKey by viewModel.currentScene.collectAsState()
- val currentDestinations by viewModel.currentDestinationScenes(coroutineScope).collectAsState()
+ val currentSceneKey: SceneKey by viewModel.currentScene.collectAsStateWithLifecycle()
+ val currentDestinations by
+ viewModel.currentDestinationScenes(coroutineScope).collectAsStateWithLifecycle()
val state: MutableSceneTransitionLayoutState = remember {
MutableSceneTransitionLayoutState(
initialScene = currentSceneKey,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index d5287362c36d..00ef11d3b745 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -30,13 +30,13 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexScenePicker
import com.android.compose.animation.scene.SceneScope
@@ -51,7 +51,7 @@ fun SceneScope.OverlayShade(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
- val backgroundScene by viewModel.backgroundScene.collectAsState()
+ val backgroundScene by viewModel.backgroundScene.collectAsStateWithLifecycle()
Box(modifier) {
if (backgroundScene == Scenes.Lockscreen) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index 709a416c0366..ac3e015e52a9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -35,7 +35,6 @@ import androidx.compose.foundation.layout.widthIn
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
@@ -52,6 +51,7 @@ import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max
import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexScenePicker
import com.android.compose.animation.scene.SceneScope
@@ -118,7 +118,7 @@ fun SceneScope.CollapsedShadeHeader(
statusBarIconController: StatusBarIconController,
modifier: Modifier = Modifier,
) {
- val isDisabled by viewModel.isDisabled.collectAsState()
+ val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle()
if (isDisabled) {
return
}
@@ -138,7 +138,7 @@ fun SceneScope.CollapsedShadeHeader(
}
}
- val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsState()
+ val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle()
// This layout assumes it is globally positioned at (0, 0) and is the
// same size as the screen.
@@ -271,7 +271,7 @@ fun SceneScope.ExpandedShadeHeader(
statusBarIconController: StatusBarIconController,
modifier: Modifier = Modifier,
) {
- val isDisabled by viewModel.isDisabled.collectAsState()
+ val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle()
if (isDisabled) {
return
}
@@ -280,7 +280,7 @@ fun SceneScope.ExpandedShadeHeader(
derivedStateOf { shouldUseExpandedFormat(layoutState.transitionState) }
}
- val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsState()
+ val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle()
Box(modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root)) {
if (isPrivacyChipVisible) {
@@ -435,7 +435,7 @@ private fun ShadeCarrierGroup(
modifier: Modifier = Modifier,
) {
Row(modifier = modifier) {
- val subIds by viewModel.mobileSubIds.collectAsState()
+ val subIds by viewModel.mobileSubIds.collectAsStateWithLifecycle()
for (subId in subIds) {
Spacer(modifier = Modifier.width(5.dp))
@@ -472,10 +472,12 @@ private fun SceneScope.StatusIcons(
val micSlot = stringResource(id = com.android.internal.R.string.status_bar_microphone)
val locationSlot = stringResource(id = com.android.internal.R.string.status_bar_location)
- val isSingleCarrier by viewModel.isSingleCarrier.collectAsState()
- val isPrivacyChipEnabled by viewModel.isPrivacyChipEnabled.collectAsState()
- val isMicCameraIndicationEnabled by viewModel.isMicCameraIndicationEnabled.collectAsState()
- val isLocationIndicationEnabled by viewModel.isLocationIndicationEnabled.collectAsState()
+ val isSingleCarrier by viewModel.isSingleCarrier.collectAsStateWithLifecycle()
+ val isPrivacyChipEnabled by viewModel.isPrivacyChipEnabled.collectAsStateWithLifecycle()
+ val isMicCameraIndicationEnabled by
+ viewModel.isMicCameraIndicationEnabled.collectAsStateWithLifecycle()
+ val isLocationIndicationEnabled by
+ viewModel.isLocationIndicationEnabled.collectAsStateWithLifecycle()
AndroidView(
factory = { context ->
@@ -544,7 +546,7 @@ private fun SceneScope.PrivacyChip(
viewModel: ShadeHeaderViewModel,
modifier: Modifier = Modifier,
) {
- val privacyList by viewModel.privacyItems.collectAsState()
+ val privacyList by viewModel.privacyItems.collectAsStateWithLifecycle()
AndroidView(
factory = { context ->
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 42e6fccab0ae..a0278a616857 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -45,7 +45,6 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -58,6 +57,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexScenePicker
import com.android.compose.animation.scene.SceneScope
@@ -71,6 +71,7 @@ import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius
+import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
@@ -177,7 +178,7 @@ private fun SceneScope.ShadeScene(
modifier: Modifier = Modifier,
shadeSession: SaveableSession,
) {
- val shadeMode by viewModel.shadeMode.collectAsState()
+ val shadeMode by viewModel.shadeMode.collectAsStateWithLifecycle()
when (shadeMode) {
is ShadeMode.Single ->
SingleShade(
@@ -228,8 +229,8 @@ private fun SceneScope.SingleShade(
key = QuickSettings.SharedValues.TilesSquishiness,
canOverflow = false
)
- val isClickable by viewModel.isClickable.collectAsState()
- val isMediaVisible by viewModel.isMediaVisible.collectAsState()
+ val isClickable by viewModel.isClickable.collectAsStateWithLifecycle()
+ val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
val shouldPunchHoleBehindScrim =
layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade) ||
@@ -335,10 +336,11 @@ private fun SceneScope.SplitShade(
) {
val screenCornerRadius = LocalScreenCornerRadius.current
- val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
- val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState()
+ val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle()
+ val isCustomizerShowing by
+ viewModel.qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle()
val customizingAnimationDuration by
- viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsState()
+ viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle()
val lifecycleOwner = LocalLifecycleOwner.current
val footerActionsViewModel =
remember(lifecycleOwner, viewModel) { viewModel.getFooterActionsViewModel(lifecycleOwner) }
@@ -353,13 +355,13 @@ private fun SceneScope.SplitShade(
.unfoldTranslationX(
isOnStartSide = true,
)
- .collectAsState(0f)
+ .collectAsStateWithLifecycle(0f)
val unfoldTranslationXForEndSide by
viewModel
.unfoldTranslationX(
isOnStartSide = false,
)
- .collectAsState(0f)
+ .collectAsStateWithLifecycle(0f)
val navBarBottomHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
val bottomPadding by
@@ -383,7 +385,8 @@ private fun SceneScope.SplitShade(
}
}
- val brightnessMirrorShowing by viewModel.brightnessMirrorViewModel.isShowing.collectAsState()
+ val brightnessMirrorShowing by
+ viewModel.brightnessMirrorViewModel.isShowing.collectAsStateWithLifecycle()
val contentAlpha by
animateFloatAsState(
targetValue = if (brightnessMirrorShowing) 0f else 1f,
@@ -393,7 +396,7 @@ private fun SceneScope.SplitShade(
viewModel.notifications.setAlphaForBrightnessMirror(contentAlpha)
DisposableEffect(Unit) { onDispose { viewModel.notifications.setAlphaForBrightnessMirror(1f) } }
- val isMediaVisible by viewModel.isMediaVisible.collectAsState()
+ val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
val brightnessMirrorShowingModifier = Modifier.graphicsLayer { alpha = contentAlpha }
@@ -444,6 +447,7 @@ private fun SceneScope.SplitShade(
Column(
modifier =
Modifier.fillMaxSize()
+ .sysuiResTag("expanded_qs_scroll_view")
.weight(1f)
.thenIf(!isCustomizerShowing) {
Modifier.verticalNestedScrollToScene()
@@ -482,6 +486,7 @@ private fun SceneScope.SplitShade(
lifecycleOwner = lifecycleOwner,
modifier =
Modifier.align(Alignment.CenterHorizontally)
+ .sysuiResTag("qs_footer_actions")
.then(brightnessMirrorShowingModifier),
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
index 5e107c60bee6..931ff56e56cb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
@@ -3,9 +3,9 @@ package com.android.systemui.shade.ui.composable
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.shadeHeaderText
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
@@ -14,8 +14,8 @@ fun VariableDayDate(
viewModel: ShadeHeaderViewModel,
modifier: Modifier = Modifier,
) {
- val longerText = viewModel.longerDateText.collectAsState()
- val shorterText = viewModel.shorterDateText.collectAsState()
+ val longerText = viewModel.longerDateText.collectAsStateWithLifecycle()
+ val shorterText = viewModel.shorterDateText.collectAsStateWithLifecycle()
Layout(
contents =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
index 44b221c1f5e1..3976c618c179 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
@@ -19,31 +19,34 @@ package com.android.systemui.volume.panel.component.anc.ui.composable
import android.view.Gravity
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonColors
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.LiveRegionMode
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
-import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.liveRegion
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel
import com.android.systemui.volume.panel.component.popup.ui.composable.VolumePanelPopup
@@ -60,19 +63,12 @@ constructor(
@Composable
override fun VolumePanelComposeScope.Content(modifier: Modifier) {
- val slice by viewModel.buttonSlice.collectAsState()
+ val slice by viewModel.buttonSlice.collectAsStateWithLifecycle()
val label = stringResource(R.string.volume_panel_noise_control_title)
val screenWidth: Float =
with(LocalDensity.current) { LocalConfiguration.current.screenWidthDp.dp.toPx() }
var gravity by remember { mutableIntStateOf(Gravity.CENTER_HORIZONTAL) }
val isClickable = viewModel.isClickable(slice)
- val onClick =
- if (isClickable) {
- { with(ancPopup) { show(null, gravity) } }
- } else {
- null
- }
-
Column(
modifier =
modifier.onGloballyPositioned {
@@ -81,20 +77,33 @@ constructor(
verticalArrangement = Arrangement.spacedBy(12.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
- SliceAndroidView(
- modifier =
- Modifier.height(64.dp)
- .fillMaxWidth()
- .semantics {
- role = Role.Button
+ Box(
+ modifier = Modifier.height(64.dp),
+ ) {
+ SliceAndroidView(
+ modifier = modifier.fillMaxSize(),
+ slice = slice,
+ onWidthChanged = viewModel::onButtonSliceWidthChanged,
+ enableAccessibility = false,
+ )
+ Button(
+ modifier =
+ modifier.fillMaxSize().padding(8.dp).semantics {
+ liveRegion = LiveRegionMode.Polite
contentDescription = label
- }
- .clip(RoundedCornerShape(28.dp)),
- slice = slice,
- isEnabled = onClick != null,
- onWidthChanged = viewModel::onButtonSliceWidthChanged,
- onClick = onClick,
- )
+ },
+ enabled = isClickable,
+ onClick = { with(ancPopup) { show(null, gravity) } },
+ colors =
+ ButtonColors(
+ contentColor = Color.Transparent,
+ containerColor = Color.Transparent,
+ disabledContentColor = Color.Transparent,
+ disabledContainerColor = Color.Transparent,
+ )
+ ) {}
+ }
+
Text(
modifier = Modifier.clearAndSetSemantics {}.basicMarquee(),
text = label,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
index d53dbf9ddd48..15df1be02f56 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
@@ -23,11 +23,11 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.slice.Slice
import com.android.internal.logging.UiEventLogger
import com.android.systemui.animation.Expandable
@@ -67,14 +67,14 @@ constructor(
@Composable
private fun Content(dialog: SystemUIDialog) {
- val isAvailable by viewModel.isAvailable.collectAsState(true)
+ val isAvailable by viewModel.isAvailable.collectAsStateWithLifecycle(true)
if (!isAvailable) {
SideEffect { dialog.dismiss() }
return
}
- val slice by viewModel.popupSlice.collectAsState()
+ val slice by viewModel.popupSlice.collectAsStateWithLifecycle()
SliceAndroidView(
modifier = Modifier.fillMaxWidth(),
slice = slice,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
index fc5d212a0be7..23d50c577300 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
@@ -16,11 +16,12 @@
package com.android.systemui.volume.panel.component.anc.ui.composable
-import android.annotation.SuppressLint
import android.content.Context
+import android.os.Bundle
import android.view.ContextThemeWrapper
-import android.view.MotionEvent
import android.view.View
+import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityNodeInfo
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
@@ -32,14 +33,13 @@ import com.android.systemui.res.R
fun SliceAndroidView(
slice: Slice?,
modifier: Modifier = Modifier,
- isEnabled: Boolean = true,
onWidthChanged: ((Int) -> Unit)? = null,
- onClick: (() -> Unit)? = null,
+ enableAccessibility: Boolean = true,
) {
AndroidView(
modifier = modifier,
factory = { context: Context ->
- ClickableSliceView(
+ ComposeSliceView(
ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel),
)
.apply {
@@ -47,17 +47,18 @@ fun SliceAndroidView(
isScrollable = false
importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
setShowTitleItems(true)
- if (onWidthChanged != null) {
- addOnLayoutChangeListener(OnWidthChangedLayoutListener(onWidthChanged))
- }
}
},
- update = { sliceView: ClickableSliceView ->
+ update = { sliceView: ComposeSliceView ->
sliceView.slice = slice
- sliceView.onClick = onClick
- sliceView.isEnabled = isEnabled
- sliceView.isClickable = isEnabled
- }
+ sliceView.layoutListener = onWidthChanged?.let(::OnWidthChangedLayoutListener)
+ sliceView.enableAccessibility = enableAccessibility
+ },
+ onRelease = { sliceView: ComposeSliceView ->
+ sliceView.layoutListener = null
+ sliceView.slice = null
+ sliceView.enableAccessibility = true
+ },
)
}
@@ -83,26 +84,39 @@ class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) :
}
}
-/**
- * [SliceView] that prioritises [onClick] when its clicked instead of passing the event to the slice
- * first.
- */
-@SuppressLint("ViewConstructor") // only used in this class
-private class ClickableSliceView(context: Context) : SliceView(context) {
+private class ComposeSliceView(context: Context) : SliceView(context) {
+
+ var enableAccessibility: Boolean = true
+ var layoutListener: OnLayoutChangeListener? = null
+ set(value) {
+ field?.let { removeOnLayoutChangeListener(it) }
+ field = value
+ field?.let { addOnLayoutChangeListener(it) }
+ }
- var onClick: (() -> Unit)? = null
+ override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo?) {
+ if (enableAccessibility) {
+ super.onInitializeAccessibilityNodeInfo(info)
+ }
+ }
- init {
- if (onClick != null) {
- setOnClickListener {}
+ override fun onInitializeAccessibilityEvent(event: AccessibilityEvent?) {
+ if (enableAccessibility) {
+ super.onInitializeAccessibilityEvent(event)
}
}
- override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
- return (isSliceViewClickable && onClick != null) || super.onInterceptTouchEvent(ev)
+ override fun performAccessibilityAction(action: Int, arguments: Bundle?): Boolean {
+ return if (enableAccessibility) {
+ super.performAccessibilityAction(action, arguments)
+ } else {
+ false
+ }
}
- override fun onClick(v: View?) {
- onClick?.takeIf { isSliceViewClickable }?.let { it() } ?: super.onClick(v)
+ override fun addChildrenForAccessibility(outChildren: ArrayList<View>?) {
+ if (enableAccessibility) {
+ super.addChildrenForAccessibility(outChildren)
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
index f11c3a5852d8..e1ae80f13312 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
@@ -28,7 +28,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
@@ -44,6 +43,7 @@ import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.Expandable
import com.android.systemui.animation.Expandable
import com.android.systemui.common.ui.compose.Icon
@@ -61,7 +61,7 @@ class ButtonComponent(
@Composable
override fun VolumePanelComposeScope.Content(modifier: Modifier) {
- val viewModelByState by viewModelFlow.collectAsState()
+ val viewModelByState by viewModelFlow.collectAsStateWithLifecycle()
val viewModel = viewModelByState ?: return
val label = viewModel.label.toString()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
index 12debbc9c011..1b821d36dceb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
@@ -29,7 +29,6 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -42,6 +41,7 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.toggleableState
import androidx.compose.ui.state.ToggleableState
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.volume.panel.component.button.ui.viewmodel.ButtonViewModel
import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent
@@ -56,7 +56,7 @@ class ToggleButtonComponent(
@Composable
override fun VolumePanelComposeScope.Content(modifier: Modifier) {
- val viewModelByState by viewModelFlow.collectAsState()
+ val viewModelByState by viewModelFlow.collectAsStateWithLifecycle()
val viewModel = viewModelByState ?: return
val label = viewModel.label.toString()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
index ded63a107e70..237bbfd714b9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
@@ -45,7 +45,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -55,6 +54,7 @@ import androidx.compose.ui.semantics.liveRegion
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.Expandable
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.common.ui.compose.toColor
@@ -77,9 +77,9 @@ constructor(
@Composable
override fun VolumePanelComposeScope.Content(modifier: Modifier) {
val connectedDeviceViewModel: ConnectedDeviceViewModel? by
- viewModel.connectedDeviceViewModel.collectAsState()
+ viewModel.connectedDeviceViewModel.collectAsStateWithLifecycle()
val deviceIconViewModel: DeviceIconViewModel? by
- viewModel.deviceIconViewModel.collectAsState()
+ viewModel.deviceIconViewModel.collectAsStateWithLifecycle()
val clickLabel = stringResource(R.string.volume_panel_enter_media_output_settings)
Expandable(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
index d41acd9e852c..9891b5b5eba2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
@@ -23,11 +23,11 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.internal.logging.UiEventLogger
import com.android.systemui.animation.Expandable
import com.android.systemui.common.ui.compose.Icon
@@ -72,14 +72,14 @@ constructor(
@Composable
private fun Content(dialog: SystemUIDialog) {
- val isAvailable by viewModel.isAvailable.collectAsState()
+ val isAvailable by viewModel.isAvailable.collectAsStateWithLifecycle()
if (!isAvailable) {
SideEffect { dialog.dismiss() }
return
}
- val enabledModelStates by viewModel.spatialAudioButtons.collectAsState()
+ val enabledModelStates by viewModel.spatialAudioButtons.collectAsStateWithLifecycle()
if (enabledModelStates.isEmpty()) {
return
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
index 1def7fe95a4b..072e91a25444 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
@@ -40,7 +40,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -52,6 +51,7 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformSliderColors
import com.android.compose.modifiers.padding
import com.android.systemui.res.R
@@ -84,7 +84,7 @@ fun ColumnVolumeSliders(
modifier = Modifier.fillMaxWidth(),
) {
val sliderViewModel: SliderViewModel = viewModels.first()
- val sliderState by viewModels.first().slider.collectAsState()
+ val sliderState by viewModels.first().slider.collectAsStateWithLifecycle()
val sliderPadding by topSliderPadding(isExpandable)
VolumeSlider(
@@ -119,7 +119,7 @@ fun ColumnVolumeSliders(
Column {
for (index in 1..viewModels.lastIndex) {
val sliderViewModel: SliderViewModel = viewModels[index]
- val sliderState by sliderViewModel.slider.collectAsState()
+ val sliderState by sliderViewModel.slider.collectAsStateWithLifecycle()
transition.AnimatedVisibility(
modifier = Modifier.padding(top = 16.dp),
visible = { it || !isExpandable },
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt
index bb17499f021f..d15430faa0a0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt
@@ -18,9 +18,9 @@ package com.android.systemui.volume.panel.component.volume.ui.composable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformSliderColors
import com.android.compose.grid.VerticalGrid
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
@@ -39,7 +39,7 @@ fun GridVolumeSliders(
horizontalSpacing = 24.dp,
) {
for (sliderViewModel in viewModels) {
- val sliderState = sliderViewModel.slider.collectAsState().value
+ val sliderState = sliderViewModel.slider.collectAsStateWithLifecycle().value
VolumeSlider(
modifier = Modifier.fillMaxWidth(),
state = sliderState,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
index 79056b26d051..770c5d5c247c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
@@ -18,9 +18,9 @@ package com.android.systemui.volume.panel.component.volume.ui.composable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformSliderDefaults
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
import com.android.systemui.volume.panel.component.volume.ui.viewmodel.AudioVolumeComponentViewModel
@@ -38,7 +38,8 @@ constructor(
@Composable
override fun VolumePanelComposeScope.Content(modifier: Modifier) {
- val sliderViewModels: List<SliderViewModel> by viewModel.sliderViewModels.collectAsState()
+ val sliderViewModels: List<SliderViewModel> by
+ viewModel.sliderViewModels.collectAsStateWithLifecycle()
if (sliderViewModels.isEmpty()) {
return
}
@@ -52,7 +53,7 @@ constructor(
val expandableViewModel: SlidersExpandableViewModel by
viewModel
.isExpandable(isPortrait)
- .collectAsState(SlidersExpandableViewModel.Unavailable)
+ .collectAsStateWithLifecycle(SlidersExpandableViewModel.Unavailable)
if (expandableViewModel is SlidersExpandableViewModel.Unavailable) {
return
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
index a602e25e05c1..83b8158a9bcf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
@@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -32,6 +31,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.paneTitle
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.res.R
import com.android.systemui.volume.panel.ui.layout.ComponentsLayout
import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
@@ -54,8 +54,8 @@ fun VolumePanelRoot(
}
val accessibilityTitle = stringResource(R.string.accessibility_volume_settings)
- val state: VolumePanelState by viewModel.volumePanelState.collectAsState()
- val components by viewModel.componentsLayout.collectAsState(null)
+ val state: VolumePanelState by viewModel.volumePanelState.collectAsStateWithLifecycle()
+ val components by viewModel.componentsLayout.collectAsStateWithLifecycle(null)
with(VolumePanelComposeScope(state)) {
components?.let { componentsState ->
diff --git a/packages/SystemUI/flag_check.py b/packages/SystemUI/flag_check.py
index bac3553e7498..95a25c58bc67 100755
--- a/packages/SystemUI/flag_check.py
+++ b/packages/SystemUI/flag_check.py
@@ -12,19 +12,20 @@ following case-sensitive regex:
%s
The Flag: stanza is regex matched and should describe whether your change is behind a flag or flags.
-
-As a CL author, you'll have a consistent place to describe the risk of the proposed change by explicitly calling out the name of the
-flag in addition to its state (ENABLED|DISABLED|DEVELOPMENT|STAGING|TEAMFOOD|TRUNKFOOD|NEXTFOOD).
+As a CL author, you'll have a consistent place to describe the risk of the proposed change by explicitly calling out the name of the flag.
+For legacy flags use EXEMPT with your flag name.
Some examples below:
-Flag: NONE
-Flag: NA
-Flag: LEGACY ENABLE_ONE_SEARCH DISABLED
-Flag: ACONFIG com.android.launcher3.enable_twoline_allapps DEVELOPMENT
-Flag: ACONFIG com.android.launcher3.enable_twoline_allapps TRUNKFOOD
+Flag: NONE Repohook Update
+Flag: TEST_ONLY
+Flag: EXEMPT resource only update
+Flag: EXEMPT bugfix
+Flag: EXEMPT refactor
+Flag: com.android.launcher3.enable_twoline_allapps
+Flag: com.google.android.apps.nexuslauncher.zero_state_web_data_loader
-Check the git history for more examples. It's a regex matched field.
+Check the git history for more examples. It's a regex matched field. See go/android-flag-directive for more details on various formats.
"""
def main():
@@ -63,28 +64,31 @@ def main():
return
field = 'Flag'
- none = '(NONE|NA|N\/A)' # NONE|NA|N/A
-
- typeExpression = '\s*(LEGACY|ACONFIG)' # [type:LEGACY|ACONFIG]
+ none = 'NONE'
+ testOnly = 'TEST_ONLY'
+ docsOnly = 'DOCS_ONLY'
+ exempt = 'EXEMPT'
+ justification = '<justification>'
- # legacyFlagName contains only uppercase alphabets with '_' - Ex: ENABLE_ONE_SEARCH
- # Aconfig Flag name format = "packageName"."flagName"
+ # Aconfig Flag name format = <packageName>.<flagName>
# package name - Contains only lowercase alphabets + digits + '.' - Ex: com.android.launcher3
- # For now alphabets, digits, "_", "." characters are allowed in flag name and not adding stricter format check.
+ # For now alphabets, digits, "_", "." characters are allowed in flag name.
+ # Checks if there is "one dot" between packageName and flagName and not adding stricter format check
#common_typos_disable
- flagName = '([a-zA-z0-9_.])+'
+ flagName = '([a-zA-Z0-9.]+)([.]+)([a-zA-Z0-9_.]+)'
- #[state:ENABLED|DISABLED|DEVELOPMENT|TEAM*(TEAMFOOD)|STAGING|TRUNK*(TRUNK_STAGING, TRUNK_FOOD)|NEXT*(NEXTFOOD)]
- stateExpression = '\s*(ENABLED|DISABLED|DEVELOPMENT|TEAM[a-zA-z]*|STAGING|TRUNK[a-zA-z]*|NEXT[a-zA-z]*)'
+ # None and Exempt needs justification
+ exemptRegex = fr'{exempt}\s*[a-zA-Z]+'
+ noneRegex = fr'{none}\s*[a-zA-Z]+'
#common_typos_enable
- readableRegexMsg = '\n\tFlag: (NONE|NA)\n\tFlag: LEGACY|ACONFIG FlagName|packageName.flagName ENABLED|DISABLED|DEVELOPMENT|TEAMFOOD|STAGING|TRUNKFOOD|NEXTFOOD'
+ readableRegexMsg = '\n\tFlag: '+none+' '+justification+'\n\tFlag: <packageName>.<flagName>\n\tFlag: ' +exempt+' '+justification+'\n\tFlag: '+testOnly+'\n\tFlag: '+docsOnly
flagRegex = fr'^{field}: .*$'
check_flag = re.compile(flagRegex) #Flag:
# Ignore case for flag name format.
- flagNameRegex = fr'(?i)^{field}:\s*({none}|{typeExpression}\s*{flagName}\s*{stateExpression})\s*'
+ flagNameRegex = fr'(?i)^{field}:\s*({noneRegex}|{flagName}|{testOnly}|{docsOnly}|{exemptRegex})\s*'
check_flagName = re.compile(flagNameRegex) #Flag: <flag name format>
flagError = False
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 47a00f408460..624f18d53a70 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -133,7 +133,7 @@ class ColorScheme(
@ColorInt seed: Int,
darkTheme: Boolean,
style: Style
- ) : this(seed, darkTheme, style, 0.5)
+ ) : this(seed, darkTheme, style, 0.0)
@JvmOverloads
constructor(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index b4b812d60a1a..0ab09595d6b0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -265,7 +265,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
// Device is dreaming and on communal.
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -282,7 +282,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
// Device is not dreaming and on communal.
- fakeKeyguardRepository.setDreaming(false)
+ updateDreaming(false)
communalInteractor.changeScene(CommunalScenes.Communal)
// Scene stays as Communal
@@ -297,7 +297,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
// Device is dreaming and on communal.
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -309,7 +309,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
// Dream stops, timeout is cancelled and device stays on hub, because the regular
// screen timeout will take effect at this point.
- fakeKeyguardRepository.setDreaming(false)
+ updateDreaming(false)
advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
}
@@ -320,7 +320,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
// Device is on communal, but not dreaming.
- fakeKeyguardRepository.setDreaming(false)
+ updateDreaming(false)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -328,7 +328,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
// Wait a bit, but not long enough to timeout, then start dreaming.
advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
// Device times out after one screen timeout interval, dream doesn't reset timeout.
@@ -338,11 +338,31 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
+ fun hubTimeout_dreamAfterInitialTimeout_goesToBlank() =
+ with(kosmos) {
+ testScope.runTest {
+ // Device is on communal.
+ communalInteractor.changeScene(CommunalScenes.Communal)
+
+ // Device stays on the hub after the timeout since we're not dreaming.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
+ val scene by collectLastValue(communalInteractor.desiredScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Start dreaming.
+ updateDreaming(true)
+
+ // Hub times out immediately.
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
+ }
+ }
+
+ @Test
fun hubTimeout_userActivityTriggered_resetsTimeout() =
with(kosmos) {
testScope.runTest {
// Device is dreaming and on communal.
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -371,7 +391,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
// Device is dreaming and on communal.
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -395,6 +415,12 @@ class CommunalSceneStartableTest : SysuiTestCase() {
runCurrent()
}
+ private fun TestScope.updateDreaming(dreaming: Boolean) =
+ with(kosmos) {
+ fakeKeyguardRepository.setDreaming(dreaming)
+ runCurrent()
+ }
+
private suspend fun TestScope.enableCommunal() =
with(kosmos) {
setCommunalAvailable(true)
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 ce7b60e86f8f..325a324da8ad 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
@@ -29,6 +29,7 @@ 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
@@ -202,6 +203,18 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() {
.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
+ )
+ }
+
private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id)))
.thenReturn(disabledFlags)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index e3dd9aefa6d0..8bfa5cff8b97 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.DreamManager;
import android.content.res.Resources;
import android.graphics.Region;
import android.os.Handler;
@@ -45,8 +46,10 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.complication.ComplicationHostViewController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.BlurUtils;
import kotlinx.coroutines.CoroutineDispatcher;
@@ -115,6 +118,12 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
DreamOverlayStateController mStateController;
@Mock
KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ @Mock
+ ShadeInteractor mShadeInteractor;
+ @Mock
+ CommunalInteractor mCommunalInteractor;
+ @Mock
+ private DreamManager mDreamManager;
DreamOverlayContainerViewController mController;
@@ -146,7 +155,10 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mAnimationsController,
mStateController,
mBouncerlessScrimController,
- mKeyguardTransitionInteractor);
+ mKeyguardTransitionInteractor,
+ mShadeInteractor,
+ mCommunalInteractor,
+ mDreamManager);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index c5d7e1f490ee..285326421a14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -23,9 +23,8 @@ import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_LOW
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import android.platform.test.flag.junit.SetFlagsRule
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.GroupEntry
@@ -44,25 +43,29 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember
import com.android.systemui.statusbar.notification.collection.render.NodeController
import com.android.systemui.statusbar.notification.icon.ConversationIconManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifierImpl
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ConversationCoordinatorTest : SysuiTestCase() {
// captured listeners and pluggables:
@@ -72,22 +75,20 @@ class ConversationCoordinatorTest : SysuiTestCase() {
private lateinit var peopleComparator: NotifComparator
private lateinit var beforeRenderListListener: OnBeforeRenderListListener
+ private lateinit var peopleNotificationIdentifier: PeopleNotificationIdentifier
+ private lateinit var peopleAlertingSection: NotifSection
+
@Mock private lateinit var pipeline: NotifPipeline
@Mock private lateinit var conversationIconManager: ConversationIconManager
- @Mock private lateinit var peopleNotificationIdentifier: PeopleNotificationIdentifier
- @Mock private lateinit var channel: NotificationChannel
@Mock private lateinit var headerController: NodeController
- private lateinit var entry: NotificationEntry
- private lateinit var entryA: NotificationEntry
- private lateinit var entryB: NotificationEntry
private lateinit var coordinator: ConversationCoordinator
- @Rule @JvmField public val setFlagsRule = SetFlagsRule()
-
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ peopleNotificationIdentifier =
+ PeopleNotificationIdentifierImpl(mock(), GroupMembershipManagerImpl())
coordinator =
ConversationCoordinator(
peopleNotificationIdentifier,
@@ -95,7 +96,6 @@ class ConversationCoordinatorTest : SysuiTestCase() {
HighPriorityProvider(peopleNotificationIdentifier, GroupMembershipManagerImpl()),
headerController
)
- whenever(channel.isImportantConversation).thenReturn(true)
coordinator.attach(pipeline)
@@ -110,49 +110,65 @@ class ConversationCoordinatorTest : SysuiTestCase() {
if (!SortBySectionTimeFlag.isEnabled)
peopleComparator = peopleAlertingSectioner.comparator!!
- entry = NotificationEntryBuilder().setChannel(channel).build()
+ peopleAlertingSection = NotifSection(peopleAlertingSectioner, 0)
+ }
- val section = NotifSection(peopleAlertingSectioner, 0)
- entryA =
- NotificationEntryBuilder().setChannel(channel).setSection(section).setTag("A").build()
- entryB =
- NotificationEntryBuilder().setChannel(channel).setSection(section).setTag("B").build()
+ @Test
+ fun priorityPeopleSectionerClaimsOnlyImportantConversations() {
+ val sectioner = coordinator.priorityPeopleSectioner
+ assertTrue(sectioner.isInSection(makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON)))
+ assertFalse(sectioner.isInSection(makeEntryOfPeopleType(TYPE_FULL_PERSON)))
+ assertFalse(sectioner.isInSection(makeEntryOfPeopleType(TYPE_PERSON)))
+ assertFalse(sectioner.isInSection(makeEntryOfPeopleType(TYPE_NON_PERSON)))
+ assertFalse(sectioner.isInSection(NotificationEntryBuilder().build()))
}
@Test
fun testPromotesImportantConversations() {
- // only promote important conversations
- assertTrue(promoter.shouldPromoteToTopLevel(entry))
+ assertTrue(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON)))
+ assertFalse(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_FULL_PERSON)))
+ assertFalse(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_PERSON)))
+ assertFalse(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_NON_PERSON)))
assertFalse(promoter.shouldPromoteToTopLevel(NotificationEntryBuilder().build()))
}
@Test
fun testPromotedImportantConversationsMakesSummaryUnimportant() {
- val altChildA = NotificationEntryBuilder().setTag("A").build()
- val altChildB = NotificationEntryBuilder().setTag("B").build()
- val summary = NotificationEntryBuilder().setId(2).setChannel(channel).build()
+ val importantChannel =
+ mock<NotificationChannel>().also {
+ whenever(it.isImportantConversation).thenReturn(true)
+ }
+ val otherChannel =
+ mock<NotificationChannel>().also {
+ whenever(it.isImportantConversation).thenReturn(false)
+ }
+ val importantChild =
+ makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON) { setChannel(importantChannel) }
+ val altChildA =
+ makeEntryOfPeopleType(TYPE_FULL_PERSON) { setChannel(otherChannel).setTag("A") }
+ val altChildB =
+ makeEntryOfPeopleType(TYPE_FULL_PERSON) { setChannel(otherChannel).setTag("B") }
+ val summary =
+ makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON) { setChannel(importantChannel).setId(2) }
val groupEntry =
GroupEntryBuilder()
.setParent(GroupEntry.ROOT_ENTRY)
.setSummary(summary)
- .setChildren(listOf(entry, altChildA, altChildB))
+ .setChildren(listOf(importantChild, altChildA, altChildB))
.build()
- assertTrue(promoter.shouldPromoteToTopLevel(entry))
+ assertTrue(promoter.shouldPromoteToTopLevel(importantChild))
assertFalse(promoter.shouldPromoteToTopLevel(altChildA))
assertFalse(promoter.shouldPromoteToTopLevel(altChildB))
- NotificationEntryBuilder.setNewParent(entry, GroupEntry.ROOT_ENTRY)
- GroupEntryBuilder.getRawChildren(groupEntry).remove(entry)
- beforeRenderListListener.onBeforeRenderList(listOf(entry, groupEntry))
+ NotificationEntryBuilder.setNewParent(importantChild, GroupEntry.ROOT_ENTRY)
+ GroupEntryBuilder.getRawChildren(groupEntry).remove(importantChild)
+ beforeRenderListListener.onBeforeRenderList(listOf(importantChild, groupEntry))
verify(conversationIconManager).setUnimportantConversations(eq(listOf(summary.key)))
}
@Test
fun testInAlertingPeopleSectionWhenTheImportanceIsAtLeastDefault() {
// GIVEN
- val alertingEntry =
- NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_DEFAULT).build()
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(alertingEntry))
- .thenReturn(TYPE_PERSON)
+ val alertingEntry = makeEntryOfPeopleType(TYPE_PERSON) { setImportance(IMPORTANCE_DEFAULT) }
// put alerting people notifications in this section
assertThat(peopleAlertingSectioner.isInSection(alertingEntry)).isTrue()
@@ -162,10 +178,7 @@ class ConversationCoordinatorTest : SysuiTestCase() {
@EnableFlags(Flags.FLAG_SORT_SECTION_BY_TIME)
fun testInAlertingPeopleSectionWhenTheImportanceIsLowerThanDefault() {
// GIVEN
- val silentEntry =
- NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_LOW).build()
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(silentEntry))
- .thenReturn(TYPE_PERSON)
+ val silentEntry = makeEntryOfPeopleType(TYPE_PERSON) { setImportance(IMPORTANCE_LOW) }
// THEN put silent people notifications in alerting section
assertThat(peopleAlertingSectioner.isInSection(silentEntry)).isTrue()
@@ -175,10 +188,7 @@ class ConversationCoordinatorTest : SysuiTestCase() {
@DisableFlags(Flags.FLAG_SORT_SECTION_BY_TIME)
fun testInSilentPeopleSectionWhenTheImportanceIsLowerThanDefault() {
// GIVEN
- val silentEntry =
- NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_LOW).build()
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(silentEntry))
- .thenReturn(TYPE_PERSON)
+ val silentEntry = makeEntryOfPeopleType(TYPE_PERSON) { setImportance(IMPORTANCE_LOW) }
// THEN put silent people notifications in this section
assertThat(peopleSilentSectioner.isInSection(silentEntry)).isTrue()
@@ -191,18 +201,14 @@ class ConversationCoordinatorTest : SysuiTestCase() {
@Test
fun testNotInPeopleSection() {
// GIVEN
- val entry =
- NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_LOW).build()
+ val entry = makeEntryOfPeopleType(TYPE_NON_PERSON) { setImportance(IMPORTANCE_LOW) }
val importantEntry =
- NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_HIGH).build()
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(entry))
- .thenReturn(TYPE_NON_PERSON)
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(importantEntry))
- .thenReturn(TYPE_NON_PERSON)
+ makeEntryOfPeopleType(TYPE_NON_PERSON) { setImportance(IMPORTANCE_HIGH) }
// THEN - only put people notification either silent or alerting
- if (!SortBySectionTimeFlag.isEnabled)
+ if (!SortBySectionTimeFlag.isEnabled) {
assertThat(peopleSilentSectioner.isInSection(entry)).isFalse()
+ }
assertThat(peopleAlertingSectioner.isInSection(importantEntry)).isFalse()
}
@@ -210,22 +216,16 @@ class ConversationCoordinatorTest : SysuiTestCase() {
fun testInAlertingPeopleSectionWhenThereIsAnImportantChild() {
// GIVEN
val altChildA =
- NotificationEntryBuilder().setTag("A").setImportance(IMPORTANCE_DEFAULT).build()
- val altChildB = NotificationEntryBuilder().setTag("B").setImportance(IMPORTANCE_LOW).build()
- val summary =
- NotificationEntryBuilder()
- .setId(2)
- .setImportance(IMPORTANCE_LOW)
- .setChannel(channel)
- .build()
+ makeEntryOfPeopleType(TYPE_NON_PERSON) { setTag("A").setImportance(IMPORTANCE_DEFAULT) }
+ val altChildB =
+ makeEntryOfPeopleType(TYPE_NON_PERSON) { setTag("B").setImportance(IMPORTANCE_LOW) }
+ val summary = makeEntryOfPeopleType(TYPE_PERSON) { setId(2).setImportance(IMPORTANCE_LOW) }
val groupEntry =
GroupEntryBuilder()
.setParent(GroupEntry.ROOT_ENTRY)
.setSummary(summary)
.setChildren(listOf(altChildA, altChildB))
.build()
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(summary))
- .thenReturn(TYPE_PERSON)
// THEN
assertThat(peopleAlertingSectioner.isInSection(groupEntry)).isTrue()
}
@@ -233,10 +233,12 @@ class ConversationCoordinatorTest : SysuiTestCase() {
@Test
@DisableFlags(Flags.FLAG_SORT_SECTION_BY_TIME)
fun testComparatorPutsImportantPeopleFirst() {
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryA))
- .thenReturn(TYPE_IMPORTANT_PERSON)
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryB))
- .thenReturn(TYPE_PERSON)
+ val entryA =
+ makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON) {
+ setSection(peopleAlertingSection).setTag("A")
+ }
+ val entryB =
+ makeEntryOfPeopleType(TYPE_PERSON) { setSection(peopleAlertingSection).setTag("B") }
// only put people notifications in this section
assertThat(peopleComparator.compare(entryA, entryB)).isEqualTo(-1)
@@ -245,10 +247,10 @@ class ConversationCoordinatorTest : SysuiTestCase() {
@Test
@DisableFlags(Flags.FLAG_SORT_SECTION_BY_TIME)
fun testComparatorEquatesPeopleWithSameType() {
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryA))
- .thenReturn(TYPE_PERSON)
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryB))
- .thenReturn(TYPE_PERSON)
+ val entryA =
+ makeEntryOfPeopleType(TYPE_PERSON) { setSection(peopleAlertingSection).setTag("A") }
+ val entryB =
+ makeEntryOfPeopleType(TYPE_PERSON) { setSection(peopleAlertingSection).setTag("B") }
// only put people notifications in this section
assertThat(peopleComparator.compare(entryA, entryB)).isEqualTo(0)
@@ -259,4 +261,23 @@ class ConversationCoordinatorTest : SysuiTestCase() {
fun testNoSecondarySortForConversations() {
assertThat(peopleAlertingSectioner.comparator).isNull()
}
+
+ private fun makeEntryOfPeopleType(
+ @PeopleNotificationType type: Int,
+ buildBlock: NotificationEntryBuilder.() -> Unit = {}
+ ): NotificationEntry {
+ val channel: NotificationChannel = mock()
+ whenever(channel.isImportantConversation).thenReturn(type == TYPE_IMPORTANT_PERSON)
+ val entry =
+ NotificationEntryBuilder()
+ .updateRanking {
+ it.setIsConversation(type != TYPE_NON_PERSON)
+ it.setShortcutInfo(if (type >= TYPE_FULL_PERSON) mock() else null)
+ it.setChannel(channel)
+ }
+ .also(buildBlock)
+ .build()
+ assertEquals(type, peopleNotificationIdentifier.getPeopleNotificationType(entry))
+ return entry
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index 50ae98557de6..ce134e64bf57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -31,9 +31,9 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.compose.animation.scene.ObservableTransitionState;
@@ -57,6 +57,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.kotlin.JavaAdapter;
@@ -75,7 +76,7 @@ import org.mockito.MockitoAnnotations;
import org.mockito.verification.VerificationMode;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@@ -86,6 +87,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Mock private WakefulnessLifecycle mWakefulnessLifecycle;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private Pluggable.PluggableListener<NotifStabilityManager> mInvalidateListener;
+ @Mock private SeenNotificationsInteractor mSeenNotificationsInteractor;
@Mock private HeadsUpManager mHeadsUpManager;
@Mock private VisibilityLocationProvider mVisibilityLocationProvider;
@Mock private VisualStabilityProvider mVisualStabilityProvider;
@@ -121,6 +123,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
mHeadsUpManager,
mShadeAnimationInteractor,
mJavaAdapter,
+ mSeenNotificationsInteractor,
mStatusBarStateController,
mVisibilityLocationProvider,
mVisualStabilityProvider,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
index 1f0812da9fe9..ee9fd3494d96 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
@@ -44,13 +44,4 @@ class NotificationsPlaceholderViewModelTest : SysuiTestCase() {
collectLastValue(kosmos.notificationStackAppearanceInteractor.shadeScrimBounds)
assertThat(stackBounds).isEqualTo(bounds)
}
-
- @Test
- fun onStackBoundsChanged() =
- kosmos.testScope.runTest {
- underTest.onStackBoundsChanged(top = 5f, bottom = 500f)
- assertThat(kosmos.notificationStackAppearanceInteractor.stackTop.value).isEqualTo(5f)
- assertThat(kosmos.notificationStackAppearanceInteractor.stackBottom.value)
- .isEqualTo(500f)
- }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index f2ce745ed293..da17366a8416 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -660,9 +660,6 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
overrideResource(R.bool.config_use_split_notification_shade, false)
configurationRepository.onAnyConfigurationChange()
- keyguardInteractor.setNotificationContainerBounds(
- NotificationContainerBounds(top = 1f, bottom = 2f)
- )
assertThat(maxNotifications).isEqualTo(10)
@@ -691,9 +688,6 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
overrideResource(R.bool.config_use_split_notification_shade, false)
configurationRepository.onAnyConfigurationChange()
- keyguardInteractor.setNotificationContainerBounds(
- NotificationContainerBounds(top = 1f, bottom = 2f)
- )
assertThat(maxNotifications).isEqualTo(10)
@@ -728,9 +722,6 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
overrideResource(R.bool.config_use_split_notification_shade, false)
configurationRepository.onAnyConfigurationChange()
- keyguardInteractor.setNotificationContainerBounds(
- NotificationContainerBounds(top = 1f, bottom = 2f)
- )
// -1 means No Limit
assertThat(maxNotifications).isEqualTo(-1)
diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
index f644584f747a..5755dcd70a82 100644
--- a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
@@ -47,6 +47,7 @@ android:layout_height="match_parent">
android:layout_gravity="center"
android:contentDescription="@null"
android:scaleType="fitXY"
+ android:importantForAccessibility="no"
app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
app:layout_constraintStart_toStartOf="@+id/biometric_icon"
diff --git a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
index 46b8e4665a22..05f6faea464e 100644
--- a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
@@ -229,6 +229,7 @@
android:layout_gravity="center"
android:contentDescription="@null"
android:scaleType="fitXY"
+ android:importantForAccessibility="no"
app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
app:layout_constraintStart_toStartOf="@+id/biometric_icon"
diff --git a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
index d51fe5849133..fa4d9a868fd7 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
@@ -222,6 +222,7 @@
android:layout_gravity="center"
android:contentDescription="@null"
android:scaleType="fitXY"
+ android:importantForAccessibility="no"
app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
app:layout_constraintStart_toStartOf="@+id/biometric_icon"
diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml
index 2cb4b0233a90..49d3a8ec8ad8 100644
--- a/packages/SystemUI/res/layout/screenshot_shelf.xml
+++ b/packages/SystemUI/res/layout/screenshot_shelf.xml
@@ -135,11 +135,12 @@
android:id="@+id/screenshot_scrollable_preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:clipToOutline="true"
android:scaleType="matrix"
android:visibility="gone"
app:layout_constraintStart_toStartOf="@id/screenshot_preview"
app:layout_constraintTop_toTopOf="@id/screenshot_preview"
- android:elevation="7dp"/>
+ android:elevation="3dp"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
@@ -170,6 +171,13 @@
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
+ android:id="@+id/screenshot_scrolling_scrim"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:clickable="true"
+ android:importantForAccessibility="no"/>
+ <ImageView
android:id="@+id/screenshot_flash"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
index 8ac1de898be8..c33b7ce1d002 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
@@ -99,7 +99,7 @@ public class PipSurfaceTransactionHelper {
final float startScale = sourceRectHint.width() <= sourceRectHint.height()
? (float) destinationBounds.width() / sourceBounds.width()
: (float) destinationBounds.height() / sourceBounds.height();
- scale = (1 - progress) * startScale + progress * endScale;
+ scale = Math.min((1 - progress) * startScale + progress * endScale, 1.0f);
}
final float left = destinationBounds.left - (insets.left + sourceBounds.left) * scale;
final float top = destinationBounds.top - (insets.top + sourceBounds.top) * scale;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 905a98c2e181..42838aeddd6b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -326,7 +326,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
if (KeyguardWmStateRefactor.isEnabled()) {
- mKeyguardTransitionInteractor.startDismissKeyguardTransition();
+ mKeyguardTransitionInteractor.startDismissKeyguardTransition(
+ "KeyguardSecurityContainerController#finish");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
index c1be37af3aeb..a51d8ff4faa5 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -23,7 +23,6 @@ import androidx.compose.foundation.layout.size
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
@@ -32,6 +31,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformSlider
import com.android.systemui.brightness.shared.GammaBrightness
import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
@@ -107,10 +107,13 @@ fun BrightnessSliderContainer(
viewModel: BrightnessSliderViewModel,
modifier: Modifier = Modifier,
) {
- val gamma: Int by viewModel.currentBrightness.map { it.value }.collectAsState(initial = 0)
+ val gamma: Int by
+ viewModel.currentBrightness.map { it.value }.collectAsStateWithLifecycle(initialValue = 0)
val coroutineScope = rememberCoroutineScope()
val restriction by
- viewModel.policyRestriction.collectAsState(initial = PolicyRestriction.NoRestriction)
+ viewModel.policyRestriction.collectAsStateWithLifecycle(
+ initialValue = PolicyRestriction.NoRestriction
+ )
BrightnessSlider(
gammaValue = gamma,
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
index 8efc66de24cd..ba236ba016ff 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
@@ -66,11 +66,11 @@ import com.android.systemui.screenshot.ui.binder.ActionButtonViewBinder;
import com.android.systemui.screenshot.ui.viewmodel.ActionButtonAppearance;
import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel;
-import java.util.ArrayList;
-
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
+import java.util.ArrayList;
+
/**
* Handles the visual elements and animations for the clipboard overlay.
*/
@@ -109,6 +109,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
private View mDismissButton;
private LinearLayout mActionContainer;
private ClipboardOverlayCallbacks mClipboardCallbacks;
+ private ActionButtonViewBinder mActionButtonViewBinder = new ActionButtonViewBinder();
public ClipboardOverlayView(Context context) {
this(context, null);
@@ -152,14 +153,15 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
private void bindDefaultActionChips() {
if (screenshotShelfUi2()) {
- ActionButtonViewBinder.INSTANCE.bind(mRemoteCopyChip,
+ mActionButtonViewBinder.bind(mRemoteCopyChip,
ActionButtonViewModel.Companion.withNextId(
new ActionButtonAppearance(
Icon.createWithResource(mContext,
R.drawable.ic_baseline_devices_24).loadDrawable(
mContext),
null,
- mContext.getString(R.string.clipboard_send_nearby_description)),
+ mContext.getString(R.string.clipboard_send_nearby_description),
+ true),
new Function0<>() {
@Override
public Unit invoke() {
@@ -169,12 +171,14 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
return null;
}
}));
- ActionButtonViewBinder.INSTANCE.bind(mShareChip,
+ mActionButtonViewBinder.bind(mShareChip,
ActionButtonViewModel.Companion.withNextId(
new ActionButtonAppearance(
Icon.createWithResource(mContext,
R.drawable.ic_screenshot_share).loadDrawable(mContext),
- null, mContext.getString(com.android.internal.R.string.share)),
+ null,
+ mContext.getString(com.android.internal.R.string.share),
+ true),
new Function0<>() {
@Override
public Unit invoke() {
@@ -512,9 +516,9 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
private View constructShelfActionChip(RemoteAction action, Runnable onFinish) {
View chip = LayoutInflater.from(mContext).inflate(
R.layout.shelf_action_chip, mActionContainer, false);
- ActionButtonViewBinder.INSTANCE.bind(chip, ActionButtonViewModel.Companion.withNextId(
+ mActionButtonViewBinder.bind(chip, ActionButtonViewModel.Companion.withNextId(
new ActionButtonAppearance(action.getIcon().loadDrawable(mContext),
- action.getTitle(), action.getTitle()), new Function0<>() {
+ action.getTitle(), action.getTitle(), false), new Function0<>() {
@Override
public Unit invoke() {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index f437032d0ddb..6f20a8daf00a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -17,7 +17,6 @@
package com.android.systemui.communal
import android.provider.Settings
-import android.service.dreams.Flags.dreamTracksFocus
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.CoreStartable
import com.android.systemui.communal.domain.interactor.CommunalInteractor
@@ -43,6 +42,7 @@ import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
@@ -74,6 +74,10 @@ constructor(
) : CoreStartable {
private var screenTimeout: Int = DEFAULT_SCREEN_TIMEOUT
+ private var timeoutJob: Job? = null
+
+ private var isDreaming: Boolean = false
+
override fun start() {
// Handle automatically switching based on keyguard state.
keyguardTransitionInteractor.startedKeyguardTransitionStep
@@ -113,47 +117,67 @@ constructor(
}
.launchIn(bgScope)
- // Handle timing out back to the dream.
+ // The hub mode timeout should start as soon as the user enters hub mode. At the end of the
+ // timer, if the device is dreaming, hub mode should closed and reveal the dream. If the
+ // dream is not running, nothing will happen. However if the dream starts again underneath
+ // hub mode after the initial timeout expires, such as if the device is docked or the dream
+ // app is updated by the Play store, a new timeout should be started.
bgScope.launch {
combine(
communalInteractor.desiredScene,
// Emit a value on start so the combine starts.
communalInteractor.userActivity.emitOnStart()
) { scene, _ ->
- // Time out should run whenever we're dreaming and the hub is open, even if not
- // docked.
+ // Only timeout if we're on the hub is open.
scene == CommunalScenes.Communal
}
- // mapLatest cancels the previous action block when new values arrive, so any
- // already running timeout gets cancelled when conditions change or user interaction
- // is detected.
- .mapLatest { shouldTimeout ->
- if (!shouldTimeout) {
- return@mapLatest false
+ .collectLatest { shouldTimeout ->
+ cancelHubTimeout()
+ if (shouldTimeout) {
+ startHubTimeout()
}
-
- delay(screenTimeout.milliseconds)
- true
}
- .sample(keyguardInteractor.isDreaming, ::Pair)
- .collect { (shouldTimeout, isDreaming) ->
- if (isDreaming && shouldTimeout) {
+ }
+ bgScope.launch {
+ keyguardInteractor.isDreaming
+ .sample(communalInteractor.desiredScene, ::Pair)
+ .collectLatest { (isDreaming, scene) ->
+ this@CommunalSceneStartable.isDreaming = isDreaming
+ if (scene == CommunalScenes.Communal && isDreaming && timeoutJob == null) {
+ // If dreaming starts after timeout has expired, ex. if dream restarts under
+ // the hub, just close the hub immediately.
communalInteractor.changeScene(CommunalScenes.Blank)
}
}
}
- if (dreamTracksFocus()) {
- bgScope.launch {
- communalInteractor.isIdleOnCommunal.collectLatest {
- withContext(mainDispatcher) {
- notificationShadeWindowController.setGlanceableHubShowing(it)
- }
+ bgScope.launch {
+ communalInteractor.isIdleOnCommunal.collectLatest {
+ withContext(mainDispatcher) {
+ notificationShadeWindowController.setGlanceableHubShowing(it)
}
}
}
}
+ private fun cancelHubTimeout() {
+ timeoutJob?.cancel()
+ timeoutJob = null
+ }
+
+ private fun startHubTimeout() {
+ if (timeoutJob == null) {
+ timeoutJob =
+ bgScope.launch {
+ delay(screenTimeout.milliseconds)
+ if (isDreaming) {
+ communalInteractor.changeScene(CommunalScenes.Blank)
+ }
+ timeoutJob = null
+ }
+ }
+ }
+
private suspend fun determineSceneAfterTransition(
lastStartedTransition: TransitionStep,
): SceneKey? {
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 03f54c8b25d7..5cd15f278f00 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,15 +17,23 @@
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
* match those in {@link AppWidgetProviderInfo}).
*/
@JvmInline
-value class CommunalWidgetCategories(
- // The default is keyguard widgets.
- val categories: Int = AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD
-) {
+value class CommunalWidgetCategories(val categories: Int = defaultCategories) {
fun contains(category: Int) = (categories and category) == category
+
+ companion object {
+ val defaultCategories: Int
+ get() {
+ return AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD or
+ if (allowAllWidgetsOnLockscreenByDefault())
+ AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
+ else 0
+ }
+ }
}
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 9debe0e56083..88cb64c95c04 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
@@ -18,7 +18,6 @@ package com.android.systemui.communal.data.repository
import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
-import android.appwidget.AppWidgetProviderInfo
import android.content.IntentFilter
import android.content.pm.UserInfo
import android.provider.Settings
@@ -108,10 +107,9 @@ constructor(
.onStart { emit(Unit) }
.map {
CommunalWidgetCategories(
- // The default is to show only keyguard widgets.
secureSettings.getIntForUser(
GLANCEABLE_HUB_CONTENT_SETTING,
- AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
+ CommunalWidgetCategories.defaultCategories,
user.id
)
)
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 f9de60984e2d..3e5126a307eb 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
@@ -75,7 +75,7 @@ constructor(
scope = bgScope,
// Start this eagerly since the value can be accessed synchronously.
started = SharingStarted.Eagerly,
- initialValue = CommunalWidgetCategories().categories
+ initialValue = CommunalWidgetCategories.defaultCategories
)
private val workProfileUserInfoCallbackFlow: Flow<UserInfo?> = conflatedCallbackFlow {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 6e043391c197..60006c68639d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -16,6 +16,8 @@
package com.android.systemui.dreams;
+import static android.service.dreams.Flags.dreamHandlesBeingObscured;
+
import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress;
import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamAlphaScaledExpansion;
import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamYPositionScaledExpansion;
@@ -23,8 +25,10 @@ import static com.android.systemui.complication.ComplicationLayoutParams.POSITIO
import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.combineFlows;
import android.animation.Animator;
+import android.app.DreamManager;
import android.content.res.Resources;
import android.graphics.Region;
import android.os.Handler;
@@ -37,7 +41,9 @@ import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.complication.ComplicationHostViewController;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
@@ -45,10 +51,12 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.util.ViewController;
import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.flow.FlowKt;
import java.util.Arrays;
@@ -68,6 +76,8 @@ public class DreamOverlayContainerViewController extends
private final DreamOverlayStateController mStateController;
private final LowLightTransitionCoordinator mLowLightTransitionCoordinator;
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private final ShadeInteractor mShadeInteractor;
+ private final CommunalInteractor mCommunalInteractor;
private final ComplicationHostViewController mComplicationHostViewController;
@@ -87,9 +97,10 @@ public class DreamOverlayContainerViewController extends
// Main thread handler used to schedule periodic tasks (e.g. burn-in protection updates).
private final Handler mHandler;
- private final CoroutineDispatcher mMainDispatcher;
+ private final CoroutineDispatcher mBackgroundDispatcher;
private final int mDreamOverlayMaxTranslationY;
private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
+ private final DreamManager mDreamManager;
private long mJitterStartTimeMillis;
@@ -178,7 +189,7 @@ public class DreamOverlayContainerViewController extends
LowLightTransitionCoordinator lowLightTransitionCoordinator,
BlurUtils blurUtils,
@Main Handler handler,
- @Main CoroutineDispatcher mainDispatcher,
+ @Background CoroutineDispatcher backgroundDispatcher,
@Main Resources resources,
@Named(DreamOverlayModule.MAX_BURN_IN_OFFSET) int maxBurnInOffset,
@Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
@@ -188,18 +199,23 @@ public class DreamOverlayContainerViewController extends
DreamOverlayAnimationsController animationsController,
DreamOverlayStateController stateController,
BouncerlessScrimController bouncerlessScrimController,
- KeyguardTransitionInteractor keyguardTransitionInteractor) {
+ KeyguardTransitionInteractor keyguardTransitionInteractor,
+ ShadeInteractor shadeInteractor,
+ CommunalInteractor communalInteractor,
+ DreamManager dreamManager) {
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
mBlurUtils = blurUtils;
mDreamOverlayAnimationsController = animationsController;
mStateController = stateController;
+ mCommunalInteractor = communalInteractor;
mLowLightTransitionCoordinator = lowLightTransitionCoordinator;
mBouncerlessScrimController = bouncerlessScrimController;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+ mShadeInteractor = shadeInteractor;
mComplicationHostViewController = complicationHostViewController;
mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize(
@@ -211,11 +227,12 @@ public class DreamOverlayContainerViewController extends
ViewGroup.LayoutParams.MATCH_PARENT));
mHandler = handler;
- mMainDispatcher = mainDispatcher;
+ mBackgroundDispatcher = backgroundDispatcher;
mMaxBurnInOffset = maxBurnInOffset;
mBurnInProtectionUpdateInterval = burnInProtectionUpdateInterval;
mMillisUntilFullJitter = millisUntilFullJitter;
mPrimaryBouncerCallbackInteractor = primaryBouncerCallbackInteractor;
+ mDreamManager = dreamManager;
}
@Override
@@ -238,11 +255,21 @@ public class DreamOverlayContainerViewController extends
mView.getRootSurfaceControl().setTouchableRegion(emptyRegion);
emptyRegion.recycle();
- collectFlow(
- mView,
- mKeyguardTransitionInteractor.isFinishedInStateWhere(KeyguardState::isBouncerState),
- isFinished -> mAnyBouncerShowing = isFinished,
- mMainDispatcher);
+ if (dreamHandlesBeingObscured()) {
+ collectFlow(
+ mView,
+ FlowKt.distinctUntilChanged(combineFlows(
+ mKeyguardTransitionInteractor.isFinishedInStateWhere(
+ KeyguardState::isBouncerState),
+ mShadeInteractor.isAnyExpanded(),
+ mCommunalInteractor.isCommunalShowing(),
+ (anyBouncerShowing, shadeExpanded, communalShowing) -> {
+ mAnyBouncerShowing = anyBouncerShowing;
+ return anyBouncerShowing || shadeExpanded || communalShowing;
+ })),
+ mDreamManager::setDreamIsObscured,
+ mBackgroundDispatcher);
+ }
// Start dream entry animations. Skip animations for low light clock.
if (!mStateController.isLowLightActive()) {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 67c556409615..140434040ca7 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -29,11 +29,13 @@ 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.statusbar.notification.collection.SortBySectionTimeFlag
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor
import com.android.systemui.statusbar.notification.shared.NotificationAvalancheSuppression
import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
import javax.inject.Inject
/** A class in which engineers can define flag dependencies */
@@ -49,6 +51,7 @@ class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, ha
NotificationsLiveDataStoreRefactor.token dependsOn NotificationIconContainerRefactor.token
FooterViewRefactor.token dependsOn NotificationIconContainerRefactor.token
NotificationAvalancheSuppression.token dependsOn VisualInterruptionRefactor.token
+ PriorityPeopleSection.token dependsOn SortBySectionTimeFlag.token
// SceneContainer dependencies
SceneContainerFlag.getFlagDependencies().forEach { (alpha, beta) -> alpha dependsOn beta }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index dbaa297b7b43..68a252b2caba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -37,6 +37,7 @@ import android.provider.Settings;
import android.service.notification.ZenModeConfig;
import android.text.TextUtils;
import android.text.style.StyleSpan;
+import android.util.Log;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
@@ -212,21 +213,27 @@ public class KeyguardSliceProvider extends SliceProvider implements
@AnyThread
@Override
public Slice onBindSlice(Uri sliceUri) {
- Trace.beginSection("KeyguardSliceProvider#onBindSlice");
- Slice slice;
- synchronized (this) {
- ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
- if (needsMediaLocked()) {
- addMediaLocked(builder);
- } else {
- builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));
+ Slice slice = null;
+ try {
+ Trace.beginSection("KeyguardSliceProvider#onBindSlice");
+ synchronized (this) {
+ ListBuilder builder = new ListBuilder(getContext(), mSliceUri,
+ ListBuilder.INFINITY);
+ if (needsMediaLocked()) {
+ addMediaLocked(builder);
+ } else {
+ builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));
+ }
+ addNextAlarmLocked(builder);
+ addZenModeLocked(builder);
+ addPrimaryActionLocked(builder);
+ slice = builder.build();
}
- addNextAlarmLocked(builder);
- addZenModeLocked(builder);
- addPrimaryActionLocked(builder);
- slice = builder.build();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not initialize slice", e);
+ } finally {
+ Trace.endSection();
}
- Trace.endSection();
return slice;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
index 00f50023b263..1b342edb28fe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
@@ -23,6 +23,7 @@ import android.view.RemoteAnimationTarget
import android.view.WindowManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier
import com.android.systemui.statusbar.policy.KeyguardStateController
import java.util.concurrent.Executor
@@ -40,6 +41,7 @@ constructor(
private val activityTaskManagerService: IActivityTaskManager,
private val keyguardStateController: KeyguardStateController,
private val keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) {
/**
@@ -141,6 +143,14 @@ constructor(
finishedCallback: IRemoteAnimationFinishedCallback
) {
if (apps.isNotEmpty()) {
+ // Ensure that we've started a dismiss keyguard transition. WindowManager can start the
+ // going away animation on its own, if an activity launches and then requests dismissing
+ // the keyguard. In this case, this is the first and only signal we'll receive to start
+ // a transition to GONE.
+ keyguardTransitionInteractor.startDismissKeyguardTransition(
+ reason = "Going away remote animation started"
+ )
+
goingAwayRemoteAnimationFinishedCallback = finishedCallback
keyguardSurfaceBehindAnimator.applyParamsToSurface(apps[0])
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index dad2d9692dbc..f1e98f3bbe6d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -263,7 +263,9 @@ constructor(
}
fun dismissKeyguard() {
- scope.launch("$TAG#dismissKeyguard") { startTransitionTo(KeyguardState.GONE) }
+ scope.launch("$TAG#dismissKeyguard") {
+ startTransitionTo(KeyguardState.GONE, ownerReason = "#dismissKeyguard()")
+ }
}
private fun listenForLockscreenToGone() {
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 2d7b7375f625..72857391793f 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
@@ -97,6 +97,7 @@ constructor(
/** Bounds of the notification container. */
val notificationContainerBounds: StateFlow<NotificationContainerBounds> by lazy {
+ SceneContainerFlag.assertInLegacyMode()
combine(
_notificationPlaceholderBounds,
sharedNotificationContainerInteractor.get().configurationBasedDimensions,
@@ -115,6 +116,7 @@ constructor(
}
fun setNotificationContainerBounds(position: NotificationContainerBounds) {
+ SceneContainerFlag.assertInLegacyMode()
_notificationPlaceholderBounds.value = position
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 30c6718adf1b..aad1ec5f0031 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -218,6 +218,8 @@ constructor(
.map { step -> step.to }
.shareIn(scope, SharingStarted.Eagerly, replay = 1)
+ val currentTransitionInfo: StateFlow<TransitionInfo> = repository.currentTransitionInfoInternal
+
/** The from state of the last [TransitionState.STARTED] transition. */
// TODO: is it performant to have several SharedFlows side by side instead of one?
@SuppressLint("SharedFlowCreation")
@@ -375,22 +377,27 @@ constructor(
/**
* Called to start a transition that will ultimately dismiss the keyguard from the current
* state.
+ *
+ * This is called exclusively by sources that can authoritatively say we should be unlocked,
+ * including KeyguardSecurityContainerController and WindowManager.
*/
- fun startDismissKeyguardTransition() {
+ fun startDismissKeyguardTransition(reason: String = "") {
// TODO(b/336576536): Check if adaptation for scene framework is needed
if (SceneContainerFlag.isEnabled) return
- when (val startedState = startedKeyguardState.replayCache.last()) {
+ Log.d(TAG, "#startDismissKeyguardTransition(reason=$reason)")
+ when (val startedState = currentTransitionInfoInternal.value.to) {
LOCKSCREEN -> fromLockscreenTransitionInteractor.get().dismissKeyguard()
PRIMARY_BOUNCER -> fromPrimaryBouncerTransitionInteractor.get().dismissPrimaryBouncer()
ALTERNATE_BOUNCER ->
fromAlternateBouncerTransitionInteractor.get().dismissAlternateBouncer()
AOD -> fromAodTransitionInteractor.get().dismissAod()
DOZING -> fromDozingTransitionInteractor.get().dismissFromDozing()
- else ->
- Log.e(
- "KeyguardTransitionInteractor",
- "We don't know how to dismiss keyguard from state $startedState."
+ KeyguardState.GONE ->
+ Log.i(
+ TAG,
+ "Already transitioning to GONE; ignoring startDismissKeyguardTransition."
)
+ else -> Log.e(TAG, "We don't know how to dismiss keyguard from state $startedState.")
}
}
@@ -527,4 +534,8 @@ constructor(
@FloatRange(from = 0.0, to = 1.0) value: Float,
state: TransitionState
) = repository.updateTransition(transitionId, value, state)
+
+ companion object {
+ private const val TAG = "KeyguardTransitionInteractor"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
index 6e00aa7956e7..3baeb7682e12 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
@@ -131,7 +131,7 @@ constructor(
val newTransition =
TransitionInfo(
ownerName = this::class.java.simpleName,
- from = transitionInteractor.getStartedState(),
+ from = transitionInteractor.currentTransitionInfo.value.to,
to = state,
animator = null,
modeOnCanceled = TransitionModeOnCanceled.REVERSE
@@ -150,7 +150,7 @@ constructor(
private suspend fun handleTransition(transition: ObservableTransitionState.Transition) {
if (transition.fromScene == Scenes.Lockscreen) {
if (currentTransitionId != null) {
- val currentToState = transitionInteractor.getStartedState()
+ val currentToState = transitionInteractor.currentTransitionInfo.value.to
if (currentToState == UNDEFINED) {
transitionKtfTo(transitionInteractor.getStartedFromState())
}
@@ -169,6 +169,8 @@ constructor(
}
private suspend fun transitionKtfTo(state: KeyguardState) {
+ // TODO(b/330311871): This is based on a sharedFlow and thus might not be up-to-date and
+ // cause a race condition. (There is no known scenario that is currently affected.)
val currentTransition = transitionInteractor.transitionState.value
if (currentTransition.isFinishedIn(state)) {
// This is already the state we want to be in
@@ -199,7 +201,7 @@ constructor(
}
private suspend fun startTransitionFromLockscreen() {
- val currentState = transitionInteractor.getStartedState()
+ val currentState = transitionInteractor.currentTransitionInfo.value.to
val newTransition =
TransitionInfo(
ownerName = this::class.java.simpleName,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index 218967c338ea..7c745bc227f0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -57,9 +57,9 @@ class ClockSizeTransition(
addTransition(SmartspaceMoveTransition(config, clockViewModel))
}
- open class VisibilityBoundsTransition() : Transition() {
- var captureSmartspace: Boolean = false
-
+ abstract class VisibilityBoundsTransition() : Transition() {
+ abstract val captureSmartspace: Boolean
+ protected val TAG = this::class.simpleName!!
override fun captureEndValues(transition: TransitionValues) = captureValues(transition)
override fun captureStartValues(transition: TransitionValues) = captureValues(transition)
override fun getTransitionProperties(): Array<String> = TRANSITION_PROPERTIES
@@ -76,7 +76,7 @@ class ClockSizeTransition(
parent.findViewById<View>(sharedR.id.bc_smartspace_view)
?: parent.findViewById<View>(R.id.keyguard_slice_view)
if (targetSSView == null) {
- Log.e(TAG, "Failed to find smartspace equivalent target for animation")
+ Log.e(TAG, "Failed to find smartspace equivalent target under $parent")
return
}
transition.values[SMARTSPACE_BOUNDS] = targetSSView.getRect()
@@ -109,14 +109,12 @@ class ClockSizeTransition(
var fromIsVis = fromVis == View.VISIBLE
var fromAlpha = startValues.values[PROP_ALPHA] as Float
val fromBounds = startValues.values[PROP_BOUNDS] as Rect
- val fromSSBounds =
- if (captureSmartspace) startValues.values[SMARTSPACE_BOUNDS] as Rect else null
+ val fromSSBounds = startValues.values[SMARTSPACE_BOUNDS] as Rect?
val toView = endValues.view
val toVis = endValues.values[PROP_VISIBILITY] as Int
val toBounds = endValues.values[PROP_BOUNDS] as Rect
- val toSSBounds =
- if (captureSmartspace) endValues.values[SMARTSPACE_BOUNDS] as Rect else null
+ val toSSBounds = endValues.values[SMARTSPACE_BOUNDS] as Rect?
val toIsVis = toVis == View.VISIBLE
val toAlpha = if (toIsVis) 1f else 0f
@@ -221,9 +219,6 @@ class ClockSizeTransition(
private const val SMARTSPACE_BOUNDS = "ClockSizeTransition:SSBounds"
private val TRANSITION_PROPERTIES =
arrayOf(PROP_VISIBILITY, PROP_ALPHA, PROP_BOUNDS, SMARTSPACE_BOUNDS)
-
- private val DEBUG = false
- private val TAG = VisibilityBoundsTransition::class.simpleName!!
}
}
@@ -232,18 +227,24 @@ class ClockSizeTransition(
val viewModel: KeyguardClockViewModel,
val smartspaceViewModel: KeyguardSmartspaceViewModel,
) : VisibilityBoundsTransition() {
+ override val captureSmartspace = !viewModel.isLargeClockVisible.value
+
init {
duration = CLOCK_IN_MILLIS
startDelay = CLOCK_IN_START_DELAY_MILLIS
interpolator = CLOCK_IN_INTERPOLATOR
- captureSmartspace =
- !viewModel.isLargeClockVisible.value && smartspaceViewModel.isSmartspaceEnabled
if (viewModel.isLargeClockVisible.value) {
viewModel.currentClock.value?.let {
+ if (DEBUG) Log.i(TAG, "Large Clock In: ${it.largeClock.layout.views}")
it.largeClock.layout.views.forEach { addTarget(it) }
}
+ ?: run {
+ Log.e(TAG, "No large clock set, falling back")
+ addTarget(R.id.lockscreen_clock_view_large)
+ }
} else {
+ if (DEBUG) Log.i(TAG, "Small Clock In")
addTarget(R.id.lockscreen_clock_view)
}
}
@@ -282,7 +283,6 @@ class ClockSizeTransition(
val CLOCK_IN_INTERPOLATOR = Interpolators.LINEAR_OUT_SLOW_IN
const val SMALL_CLOCK_IN_MOVE_SCALE =
CLOCK_IN_MILLIS / SmartspaceMoveTransition.STATUS_AREA_MOVE_DOWN_MILLIS.toFloat()
- private val TAG = ClockFaceInTransition::class.simpleName!!
}
}
@@ -291,18 +291,24 @@ class ClockSizeTransition(
val viewModel: KeyguardClockViewModel,
val smartspaceViewModel: KeyguardSmartspaceViewModel,
) : VisibilityBoundsTransition() {
+ override val captureSmartspace = viewModel.isLargeClockVisible.value
+
init {
duration = CLOCK_OUT_MILLIS
interpolator = CLOCK_OUT_INTERPOLATOR
- captureSmartspace =
- viewModel.isLargeClockVisible.value && smartspaceViewModel.isSmartspaceEnabled
if (viewModel.isLargeClockVisible.value) {
+ if (DEBUG) Log.i(TAG, "Small Clock Out")
addTarget(R.id.lockscreen_clock_view)
} else {
viewModel.currentClock.value?.let {
+ if (DEBUG) Log.i(TAG, "Large Clock Out: ${it.largeClock.layout.views}")
it.largeClock.layout.views.forEach { addTarget(it) }
}
+ ?: run {
+ Log.e(TAG, "No large clock set, falling back")
+ addTarget(R.id.lockscreen_clock_view_large)
+ }
}
}
@@ -339,7 +345,6 @@ class ClockSizeTransition(
val CLOCK_OUT_INTERPOLATOR = Interpolators.LINEAR
const val SMALL_CLOCK_OUT_MOVE_SCALE =
CLOCK_OUT_MILLIS / SmartspaceMoveTransition.STATUS_AREA_MOVE_UP_MILLIS.toFloat()
- private val TAG = ClockFaceOutTransition::class.simpleName!!
}
}
@@ -348,6 +353,8 @@ class ClockSizeTransition(
val config: IntraBlueprintTransition.Config,
viewModel: KeyguardClockViewModel,
) : VisibilityBoundsTransition() {
+ override val captureSmartspace = false
+
init {
duration =
if (viewModel.isLargeClockVisible.value) STATUS_AREA_MOVE_UP_MILLIS
@@ -367,4 +374,8 @@ class ClockSizeTransition(
const val STATUS_AREA_MOVE_DOWN_MILLIS = 467L
}
}
+
+ companion object {
+ val DEBUG = true
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
index d1fee903e6f5..1a0f582fb100 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
@@ -21,9 +21,7 @@ import android.app.BroadcastOptions
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
-import android.media.session.MediaController
import android.media.session.MediaSession
-import android.media.session.PlaybackState
import android.provider.Settings
import android.util.Log
import com.android.internal.jank.Cuj
@@ -42,7 +40,6 @@ import com.android.systemui.media.dialog.MediaOutputDialogManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.kotlin.pairwiseBy
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.Flow
@@ -70,19 +67,6 @@ constructor(
.map { entries -> entries[instanceId]?.let { toMediaControlModel(it) } }
.distinctUntilChanged()
- val isStartedPlaying: Flow<Boolean> =
- mediaControl
- .map { mediaControl ->
- mediaControl?.token?.let { token ->
- MediaController(applicationContext, token).playbackState?.let {
- it.state == PlaybackState.STATE_PLAYING
- }
- }
- ?: false
- }
- .pairwiseBy(initialValue = false) { wasPlaying, isPlaying -> !wasPlaying && isPlaying }
- .distinctUntilChanged()
-
val onAnyMediaConfigurationChange: Flow<Unit> = repository.onAnyMediaConfigurationChange
fun removeMediaControl(
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
index 73fb5583ab3e..fed93f037638 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
@@ -260,44 +260,50 @@ object MediaControlViewBinder {
}
SEMANTIC_ACTIONS_ALL.forEachIndexed { index, id ->
- val button = viewHolder.getAction(id)
- val actionViewModel = viewModel.actionButtons[index]
- if (button.id == R.id.actionPrev) {
- actionViewModel?.let {
- viewController.setUpPrevButtonInfo(true, it.notVisibleValue)
- }
- } else if (button.id == R.id.actionNext) {
- actionViewModel?.let {
- viewController.setUpNextButtonInfo(true, it.notVisibleValue)
- }
+ val buttonView = viewHolder.getAction(id)
+ val buttonModel = viewModel.actionButtons[index]
+ if (buttonView.id == R.id.actionPrev) {
+ viewController.setUpPrevButtonInfo(
+ buttonModel.isEnabled,
+ buttonModel.notVisibleValue
+ )
+ } else if (buttonView.id == R.id.actionNext) {
+ viewController.setUpNextButtonInfo(
+ buttonModel.isEnabled,
+ buttonModel.notVisibleValue
+ )
}
- actionViewModel?.let { action ->
- val animHandler = (button.tag ?: AnimationBindHandler()) as AnimationBindHandler
- animHandler.tryExecute {
- if (animHandler.updateRebindId(action.rebindId)) {
+ val animHandler = (buttonView.tag ?: AnimationBindHandler()) as AnimationBindHandler
+ animHandler.tryExecute {
+ if (buttonModel.isEnabled) {
+ if (animHandler.updateRebindId(buttonModel.rebindId)) {
animHandler.unregisterAll()
- animHandler.tryRegister(action.icon)
- animHandler.tryRegister(action.background)
+ animHandler.tryRegister(buttonModel.icon)
+ animHandler.tryRegister(buttonModel.background)
bindButtonCommon(
- button,
+ buttonView,
viewHolder.multiRippleView,
- action,
+ buttonModel,
viewController,
falsingManager,
)
}
- val visible = action.isVisibleWhenScrubbing || !viewController.isScrubbing
- setSemanticButtonVisibleAndAlpha(
- viewHolder.getAction(id),
- viewController.expandedLayout,
- viewController.collapsedLayout,
- visible,
- action.notVisibleValue,
- action.showInCollapsed
- )
+ } else {
+ animHandler.unregisterAll()
+ clearButton(buttonView)
}
+ val visible =
+ buttonModel.isEnabled &&
+ (buttonModel.isVisibleWhenScrubbing || !viewController.isScrubbing)
+ setSemanticButtonVisibleAndAlpha(
+ viewHolder.getAction(id),
+ viewController.expandedLayout,
+ viewController.collapsedLayout,
+ visible,
+ buttonModel.notVisibleValue,
+ buttonModel.showInCollapsed
+ )
}
- ?: clearButton(button)
}
} else {
// Hide buttons that only appear for semantic actions
@@ -309,22 +315,16 @@ object MediaControlViewBinder {
// Set all generic buttons
genericButtons.forEachIndexed { index, button ->
if (index < viewModel.actionButtons.size) {
- viewModel.actionButtons[index]?.let { action ->
- bindButtonCommon(
- button,
- viewHolder.multiRippleView,
- action,
- viewController,
- falsingManager,
- )
- setVisibleAndAlpha(expandedSet, button.id, visible = true)
- setVisibleAndAlpha(
- collapsedSet,
- button.id,
- visible = action.showInCollapsed
- )
- }
- ?: clearButton(button)
+ val action = viewModel.actionButtons[index]
+ bindButtonCommon(
+ button,
+ viewHolder.multiRippleView,
+ action,
+ viewController,
+ falsingManager,
+ )
+ setVisibleAndAlpha(expandedSet, button.id, visible = true)
+ setVisibleAndAlpha(collapsedSet, button.id, visible = action.showInCollapsed)
} else {
// Hide any unused buttons
clearButton(button)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index b07253402645..d09e997da20f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -360,8 +360,10 @@ constructor(
)
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
mediaCarousel.repeatWhenAttached {
- mediaCarouselViewModel.onAttached()
- mediaCarouselScrollHandler.scrollToStart()
+ if (mediaFlags.isMediaControlsRefactorEnabled()) {
+ mediaCarouselViewModel.onAttached()
+ mediaCarouselScrollHandler.scrollToStart()
+ }
repeatOnLifecycle(Lifecycle.State.STARTED) {
listenForAnyStateToGoneKeyguardTransition(this)
listenForAnyStateToLockscreenTransition(this)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
index 2b5985882a6e..38377088a2d7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
@@ -709,12 +709,6 @@ constructor(
// For Turbulence noise.
val loadingEffectView = mediaViewHolder.loadingEffectView
- turbulenceNoiseAnimationConfig =
- createTurbulenceNoiseConfig(
- loadingEffectView,
- turbulenceNoiseView,
- colorSchemeTransition
- )
noiseDrawCallback =
object : PaintDrawCallback {
override fun onDraw(paint: Paint) {
@@ -809,6 +803,14 @@ constructor(
fun setUpTurbulenceNoise() {
if (!mediaFlags.isMediaControlsRefactorEnabled()) return
+ if (!this::turbulenceNoiseAnimationConfig.isInitialized) {
+ turbulenceNoiseAnimationConfig =
+ createTurbulenceNoiseConfig(
+ mediaViewHolder.loadingEffectView,
+ mediaViewHolder.turbulenceNoiseView,
+ colorSchemeTransition
+ )
+ }
if (Flags.shaderlibLoadingEffectRefactor()) {
if (!this::loadingEffect.isInitialized) {
loadingEffect =
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
index bc364c36a298..1944f072e7dd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
@@ -20,6 +20,7 @@ import android.content.Context
import android.content.pm.PackageManager
import android.media.session.MediaController
import android.media.session.MediaSession.Token
+import android.media.session.PlaybackState
import android.text.TextUtils
import android.util.Log
import androidx.constraintlayout.widget.ConstraintSet
@@ -40,16 +41,14 @@ import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.monet.ColorScheme
import com.android.systemui.monet.Style
import com.android.systemui.res.R
-import com.android.systemui.util.kotlin.sample
import java.util.concurrent.Executor
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
/** Models UI state and handles user input for a media control. */
class MediaControlViewModel(
@@ -60,31 +59,20 @@ class MediaControlViewModel(
private val logger: MediaUiEventLogger,
) {
- private val isAnyButtonClicked: MutableStateFlow<Boolean> = MutableStateFlow(false)
-
- private val playTurbulenceNoise: Flow<Boolean> =
- interactor.mediaControl.sample(
- combine(isAnyButtonClicked, interactor.isStartedPlaying) {
- isButtonClicked,
- isStartedPlaying ->
- isButtonClicked && isStartedPlaying
- }
- .distinctUntilChanged()
- )
-
@OptIn(ExperimentalCoroutinesApi::class)
val player: Flow<MediaPlayerViewModel?> =
interactor.onAnyMediaConfigurationChange
.flatMapLatest {
- combine(playTurbulenceNoise, interactor.mediaControl) {
- playTurbulenceNoise,
- mediaControl ->
- mediaControl?.let { toViewModel(it, playTurbulenceNoise) }
+ interactor.mediaControl.map { mediaControl ->
+ mediaControl?.let { toViewModel(it) }
}
}
.distinctUntilChanged()
.flowOn(backgroundDispatcher)
+ private var isPlaying = false
+ private var isAnyButtonClicked = false
+
private fun onDismissMediaData(
token: Token?,
uid: Int,
@@ -95,10 +83,8 @@ class MediaControlViewModel(
interactor.removeMediaControl(token, instanceId, MEDIA_PLAYER_ANIMATION_DELAY)
}
- private suspend fun toViewModel(
- model: MediaControlModel,
- playTurbulenceNoise: Boolean
- ): MediaPlayerViewModel? {
+ private suspend fun toViewModel(model: MediaControlModel): MediaPlayerViewModel? {
+ val mediaController = model.token?.let { MediaController(applicationContext, it) }
val wallpaperColors =
MediaArtworkHelper.getWallpaperColor(
applicationContext,
@@ -118,8 +104,14 @@ class MediaControlViewModel(
val gutsViewModel = toGutsViewModel(model, scheme)
+ // Set playing state
+ val wasPlaying = isPlaying
+ isPlaying =
+ mediaController?.playbackState?.let { it.state == PlaybackState.STATE_PLAYING } ?: false
+
// Resetting button clicks state.
- isAnyButtonClicked.value = false
+ val wasButtonClicked = isAnyButtonClicked
+ isAnyButtonClicked = false
return MediaPlayerViewModel(
contentDescription = { gutsVisible ->
@@ -144,7 +136,7 @@ class MediaControlViewModel(
shouldAddGradient = wallpaperColors != null,
colorScheme = scheme,
canShowTime = canShowScrubbingTimeViews(model.semanticActionButtons),
- playTurbulenceNoise = playTurbulenceNoise,
+ playTurbulenceNoise = isPlaying && !wasPlaying && wasButtonClicked,
useSemanticActions = model.semanticActionButtons != null,
actionButtons = toActionViewModels(model),
outputSwitcher = toOutputSwitcherViewModel(model),
@@ -168,9 +160,7 @@ class MediaControlViewModel(
seekBarViewModel.updateStaticProgress(model.resumeProgress)
} else {
backgroundExecutor.execute {
- seekBarViewModel.updateController(
- model.token?.let { MediaController(applicationContext, it) }
- )
+ seekBarViewModel.updateController(mediaController)
}
}
}
@@ -283,16 +273,17 @@ class MediaControlViewModel(
)
}
- private fun toActionViewModels(model: MediaControlModel): List<MediaActionViewModel?> {
+ private fun toActionViewModels(model: MediaControlModel): List<MediaActionViewModel> {
val semanticActionButtons =
model.semanticActionButtons?.let { mediaButton ->
- with(mediaButton) {
- val isScrubbingTimeEnabled = canShowScrubbingTimeViews(mediaButton)
- SEMANTIC_ACTIONS_ALL.map { buttonId ->
- getActionById(buttonId)?.let {
- toSemanticActionViewModel(model, it, buttonId, isScrubbingTimeEnabled)
- }
- }
+ val isScrubbingTimeEnabled = canShowScrubbingTimeViews(mediaButton)
+ SEMANTIC_ACTIONS_ALL.map { buttonId ->
+ toSemanticActionViewModel(
+ model,
+ mediaButton.getActionById(buttonId),
+ buttonId,
+ isScrubbingTimeEnabled
+ )
}
}
val notifActionButtons =
@@ -304,7 +295,7 @@ class MediaControlViewModel(
private fun toSemanticActionViewModel(
model: MediaControlModel,
- mediaAction: MediaAction,
+ mediaAction: MediaAction?,
buttonId: Int,
canShowScrubbingTimeViews: Boolean
): MediaActionViewModel {
@@ -312,9 +303,9 @@ class MediaControlViewModel(
val hideWhenScrubbing = SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING.contains(buttonId)
val shouldHideWhenScrubbing = canShowScrubbingTimeViews && hideWhenScrubbing
return MediaActionViewModel(
- icon = mediaAction.icon,
- contentDescription = mediaAction.contentDescription,
- background = mediaAction.background,
+ icon = mediaAction?.icon,
+ contentDescription = mediaAction?.contentDescription,
+ background = mediaAction?.background,
isVisibleWhenScrubbing = !shouldHideWhenScrubbing,
notVisibleValue =
if (
@@ -326,11 +317,11 @@ class MediaControlViewModel(
ConstraintSet.GONE
},
showInCollapsed = showInCollapsed,
- rebindId = mediaAction.rebindId,
+ rebindId = mediaAction?.rebindId,
buttonId = buttonId,
- isEnabled = mediaAction.action != null,
+ isEnabled = mediaAction?.action != null,
onClicked = { id ->
- mediaAction.action?.let {
+ mediaAction?.action?.let {
onButtonClicked(id, model.uid, model.packageName, model.instanceId, it)
}
},
@@ -366,7 +357,7 @@ class MediaControlViewModel(
) {
logger.logTapAction(id, uid, packageName, instanceId)
// TODO (b/330897926) log smartspace card reported (SMARTSPACE_CARD_CLICK_EVENT)
- isAnyButtonClicked.value = true
+ isAnyButtonClicked = true
action.run()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt
index d1014e83ea11..433434129b96 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt
@@ -35,7 +35,7 @@ data class MediaPlayerViewModel(
val canShowTime: Boolean,
val playTurbulenceNoise: Boolean,
val useSemanticActions: Boolean,
- val actionButtons: List<MediaActionViewModel?>,
+ val actionButtons: List<MediaActionViewModel>,
val outputSwitcher: MediaOutputSwitcherViewModel,
val gutsMenu: GutsViewModel,
val onClicked: (Expandable) -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt
index 5c17fd1bf94e..3bda7757f8e5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt
@@ -20,9 +20,9 @@ import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.qs.panels.ui.viewmodel.EditModeViewModel
@Composable
@@ -30,8 +30,8 @@ fun EditMode(
viewModel: EditModeViewModel,
modifier: Modifier = Modifier,
) {
- val gridLayout by viewModel.gridLayout.collectAsState()
- val tiles by viewModel.tiles.collectAsState(emptyList())
+ val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle()
+ val tiles by viewModel.tiles.collectAsStateWithLifecycle(emptyList())
BackHandler { viewModel.stopEditing() }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
index dc43091e3c67..bac0f604e294 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
@@ -53,7 +53,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -72,6 +71,7 @@ import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.Expandable
import com.android.compose.theme.colorAttr
import com.android.systemui.common.shared.model.Icon
@@ -116,8 +116,8 @@ constructor(
tiles.forEach { it.startListening(token) }
onDispose { tiles.forEach { it.stopListening(token) } }
}
- val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsState()
- val columns by gridSizeInteractor.columns.collectAsState()
+ val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle()
+ val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle()
TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) {
items(
@@ -150,7 +150,7 @@ constructor(
val state: TileUiState by
tile.state
.mapLatest { it.toUiState() }
- .collectAsState(initial = tile.currentState.toUiState())
+ .collectAsStateWithLifecycle(initialValue = tile.currentState.toUiState())
val context = LocalContext.current
Expandable(
@@ -201,10 +201,13 @@ constructor(
val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState {
onAddTile(it, POSITION_AT_END)
}
- val iconOnlySpecs by iconTilesInteractor.iconTilesSpecs.collectAsState(initial = emptySet())
+ val iconOnlySpecs by
+ iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle(
+ initialValue = emptySet()
+ )
val isIconOnly: (TileSpec) -> Boolean =
remember(iconOnlySpecs) { { tileSpec: TileSpec -> tileSpec in iconOnlySpecs } }
- val columns by gridSizeInteractor.columns.collectAsState()
+ val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle()
TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) {
// These Text are just placeholders to see the different sections. Not final UI.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
index 2f32d7264350..2dab7c3d61ca 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
@@ -17,15 +17,15 @@
package com.android.systemui.qs.panels.ui.compose
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
@Composable
fun TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) {
- val gridLayout by viewModel.gridLayout.collectAsState()
- val tiles by viewModel.tileViewModels.collectAsState(emptyList())
+ val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle()
+ val tiles by viewModel.tileViewModels.collectAsStateWithLifecycle(emptyList())
gridLayout.TileGrid(tiles, modifier)
}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
index 4e290e699ac4..6694878cea74 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -20,7 +20,6 @@ import android.app.IActivityManager
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
-import android.content.pm.LauncherApps
import android.content.res.Resources
import android.net.Uri
import android.os.Handler
@@ -63,7 +62,6 @@ constructor(
private val panelInteractor: PanelInteractor,
private val issueRecordingState: IssueRecordingState,
private val iActivityManager: IActivityManager,
- private val launcherApps: LauncherApps,
) :
RecordingService(
controller,
@@ -85,7 +83,7 @@ constructor(
when (intent?.action) {
ACTION_START -> {
TraceUtils.traceStart(
- contentResolver,
+ this,
DEFAULT_TRACE_TAGS,
DEFAULT_BUFFER_SIZE,
DEFAULT_IS_INCLUDING_WINSCOPE,
@@ -104,11 +102,7 @@ constructor(
}
ACTION_STOP,
ACTION_STOP_NOTIF -> {
- // ViewCapture needs to save it's data before it is disabled, or else the data will
- // be lost. This is expected to change in the near future, and when that happens
- // this line should be removed.
- launcherApps.saveViewCaptureData()
- TraceUtils.traceStop(contentResolver)
+ TraceUtils.traceStop(this)
issueRecordingState.isRecording = false
}
ACTION_SHARE -> {
@@ -142,7 +136,7 @@ constructor(
private fun shareRecording(screenRecording: Uri?) {
val traces =
- TraceUtils.traceDump(contentResolver, TRACE_FILE_NAME).getOrElse {
+ TraceUtils.traceDump(this, TRACE_FILE_NAME).getOrElse {
Log.v(
TAG,
"Traces were not present. This can happen if users double" +
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
index caa67dff086f..1868b4a29f20 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
@@ -25,7 +25,6 @@ import android.content.Intent
import android.os.UserHandle
import android.util.Log
import android.util.Pair
-import android.view.View
import android.view.Window
import com.android.app.tracing.coroutines.launch
import com.android.internal.app.ChooserActivity
@@ -41,8 +40,8 @@ constructor(
private val intentExecutor: ActionIntentExecutor,
@Application private val applicationScope: CoroutineScope,
@Assisted val window: Window,
- @Assisted val transitionView: View,
- @Assisted val onDismiss: (() -> Unit)
+ @Assisted val viewProxy: ScreenshotViewProxy,
+ @Assisted val finishDismiss: () -> Unit,
) {
var isPendingSharedTransition = false
@@ -50,6 +49,7 @@ constructor(
fun startSharedTransition(intent: Intent, user: UserHandle, overrideTransition: Boolean) {
isPendingSharedTransition = true
+ viewProxy.fadeForSharedTransition()
val windowTransition = createWindowTransition()
applicationScope.launch("$TAG#launchIntentAsync") {
intentExecutor.launchIntent(
@@ -70,7 +70,7 @@ constructor(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
)
pendingIntent.send(options.toBundle())
- onDismiss.invoke()
+ viewProxy.requestDismissal(null)
} catch (e: PendingIntent.CanceledException) {
Log.e(TAG, "Intent cancelled", e)
}
@@ -89,7 +89,7 @@ constructor(
override fun hideSharedElements() {
isPendingSharedTransition = false
- onDismiss.invoke()
+ finishDismiss.invoke()
}
override fun onFinish() {}
@@ -98,13 +98,20 @@ constructor(
window,
callbacks,
null,
- Pair.create(transitionView, ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)
+ Pair.create(
+ viewProxy.screenshotPreview,
+ ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME
+ )
)
}
@AssistedFactory
interface Factory {
- fun create(window: Window, transitionView: View, onDismiss: (() -> Unit)): ActionExecutor
+ fun create(
+ window: Window,
+ viewProxy: ScreenshotViewProxy,
+ finishDismiss: (() -> Unit)
+ ): ActionExecutor
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
index a0cef529ecde..15638d3496e9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
@@ -97,6 +97,7 @@ object ActionIntentCreator {
.putExtra(LongScreenshotActivity.EXTRA_SCREENSHOT_USER_HANDLE, owner)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
}
private const val EXTRA_EDIT_SOURCE = "edit_source"
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index 4eca51d47a36..4ab09185fcdd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -33,10 +33,11 @@ import android.view.WindowManager
import android.view.WindowManagerGlobal
import com.android.app.tracing.coroutines.launch
import com.android.internal.infra.ServiceConnector
-import com.android.systemui.Flags.screenshotActionDismissSystemWindows
+import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.screenshot.proxy.SystemUiProxy
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -54,8 +55,8 @@ constructor(
private val activityManagerWrapper: ActivityManagerWrapper,
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
+ private val systemUiProxy: SystemUiProxy,
private val displayTracker: DisplayTracker,
- private val keyguardController: ScreenshotKeyguardController,
) {
/**
* Execute the given intent with startActivity while performing operations for screenshot action
@@ -83,14 +84,12 @@ constructor(
options: ActivityOptions?,
transitionCoordinator: ExitTransitionCoordinator?,
) {
- if (screenshotActionDismissSystemWindows()) {
- keyguardController.dismiss()
+ if (Flags.fixScreenshotActionDismissSystemWindows()) {
activityManagerWrapper.closeSystemWindows(
CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT
)
- } else {
- dismissKeyguard()
}
+ systemUiProxy.dismissKeyguard()
transitionCoordinator?.startExit()
if (user == myUserHandle()) {
@@ -110,27 +109,6 @@ constructor(
}
}
- private val proxyConnector: ServiceConnector<IScreenshotProxy> =
- ServiceConnector.Impl(
- context,
- Intent(context, ScreenshotProxyService::class.java),
- Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
- context.userId,
- IScreenshotProxy.Stub::asInterface,
- )
-
- private suspend fun dismissKeyguard() {
- val completion = CompletableDeferred<Unit>()
- val onDoneBinder =
- object : IOnDoneCallback.Stub() {
- override fun onDone(success: Boolean) {
- completion.complete(Unit)
- }
- }
- proxyConnector.post { it.dismissKeyguard(onDoneBinder) }
- completion.await()
- }
-
private fun getCrossProfileConnector(user: UserHandle): ServiceConnector<ICrossProfileService> =
ServiceConnector.Impl<ICrossProfileService>(
context,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
index 4cf18fb482d8..3d024a6a8ccf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
@@ -157,6 +157,8 @@ constructor(
override fun restoreNonScrollingUi() = view.restoreNonScrollingUi()
+ override fun fadeForSharedTransition() {} // unused
+
override fun stopInputListening() = view.stopInputListening()
override fun requestFocus() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 2f026aee64d8..9ad6d0faea88 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -317,9 +317,9 @@ public class ScreenshotController {
mConfigChanges.applyNewConfig(context.getResources());
reloadAssets();
- mActionExecutor = actionExecutorFactory.create(mWindow, mViewProxy.getScreenshotPreview(),
+ mActionExecutor = actionExecutorFactory.create(mWindow, mViewProxy,
() -> {
- requestDismissal(null);
+ finishDismiss();
return Unit.INSTANCE;
});
@@ -623,9 +623,11 @@ public class ScreenshotController {
(response) -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION,
0, response.getPackageName());
- if (screenshotShelfUi2() && mActionsProvider != null) {
- mActionsProvider.onScrollChipReady(
- () -> onScrollButtonClicked(owner, response));
+ if (screenshotShelfUi2()) {
+ if (mActionsProvider != null) {
+ mActionsProvider.onScrollChipReady(
+ () -> onScrollButtonClicked(owner, response));
+ }
} else {
mViewProxy.showScrollChip(response.getPackageName(),
() -> onScrollButtonClicked(owner, response));
@@ -657,9 +659,7 @@ public class ScreenshotController {
() -> {
final Intent intent = ActionIntentCreator.INSTANCE.createLongScreenshotIntent(
owner, mContext);
- mActionIntentExecutor.launchIntentAsync(intent, owner, true,
- ActivityOptions.makeCustomAnimation(mContext, 0, 0), null);
-
+ mActionIntentExecutor.launchIntentAsync(intent, owner, true, null, null);
},
mViewProxy::restoreNonScrollingUi,
mViewProxy::startLongScreenshotTransition);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt
deleted file mode 100644
index 7696bbe3763e..000000000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.screenshot
-
-import android.content.Context
-import android.content.Intent
-import com.android.internal.infra.ServiceConnector
-import javax.inject.Inject
-import kotlinx.coroutines.CompletableDeferred
-
-open class ScreenshotKeyguardController @Inject constructor(context: Context) {
- private val proxyConnector: ServiceConnector<IScreenshotProxy> =
- ServiceConnector.Impl(
- context,
- Intent(context, ScreenshotProxyService::class.java),
- Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
- context.userId,
- IScreenshotProxy.Stub::asInterface
- )
-
- suspend fun dismiss() {
- val completion = CompletableDeferred<Unit>()
- val onDoneBinder =
- object : IOnDoneCallback.Stub() {
- override fun onDone(success: Boolean) {
- completion.complete(Unit)
- }
- }
- proxyConnector.post { it.dismissKeyguard(onDoneBinder) }
- completion.await()
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
index 1e66cd10cc61..3ac070a28b2b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
@@ -31,6 +31,7 @@ import android.view.WindowInsets
import android.view.WindowManager
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
+import androidx.appcompat.content.res.AppCompatResources
import androidx.core.animation.doOnEnd
import androidx.core.animation.doOnStart
import com.android.internal.logging.UiEventLogger
@@ -58,6 +59,7 @@ constructor(
private val logger: UiEventLogger,
private val viewModel: ScreenshotViewModel,
private val windowManager: WindowManager,
+ shelfViewBinder: ScreenshotShelfViewBinder,
private val thumbnailObserver: ThumbnailObserver,
@Assisted private val context: Context,
@Assisted private val displayId: Int
@@ -69,7 +71,17 @@ constructor(
override var callbacks: ScreenshotView.ScreenshotViewCallback? = null
override var screenshot: ScreenshotData? = null
set(value) {
- viewModel.setScreenshotBitmap(value?.bitmap)
+ value?.let {
+ viewModel.setScreenshotBitmap(it.bitmap)
+ val badgeBg =
+ AppCompatResources.getDrawable(context, R.drawable.overlay_badge_background)
+ val user = it.userHandle
+ if (badgeBg != null && user != null) {
+ viewModel.setScreenshotBadge(
+ context.packageManager.getUserBadgedIcon(badgeBg, user)
+ )
+ }
+ }
field = value
}
@@ -78,15 +90,15 @@ constructor(
override var isDismissing = false
override var isPendingSharedTransition = false
- private val animationController = ScreenshotAnimationController(view)
+ private val animationController = ScreenshotAnimationController(view, viewModel)
init {
- ScreenshotShelfViewBinder.bind(
+ shelfViewBinder.bind(
view,
viewModel,
+ animationController,
LayoutInflater.from(context),
onDismissalRequested = { event, velocity -> requestDismissal(event, velocity) },
- onDismissalCancelled = { animationController.getSwipeReturnAnimation().start() },
onUserInteraction = { callbacks?.onUserInteraction() }
)
view.updateInsets(windowManager.currentWindowMetrics.windowInsets)
@@ -176,24 +188,53 @@ constructor(
override fun prepareScrollingTransition(
response: ScrollCaptureResponse,
- screenBitmap: Bitmap,
+ screenBitmap: Bitmap, // unused
newScreenshot: Bitmap,
screenshotTakenInPortrait: Boolean,
onTransitionPrepared: Runnable,
) {
- onTransitionPrepared.run()
+ viewModel.setScrollingScrimBitmap(newScreenshot)
+ viewModel.setScrollableRect(scrollableAreaOnScreen(response))
+ animationController.fadeForLongScreenshotTransition()
+ view.post { onTransitionPrepared.run() }
+ }
+
+ private fun scrollableAreaOnScreen(response: ScrollCaptureResponse): Rect {
+ val r = Rect(response.boundsInWindow)
+ val windowInScreen = response.windowBounds
+ r.offset(windowInScreen?.left ?: 0, windowInScreen?.top ?: 0)
+ r.intersect(
+ Rect(
+ 0,
+ 0,
+ context.resources.displayMetrics.widthPixels,
+ context.resources.displayMetrics.heightPixels
+ )
+ )
+ return r
}
override fun startLongScreenshotTransition(
transitionDestination: Rect,
onTransitionEnd: Runnable,
- longScreenshot: ScrollCaptureController.LongScreenshot
+ longScreenshot: ScrollCaptureController.LongScreenshot,
) {
- onTransitionEnd.run()
- callbacks?.onDismiss()
+ val transitionAnimation =
+ animationController.runLongScreenshotTransition(
+ transitionDestination,
+ longScreenshot,
+ onTransitionEnd
+ )
+ transitionAnimation.doOnEnd { callbacks?.onDismiss() }
+ transitionAnimation.start()
}
- override fun restoreNonScrollingUi() {}
+ override fun restoreNonScrollingUi() {
+ viewModel.setScrollableRect(null)
+ viewModel.setScrollingScrimBitmap(null)
+ animationController.restoreUI()
+ callbacks?.onUserInteraction() // reset the timeout
+ }
override fun stopInputListening() {}
@@ -216,6 +257,10 @@ constructor(
)
}
+ override fun fadeForSharedTransition() {
+ animationController.fadeForSharedTransition()
+ }
+
private fun addPredictiveBackListener(onDismissRequested: (ScreenshotEvent) -> Unit) {
val onBackInvokedCallback = OnBackInvokedCallback {
debugLog(DEBUG_INPUT) { "Predictive Back callback dispatched" }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
index a4069d11f8fb..df93a5e56c22 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
@@ -63,6 +63,7 @@ interface ScreenshotViewProxy {
longScreenshot: ScrollCaptureController.LongScreenshot
)
fun restoreNonScrollingUi()
+ fun fadeForSharedTransition()
fun stopInputListening()
fun requestFocus()
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
index 06e88f46c5f1..a4906c12b487 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
@@ -20,6 +20,10 @@ import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
+import android.content.res.ColorStateList
+import android.graphics.BlendMode
+import android.graphics.Color
+import android.graphics.Matrix
import android.graphics.PointF
import android.graphics.Rect
import android.util.MathUtils
@@ -29,13 +33,21 @@ import android.widget.ImageView
import androidx.core.animation.doOnEnd
import androidx.core.animation.doOnStart
import com.android.systemui.res.R
+import com.android.systemui.screenshot.scroll.ScrollCaptureController
+import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.sign
-class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
+class ScreenshotAnimationController(
+ private val view: ScreenshotShelfView,
+ private val viewModel: ScreenshotViewModel
+) {
private var animator: Animator? = null
private val screenshotPreview = view.requireViewById<ImageView>(R.id.screenshot_preview)
+ private val scrollingScrim = view.requireViewById<ImageView>((R.id.screenshot_scrolling_scrim))
+ private val scrollTransitionPreview =
+ view.requireViewById<ImageView>(R.id.screenshot_scrollable_preview)
private val flashView = view.requireViewById<View>(R.id.screenshot_flash)
private val actionContainer = view.requireViewById<View>(R.id.actions_container_background)
private val fastOutSlowIn =
@@ -46,6 +58,14 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
view.requireViewById(R.id.screenshot_badge),
view.requireViewById(R.id.screenshot_dismiss_button)
)
+ private val fadeUI =
+ listOf<View>(
+ view.requireViewById(R.id.screenshot_preview_border),
+ view.requireViewById(R.id.actions_container_background),
+ view.requireViewById(R.id.screenshot_badge),
+ view.requireViewById(R.id.screenshot_dismiss_button),
+ view.requireViewById(R.id.screenshot_message_container),
+ )
fun getEntranceAnimation(
bounds: Rect,
@@ -96,15 +116,108 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
}
entranceAnimation.play(fadeInAnimator).after(previewAnimator)
entranceAnimation.doOnStart {
+ viewModel.setIsAnimating(true)
for (child in staticUI) {
child.alpha = 0f
}
}
+ entranceAnimation.doOnEnd { viewModel.setIsAnimating(false) }
this.animator = entranceAnimation
return entranceAnimation
}
+ fun fadeForSharedTransition() {
+ animator?.cancel()
+ val fadeAnimator = ValueAnimator.ofFloat(1f, 0f)
+ fadeAnimator.addUpdateListener {
+ for (view in fadeUI) {
+ view.alpha = it.animatedValue as Float
+ }
+ }
+ animator = fadeAnimator
+ fadeAnimator.start()
+ }
+
+ fun runLongScreenshotTransition(
+ destRect: Rect,
+ longScreenshot: ScrollCaptureController.LongScreenshot,
+ onTransitionEnd: Runnable
+ ): Animator {
+ val animSet = AnimatorSet()
+
+ val scrimAnim = ValueAnimator.ofFloat(0f, 1f)
+ scrimAnim.addUpdateListener { animation: ValueAnimator ->
+ scrollingScrim.setAlpha(1 - animation.animatedFraction)
+ }
+ scrollTransitionPreview.visibility = View.VISIBLE
+ if (true) {
+ scrollTransitionPreview.setImageBitmap(longScreenshot.toBitmap())
+ val startX: Float = scrollTransitionPreview.x
+ val startY: Float = scrollTransitionPreview.y
+ val locInScreen: IntArray = scrollTransitionPreview.getLocationOnScreen()
+ destRect.offset(startX.toInt() - locInScreen[0], startY.toInt() - locInScreen[1])
+ scrollTransitionPreview.pivotX = 0f
+ scrollTransitionPreview.pivotY = 0f
+ scrollTransitionPreview.setAlpha(1f)
+ val currentScale: Float = scrollTransitionPreview.width / longScreenshot.width.toFloat()
+ val matrix = Matrix()
+ matrix.setScale(currentScale, currentScale)
+ matrix.postTranslate(
+ longScreenshot.left * currentScale,
+ longScreenshot.top * currentScale
+ )
+ scrollTransitionPreview.setImageMatrix(matrix)
+ val destinationScale: Float = destRect.width() / scrollTransitionPreview.width.toFloat()
+ val previewAnim = ValueAnimator.ofFloat(0f, 1f)
+ previewAnim.addUpdateListener { animation: ValueAnimator ->
+ val t = animation.animatedFraction
+ val currScale = MathUtils.lerp(1f, destinationScale, t)
+ scrollTransitionPreview.scaleX = currScale
+ scrollTransitionPreview.scaleY = currScale
+ scrollTransitionPreview.x = MathUtils.lerp(startX, destRect.left.toFloat(), t)
+ scrollTransitionPreview.y = MathUtils.lerp(startY, destRect.top.toFloat(), t)
+ }
+ val previewFadeAnim = ValueAnimator.ofFloat(1f, 0f)
+ previewFadeAnim.addUpdateListener { animation: ValueAnimator ->
+ scrollTransitionPreview.setAlpha(1 - animation.animatedFraction)
+ }
+ previewAnim.doOnEnd { onTransitionEnd.run() }
+ animSet.play(previewAnim).with(scrimAnim).before(previewFadeAnim)
+ } else {
+ // if we switched orientations between the original screenshot and the long screenshot
+ // capture, just fade out the scrim instead of running the preview animation
+ scrimAnim.doOnEnd { onTransitionEnd.run() }
+ animSet.play(scrimAnim)
+ }
+ animator = animSet
+ return animSet
+ }
+
+ fun fadeForLongScreenshotTransition() {
+ scrollingScrim.imageTintBlendMode = BlendMode.SRC_ATOP
+ val anim = ValueAnimator.ofFloat(0f, .3f)
+ anim.addUpdateListener {
+ scrollingScrim.setImageTintList(
+ ColorStateList.valueOf(Color.argb(it.animatedValue as Float, 0f, 0f, 0f))
+ )
+ }
+ for (view in fadeUI) {
+ view.alpha = 0f
+ }
+ screenshotPreview.alpha = 0f
+ anim.setDuration(200)
+ anim.start()
+ }
+
+ fun restoreUI() {
+ animator?.cancel()
+ for (view in fadeUI) {
+ view.alpha = 1f
+ }
+ screenshotPreview.alpha = 1f
+ }
+
fun getSwipeReturnAnimation(): Animator {
animator?.cancel()
val animator = ValueAnimator.ofFloat(view.translationX, 0f)
@@ -114,6 +227,7 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
}
fun getSwipeDismissAnimation(requestedVelocity: Float?): Animator {
+ animator?.cancel()
val velocity = getAdjustedVelocity(requestedVelocity)
val screenWidth = view.resources.displayMetrics.widthPixels
// translation at which point the visible UI is fully off the screen (in the direction
@@ -131,6 +245,8 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
view.alpha = 1f - it.animatedFraction
}
animator.duration = ((abs(distance / velocity))).toLong()
+ animator.doOnStart { viewModel.setIsAnimating(true) }
+ animator.doOnEnd { viewModel.setIsAnimating(false) }
this.animator = animator
return animator
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
index 2243ade27b2e..36aa39fa9fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
@@ -23,8 +23,9 @@ import android.widget.TextView
import com.android.systemui.res.R
import com.android.systemui.screenshot.ui.TransitioningIconDrawable
import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel
+import javax.inject.Inject
-object ActionButtonViewBinder {
+class ActionButtonViewBinder @Inject constructor() {
/** Binds the given view to the given view-model */
fun bind(view: View, viewModel: ActionButtonViewModel) {
val iconView = view.requireViewById<ImageView>(R.id.overlay_action_chip_icon)
@@ -36,6 +37,10 @@ object ActionButtonViewBinder {
// Note we never re-bind a view to a different ActionButtonViewModel, different view
// models would remove/create separate views.
drawable?.setIcon(viewModel.appearance.icon)
+ iconView.setImageDrawable(viewModel.appearance.icon)
+ if (!viewModel.appearance.tint) {
+ iconView.setImageTintList(null)
+ }
textView.text = viewModel.appearance.label
viewModel.appearance.customBackground?.also {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
index 89f904a0878f..442b3873be4d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
@@ -16,7 +16,11 @@
package com.android.systemui.screenshot.ui.binder
+import android.content.res.Configuration
import android.graphics.Bitmap
+import android.graphics.Matrix
+import android.graphics.Rect
+import android.util.LayoutDirection
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -29,22 +33,26 @@ import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.screenshot.ScreenshotEvent
+import com.android.systemui.screenshot.ui.ScreenshotAnimationController
import com.android.systemui.screenshot.ui.ScreenshotShelfView
import com.android.systemui.screenshot.ui.SwipeGestureListener
import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel
import com.android.systemui.screenshot.ui.viewmodel.AnimationState
import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
import com.android.systemui.util.children
+import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-object ScreenshotShelfViewBinder {
+class ScreenshotShelfViewBinder
+@Inject
+constructor(private val buttonViewBinder: ActionButtonViewBinder) {
fun bind(
view: ScreenshotShelfView,
viewModel: ScreenshotViewModel,
+ animationController: ScreenshotAnimationController,
layoutInflater: LayoutInflater,
onDismissalRequested: (event: ScreenshotEvent, velocity: Float?) -> Unit,
- onDismissalCancelled: () -> Unit,
onUserInteraction: () -> Unit
) {
val swipeGestureListener =
@@ -53,7 +61,7 @@ object ScreenshotShelfViewBinder {
onDismiss = {
onDismissalRequested(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, it)
},
- onCancel = onDismissalCancelled
+ onCancel = { animationController.getSwipeReturnAnimation().start() }
)
view.onTouchInterceptListener = { swipeGestureListener.onMotionEvent(it) }
view.userInteractionCallback = onUserInteraction
@@ -63,11 +71,15 @@ object ScreenshotShelfViewBinder {
val previewBorder = view.requireViewById<View>(R.id.screenshot_preview_border)
previewView.clipToOutline = true
previewViewBlur.clipToOutline = true
+ val actionsContainer: LinearLayout = view.requireViewById(R.id.screenshot_actions)
val dismissButton = view.requireViewById<View>(R.id.screenshot_dismiss_button)
dismissButton.visibility = if (viewModel.showDismissButton) View.VISIBLE else View.GONE
dismissButton.setOnClickListener {
onDismissalRequested(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL, null)
}
+ val scrollingScrim: ImageView = view.requireViewById(R.id.screenshot_scrolling_scrim)
+ val scrollablePreview: ImageView = view.requireViewById(R.id.screenshot_scrollable_preview)
+ val badgeView = view.requireViewById<ImageView>(R.id.screenshot_badge)
// use immediate dispatcher to ensure screenshot bitmap is set before animation
view.repeatWhenAttached(Dispatchers.Main.immediate) {
@@ -87,11 +99,48 @@ object ScreenshotShelfViewBinder {
}
}
launch {
+ viewModel.scrollingScrim.collect { bitmap ->
+ if (bitmap != null) {
+ scrollingScrim.setImageBitmap(bitmap)
+ scrollingScrim.visibility = View.VISIBLE
+ } else {
+ scrollingScrim.visibility = View.GONE
+ }
+ }
+ }
+ launch {
+ viewModel.scrollableRect.collect { rect ->
+ if (rect != null) {
+ setScrollablePreview(
+ scrollablePreview,
+ viewModel.preview.value,
+ rect
+ )
+ } else {
+ scrollablePreview.visibility = View.GONE
+ }
+ }
+ }
+ launch {
+ viewModel.badge.collect { badge ->
+ badgeView.setImageDrawable(badge)
+ badgeView.visibility = if (badge != null) View.VISIBLE else View.GONE
+ }
+ }
+ launch {
viewModel.previewAction.collect { onClick ->
previewView.setOnClickListener { onClick?.invoke() }
}
}
launch {
+ viewModel.isAnimating.collect { isAnimating ->
+ previewView.isClickable = !isAnimating
+ for (child in actionsContainer.children) {
+ child.isClickable = !isAnimating
+ }
+ }
+ }
+ launch {
viewModel.actions.collect { actions ->
updateActions(
actions,
@@ -151,14 +200,14 @@ object ScreenshotShelfViewBinder {
val currentView: View? = actionsContainer.getChildAt(index)
if (action.id == currentView?.tag) {
// Same ID, update the display
- ActionButtonViewBinder.bind(currentView, action)
+ buttonViewBinder.bind(currentView, action)
} else {
// Different ID. Removals have already happened so this must
// mean that the new action must be inserted here.
val actionButton =
layoutInflater.inflate(R.layout.shelf_action_chip, actionsContainer, false)
actionsContainer.addView(actionButton, index)
- ActionButtonViewBinder.bind(actionButton, action)
+ buttonViewBinder.bind(actionButton, action)
}
}
}
@@ -181,4 +230,35 @@ object ScreenshotShelfViewBinder {
screenshotPreview.layoutParams = params
screenshotPreview.requestLayout()
}
+
+ private fun setScrollablePreview(
+ scrollablePreview: ImageView,
+ bitmap: Bitmap?,
+ scrollableRect: Rect
+ ) {
+ if (bitmap == null) {
+ return
+ }
+ val fixedSize = scrollablePreview.resources.getDimensionPixelSize(R.dimen.overlay_x_scale)
+ val inPortrait =
+ scrollablePreview.resources.configuration.orientation ==
+ Configuration.ORIENTATION_PORTRAIT
+ val scale: Float = fixedSize / ((if (inPortrait) bitmap.width else bitmap.height).toFloat())
+ val params = scrollablePreview.layoutParams
+
+ params.width = (scale * scrollableRect.width()).toInt()
+ params.height = (scale * scrollableRect.height()).toInt()
+ val matrix = Matrix()
+ matrix.setScale(scale, scale)
+ matrix.postTranslate(-scrollableRect.left * scale, -scrollableRect.top * scale)
+
+ scrollablePreview.translationX =
+ (scale *
+ if (scrollablePreview.layoutDirection == LayoutDirection.LTR) scrollableRect.left
+ else scrollableRect.right - (scrollablePreview.parent as View).width)
+ scrollablePreview.translationY = scale * scrollableRect.top
+ scrollablePreview.setImageMatrix(matrix)
+ scrollablePreview.setImageBitmap(bitmap)
+ scrollablePreview.setVisibility(View.VISIBLE)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt
index 2982ea011825..42ad326c6b45 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt
@@ -25,5 +25,6 @@ constructor(
val icon: Drawable?,
val label: CharSequence?,
val description: CharSequence,
+ val tint: Boolean = true,
val customBackground: Drawable? = null,
)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
index 5f36f73f2135..3f99bc4597cb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
@@ -17,6 +17,8 @@
package com.android.systemui.screenshot.ui.viewmodel
import android.graphics.Bitmap
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
import android.util.Log
import android.view.accessibility.AccessibilityManager
import kotlinx.coroutines.flow.MutableStateFlow
@@ -25,6 +27,10 @@ import kotlinx.coroutines.flow.StateFlow
class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager) {
private val _preview = MutableStateFlow<Bitmap?>(null)
val preview: StateFlow<Bitmap?> = _preview
+ private val _scrollingScrim = MutableStateFlow<Bitmap?>(null)
+ val scrollingScrim: StateFlow<Bitmap?> = _scrollingScrim
+ private val _badge = MutableStateFlow<Drawable?>(null)
+ val badge: StateFlow<Drawable?> = _badge
private val _previewAction = MutableStateFlow<(() -> Unit)?>(null)
val previewAction: StateFlow<(() -> Unit)?> = _previewAction
private val _actions = MutableStateFlow(emptyList<ActionButtonViewModel>())
@@ -32,6 +38,10 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager
private val _animationState = MutableStateFlow(AnimationState.NOT_STARTED)
val animationState: StateFlow<AnimationState> = _animationState
+ private val _isAnimating = MutableStateFlow(false)
+ val isAnimating: StateFlow<Boolean> = _isAnimating
+ private val _scrollableRect = MutableStateFlow<Rect?>(null)
+ val scrollableRect: StateFlow<Rect?> = _scrollableRect
val showDismissButton: Boolean
get() = accessibilityManager.isEnabled
@@ -39,6 +49,14 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager
_preview.value = bitmap
}
+ fun setScrollingScrimBitmap(bitmap: Bitmap?) {
+ _scrollingScrim.value = bitmap
+ }
+
+ fun setScreenshotBadge(badge: Drawable?) {
+ _badge.value = badge
+ }
+
fun setPreviewAction(onClick: () -> Unit) {
_previewAction.value = onClick
}
@@ -107,11 +125,23 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager
_animationState.value = state
}
+ fun setIsAnimating(isAnimating: Boolean) {
+ _isAnimating.value = isAnimating
+ }
+
+ fun setScrollableRect(rect: Rect?) {
+ _scrollableRect.value = rect
+ }
+
fun reset() {
_preview.value = null
+ _scrollingScrim.value = null
+ _badge.value = null
_previewAction.value = null
_actions.value = listOf()
_animationState.value = AnimationState.NOT_STARTED
+ _isAnimating.value = false
+ _scrollableRect.value = null
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index 3d0fd89dce88..af2c1979ff77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -31,8 +31,10 @@ import com.android.systemui.statusbar.notification.dagger.PeopleHeader
import com.android.systemui.statusbar.notification.icon.ConversationIconManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.BUCKET_PRIORITY_PEOPLE
import javax.inject.Inject
/**
@@ -81,6 +83,13 @@ class ConversationCoordinator @Inject constructor(
}
}
+ val priorityPeopleSectioner =
+ object : NotifSectioner("Priority People", BUCKET_PRIORITY_PEOPLE) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ return getPeopleType(entry) == TYPE_IMPORTANT_PERSON
+ }
+ }
+
// TODO(b/330193582): Rename to just "People"
val peopleAlertingSectioner = object : NotifSectioner("People(alerting)", BUCKET_PEOPLE) {
override fun isInSection(entry: ListEntry): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 933eb207e76d..42bf4e7d0787 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -31,15 +31,20 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.expansionChanges
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
+import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.headsUpEvents
import com.android.systemui.util.asIndenting
@@ -106,6 +111,10 @@ constructor(
}
private fun attachUnseenFilter(pipeline: NotifPipeline) {
+ if (NotificationMinimalismPrototype.V2.isEnabled) {
+ pipeline.addPromoter(unseenNotifPromoter)
+ pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotif)
+ }
pipeline.addFinalizeFilter(unseenNotifFilter)
pipeline.addCollectionListener(collectionListener)
scope.launch { trackUnseenFilterSettingChanges() }
@@ -263,7 +272,10 @@ constructor(
}
private fun unseenFeatureEnabled(): Flow<Boolean> {
- if (NotificationMinimalismPrototype.V1.isEnabled) {
+ if (
+ NotificationMinimalismPrototype.V1.isEnabled ||
+ NotificationMinimalismPrototype.V2.isEnabled
+ ) {
return flowOf(true)
}
return secureSettings
@@ -334,6 +346,57 @@ constructor(
}
}
+ private fun pickOutTopUnseenNotif(list: List<ListEntry>) {
+ if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return
+ // Only ever elevate a top unseen notification on keyguard, not even locked shade
+ if (statusBarStateController.state != StatusBarState.KEYGUARD) {
+ seenNotificationsInteractor.setTopUnseenNotification(null)
+ return
+ }
+ // On keyguard pick the top-ranked unseen or ongoing notification to elevate
+ seenNotificationsInteractor.setTopUnseenNotification(
+ list
+ .asSequence()
+ .flatMap {
+ when (it) {
+ is NotificationEntry -> listOfNotNull(it)
+ is GroupEntry -> it.children
+ else -> error("unhandled type of $it")
+ }
+ }
+ .filter { shouldIgnoreUnseenCheck(it) || it in unseenNotifications }
+ .minByOrNull { it.ranking.rank }
+ )
+ }
+
+ @VisibleForTesting
+ internal val unseenNotifPromoter =
+ object : NotifPromoter("$TAG-unseen") {
+ override fun shouldPromoteToTopLevel(child: NotificationEntry): Boolean =
+ if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false
+ else
+ seenNotificationsInteractor.isTopUnseenNotification(child) &&
+ NotificationMinimalismPrototype.V2.ungroupTopUnseen
+ }
+
+ val unseenNotifSectioner =
+ object : NotifSectioner("Unseen", BUCKET_FOREGROUND_SERVICE) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false
+ if (
+ seenNotificationsInteractor.isTopUnseenNotification(entry.representativeEntry)
+ ) {
+ return true
+ }
+ if (entry !is GroupEntry) {
+ return false
+ }
+ return entry.children.any {
+ seenNotificationsInteractor.isTopUnseenNotification(it)
+ }
+ }
+ }
+
@VisibleForTesting
internal val unseenNotifFilter =
object : NotifFilter("$TAG-unseen") {
@@ -351,7 +414,9 @@ constructor(
* allow seen notifications to appear in the locked shade.
*/
private fun isOnKeyguard(): Boolean =
- if (
+ if (NotificationMinimalismPrototype.V2.isEnabled) {
+ false // disable this feature under this prototype
+ } else if (
NotificationMinimalismPrototype.V1.isEnabled &&
NotificationMinimalismPrototype.V1.showOnLockedShade
) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 36c12a719570..4506385a2fb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -24,47 +24,51 @@ import com.android.systemui.statusbar.notification.collection.SortBySectionTimeF
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
+import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
import javax.inject.Inject
/**
- * Handles the attachment of [Coordinator]s to the [NotifPipeline] so that the
- * Coordinators can register their respective callbacks.
+ * Handles the attachment of [Coordinator]s to the [NotifPipeline] so that the Coordinators can
+ * register their respective callbacks.
*/
interface NotifCoordinators : Coordinator, PipelineDumpable
@CoordinatorScope
-class NotifCoordinatorsImpl @Inject constructor(
- sectionStyleProvider: SectionStyleProvider,
- featureFlags: FeatureFlags,
- dataStoreCoordinator: DataStoreCoordinator,
- hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
- hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
- keyguardCoordinator: KeyguardCoordinator,
- rankingCoordinator: RankingCoordinator,
- colorizedFgsCoordinator: ColorizedFgsCoordinator,
- deviceProvisionedCoordinator: DeviceProvisionedCoordinator,
- bubbleCoordinator: BubbleCoordinator,
- headsUpCoordinator: HeadsUpCoordinator,
- gutsCoordinator: GutsCoordinator,
- conversationCoordinator: ConversationCoordinator,
- debugModeCoordinator: DebugModeCoordinator,
- groupCountCoordinator: GroupCountCoordinator,
- groupWhenCoordinator: GroupWhenCoordinator,
- mediaCoordinator: MediaCoordinator,
- preparationCoordinator: PreparationCoordinator,
- remoteInputCoordinator: RemoteInputCoordinator,
- rowAlertTimeCoordinator: RowAlertTimeCoordinator,
- rowAppearanceCoordinator: RowAppearanceCoordinator,
- stackCoordinator: StackCoordinator,
- shadeEventCoordinator: ShadeEventCoordinator,
- smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
- viewConfigCoordinator: ViewConfigCoordinator,
- visualStabilityCoordinator: VisualStabilityCoordinator,
- sensitiveContentCoordinator: SensitiveContentCoordinator,
- dismissibilityCoordinator: DismissibilityCoordinator,
- dreamCoordinator: DreamCoordinator,
- statsLoggerCoordinator: NotificationStatsLoggerCoordinator,
+class NotifCoordinatorsImpl
+@Inject
+constructor(
+ sectionStyleProvider: SectionStyleProvider,
+ featureFlags: FeatureFlags,
+ dataStoreCoordinator: DataStoreCoordinator,
+ hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
+ hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
+ keyguardCoordinator: KeyguardCoordinator,
+ rankingCoordinator: RankingCoordinator,
+ colorizedFgsCoordinator: ColorizedFgsCoordinator,
+ deviceProvisionedCoordinator: DeviceProvisionedCoordinator,
+ bubbleCoordinator: BubbleCoordinator,
+ headsUpCoordinator: HeadsUpCoordinator,
+ gutsCoordinator: GutsCoordinator,
+ conversationCoordinator: ConversationCoordinator,
+ debugModeCoordinator: DebugModeCoordinator,
+ groupCountCoordinator: GroupCountCoordinator,
+ groupWhenCoordinator: GroupWhenCoordinator,
+ mediaCoordinator: MediaCoordinator,
+ preparationCoordinator: PreparationCoordinator,
+ remoteInputCoordinator: RemoteInputCoordinator,
+ rowAlertTimeCoordinator: RowAlertTimeCoordinator,
+ rowAppearanceCoordinator: RowAppearanceCoordinator,
+ stackCoordinator: StackCoordinator,
+ shadeEventCoordinator: ShadeEventCoordinator,
+ smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
+ viewConfigCoordinator: ViewConfigCoordinator,
+ visualStabilityCoordinator: VisualStabilityCoordinator,
+ sensitiveContentCoordinator: SensitiveContentCoordinator,
+ dismissibilityCoordinator: DismissibilityCoordinator,
+ dreamCoordinator: DreamCoordinator,
+ statsLoggerCoordinator: NotificationStatsLoggerCoordinator,
) : NotifCoordinators {
private val mCoreCoordinators: MutableList<CoreCoordinator> = ArrayList()
@@ -114,6 +118,12 @@ class NotifCoordinatorsImpl @Inject constructor(
// Manually add Ordered Sections
mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp
mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService
+ if (NotificationMinimalismPrototype.V2.isEnabled) {
+ mOrderedSections.add(keyguardCoordinator.unseenNotifSectioner) // Unseen (FGS)
+ }
+ if (PriorityPeopleSection.isEnabled) {
+ mOrderedSections.add(conversationCoordinator.priorityPeopleSectioner) // Priority People
+ }
mOrderedSections.add(conversationCoordinator.peopleAlertingSectioner) // People Alerting
if (!SortBySectionTimeFlag.isEnabled) {
mOrderedSections.add(conversationCoordinator.peopleSilentSectioner) // People Silent
@@ -124,22 +134,26 @@ class NotifCoordinatorsImpl @Inject constructor(
sectionStyleProvider.setMinimizedSections(setOf(rankingCoordinator.minimizedSectioner))
if (SortBySectionTimeFlag.isEnabled) {
- sectionStyleProvider.setSilentSections(listOf(
+ sectionStyleProvider.setSilentSections(
+ listOf(
rankingCoordinator.silentSectioner,
rankingCoordinator.minimizedSectioner,
- ))
+ )
+ )
} else {
- sectionStyleProvider.setSilentSections(listOf(
+ sectionStyleProvider.setSilentSections(
+ listOf(
conversationCoordinator.peopleSilentSectioner,
rankingCoordinator.silentSectioner,
rankingCoordinator.minimizedSectioner,
- ))
+ )
+ )
}
}
/**
- * Sends the pipeline to each coordinator when the pipeline is ready to accept
- * [Pluggable]s, [NotifCollectionListener]s and [NotifLifetimeExtender]s.
+ * Sends the pipeline to each coordinator when the pipeline is ready to accept [Pluggable]s,
+ * [NotifCollectionListener]s and [NotifLifetimeExtender]s.
*/
override fun attach(pipeline: NotifPipeline) {
for (c in mCoreCoordinators) {
@@ -155,10 +169,11 @@ class NotifCoordinatorsImpl @Inject constructor(
* As part of the NotifPipeline dumpable, dumps the list of coordinators; sections are omitted
* as they are dumped in the RenderStageManager instead.
*/
- override fun dumpPipeline(d: PipelineDumper) = with(d) {
- dump("core coordinators", mCoreCoordinators)
- dump("normal coordinators", mCoordinators)
- }
+ override fun dumpPipeline(d: PipelineDumper) =
+ with(d) {
+ dump("core coordinators", mCoreCoordinators)
+ dump("normal coordinators", mCoordinators)
+ }
companion object {
private const val TAG = "NotifCoordinators"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 350e88ea9df5..caa6c17ac3d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -38,6 +38,8 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
+import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.Compile;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -63,6 +65,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
public static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
private final DelayableExecutor mDelayableExecutor;
private final HeadsUpManager mHeadsUpManager;
+ private final SeenNotificationsInteractor mSeenNotificationsInteractor;
private final ShadeAnimationInteractor mShadeAnimationInteractor;
private final StatusBarStateController mStatusBarStateController;
private final JavaAdapter mJavaAdapter;
@@ -101,6 +104,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
HeadsUpManager headsUpManager,
ShadeAnimationInteractor shadeAnimationInteractor,
JavaAdapter javaAdapter,
+ SeenNotificationsInteractor seenNotificationsInteractor,
StatusBarStateController statusBarStateController,
VisibilityLocationProvider visibilityLocationProvider,
VisualStabilityProvider visualStabilityProvider,
@@ -109,6 +113,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
mHeadsUpManager = headsUpManager;
mShadeAnimationInteractor = shadeAnimationInteractor;
mJavaAdapter = javaAdapter;
+ mSeenNotificationsInteractor = seenNotificationsInteractor;
mVisibilityLocationProvider = visibilityLocationProvider;
mVisualStabilityProvider = visualStabilityProvider;
mWakefulnessLifecycle = wakefulnessLifecycle;
@@ -142,8 +147,15 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
private final NotifStabilityManager mNotifStabilityManager =
new NotifStabilityManager("VisualStabilityCoordinator") {
private boolean canMoveForHeadsUp(NotificationEntry entry) {
- return entry != null && mHeadsUpManager.isHeadsUpEntry(entry.getKey())
- && !mVisibilityLocationProvider.isInVisibleLocation(entry);
+ if (entry == null) {
+ return false;
+ }
+ boolean isTopUnseen = NotificationMinimalismPrototype.V2.isEnabled()
+ && mSeenNotificationsInteractor.isTopUnseenNotification(entry);
+ if (isTopUnseen || mHeadsUpManager.isHeadsUpEntry(entry.getKey())) {
+ return !mVisibilityLocationProvider.isInVisibleLocation(entry);
+ }
+ return false;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
index 5c844bcf749c..e2c9e02672d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
@@ -41,6 +41,9 @@ class ActiveNotificationListRepository @Inject constructor() {
/** Stats about the list of notifications attached to the shade */
val notifStats = MutableStateFlow(NotifStats.empty)
+
+ /** The key of the top unseen notification */
+ val topUnseenNotificationKey = MutableStateFlow<String?>(null)
}
/** Represents the notification list, comprised of groups and individual notifications. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt
index 1f7ab962c3f2..42828d99c7e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt
@@ -17,7 +17,9 @@
package com.android.systemui.statusbar.notification.domain.interactor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
+import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow
@@ -36,4 +38,15 @@ constructor(
fun setHasFilteredOutSeenNotifications(value: Boolean) {
notificationListRepository.hasFilteredOutSeenNotifications.value = value
}
+
+ /** Set the entry that is identified as the top unseen notification. */
+ fun setTopUnseenNotification(entry: NotificationEntry?) {
+ if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return
+ notificationListRepository.topUnseenNotificationKey.value = entry?.key
+ }
+
+ /** Determine if the given notification is the top unseen notification. */
+ fun isTopUnseenNotification(entry: NotificationEntry?): Boolean =
+ if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false
+ else entry != null && notificationListRepository.topUnseenNotificationKey.value == entry.key
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
index 89aa3ab9c84d..9e0dd8fc4d92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -21,6 +21,7 @@ import static com.android.systemui.statusbar.notification.stack.NotificationPrio
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PRIORITY_PEOPLE;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
import android.annotation.Nullable;
@@ -130,7 +131,8 @@ public interface NotificationPanelLogger {
case BUCKET_HEADS_UP: return Notifications.Notification.SECTION_HEADS_UP;
case BUCKET_FOREGROUND_SERVICE:
return Notifications.Notification.SECTION_FOREGROUND_SERVICE;
- case BUCKET_PEOPLE: return Notifications.Notification.SECTION_PEOPLE;
+ case BUCKET_PEOPLE, BUCKET_PRIORITY_PEOPLE:
+ return Notifications.Notification.SECTION_PEOPLE;
case BUCKET_ALERTING: return Notifications.Notification.SECTION_ALERTING;
case BUCKET_SILENT: return Notifications.Notification.SECTION_SILENT;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 747cb3c8d934..4f1056ce9e57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -590,7 +590,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mMenuRow.setAppName(mAppName);
}
if (mIsSummaryWithChildren) {
- if (!AsyncGroupHeaderViewInflation.isEnabled()) {
+ if (AsyncGroupHeaderViewInflation.isEnabled()) {
+ mChildrenContainer.updateGroupHeaderExpandState();
+ } else {
// We create the header from the background thread instead
mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
isConversation());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt
index 8889a10f5ad1..bf37036ee018 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt
@@ -24,6 +24,11 @@ import com.android.systemui.flags.RefactorFlagUtils
/** Helper for reading or using the minimalism prototype flag state. */
@Suppress("NOTHING_TO_INLINE")
object NotificationMinimalismPrototype {
+
+ val version: Int by lazy {
+ SystemProperties.getInt("persist.notification_minimalism_prototype.version", 2)
+ }
+
object V1 {
/** The aconfig flag name */
const val FLAG_NAME = Flags.FLAG_NOTIFICATION_MINIMALISM_PROTOTYPE
@@ -35,7 +40,7 @@ object NotificationMinimalismPrototype {
/** Is the heads-up cycling animation enabled */
@JvmStatic
inline val isEnabled
- get() = Flags.notificationMinimalismPrototype()
+ get() = Flags.notificationMinimalismPrototype() && version == 1
/**
* the prototype will now show seen notifications on the locked shade by default, but this
@@ -76,4 +81,45 @@ object NotificationMinimalismPrototype {
@JvmStatic
inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
}
+ object V2 {
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATION_MINIMALISM_PROTOTYPE
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the heads-up cycling animation enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.notificationMinimalismPrototype() && version == 2
+
+ /**
+ * The prototype will (by default) use a promoter to ensure that the top unseen notification
+ * is not grouped, but this property read allows that behavior to be disabled.
+ */
+ val ungroupTopUnseen: Boolean
+ get() =
+ if (isUnexpectedlyInLegacyMode()) false
+ else
+ SystemProperties.getBoolean(
+ "persist.notification_minimalism_prototype.ungroup_top_unseen",
+ true
+ )
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an
+ * eng build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception
+ * if the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/PriorityPeopleSection.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/PriorityPeopleSection.kt
new file mode 100644
index 000000000000..472fd9564963
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/PriorityPeopleSection.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for com.android.systemui.Flags.FLAG_PRIORITY_PEOPLE_SECTION */
+@Suppress("NOTHING_TO_INLINE")
+object PriorityPeopleSection {
+ const val FLAG_NAME = Flags.FLAG_PRIORITY_PEOPLE_SECTION
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Are sections sorted by time? */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.priorityPeopleSection()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 92c597cf384e..48796d8f8f2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -439,6 +439,15 @@ public class NotificationChildrenContainer extends ViewGroup
Trace.endSection();
}
+ /**
+ * Update the expand state of the group header.
+ */
+ public void updateGroupHeaderExpandState() {
+ if (mGroupHeaderWrapper != null) {
+ mGroupHeaderWrapper.setExpanded(mChildrenExpanded);
+ }
+ }
+
private void removeGroupHeader() {
if (mGroupHeader == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
index 31f4857e4b04..fc28a99ef4ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
@@ -3,15 +3,22 @@ package com.android.systemui.statusbar.notification.stack
import android.annotation.IntDef
/**
- * For now, declare the available notification buckets (sections) here so that other
- * presentation code can decide what to do based on an entry's buckets
+ * For now, declare the available notification buckets (sections) here so that other presentation
+ * code can decide what to do based on an entry's buckets
*/
@Retention(AnnotationRetention.SOURCE)
@IntDef(
- prefix = ["BUCKET_"],
- value = [
- BUCKET_UNKNOWN, BUCKET_MEDIA_CONTROLS, BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE,
- BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT
+ prefix = ["BUCKET_"],
+ value =
+ [
+ BUCKET_UNKNOWN,
+ BUCKET_MEDIA_CONTROLS,
+ BUCKET_HEADS_UP,
+ BUCKET_FOREGROUND_SERVICE,
+ BUCKET_PRIORITY_PEOPLE,
+ BUCKET_PEOPLE,
+ BUCKET_ALERTING,
+ BUCKET_SILENT
]
)
annotation class PriorityBucket
@@ -20,6 +27,7 @@ const val BUCKET_UNKNOWN = 0
const val BUCKET_MEDIA_CONTROLS = 1
const val BUCKET_HEADS_UP = 2
const val BUCKET_FOREGROUND_SERVICE = 3
+const val BUCKET_PRIORITY_PEOPLE = 7
const val BUCKET_PEOPLE = 4
const val BUCKET_ALERTING = 5
const val BUCKET_SILENT = 6
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index a44674542b5c..4b0b1e0029f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -72,6 +72,9 @@ constructor(
*/
private var maxNotificationsExcludesMedia = false
+ /** Whether we allow keyguard to show less important notifications above the shelf. */
+ private var limitLockScreenToImportant = false
+
/** Minimum space between two notifications, see [calculateGapAndDividerHeight]. */
private var dividerHeight by notNull<Float>()
@@ -85,6 +88,14 @@ constructor(
updateResources()
}
+ private fun allowedByPolicy(stackHeight: StackHeight): Boolean =
+ if (limitLockScreenToImportant && stackHeight.includesLessImportantNotification) {
+ log { "\tallowedByPolicy = false" }
+ false
+ } else {
+ true
+ }
+
/**
* Returns whether notifications and (shelf if visible) can fit in total space available.
* [shelfSpace] is extra vertical space allowed for the shelf to overlap the lock icon.
@@ -183,11 +194,12 @@ constructor(
log { "\tGet maxNotifWithoutSavingSpace ---" }
val maxNotifWithoutSavingSpace =
stackHeightSequence.lastIndexWhile { heightResult ->
- canStackFitInSpace(
- heightResult,
- notifSpace = notifSpace,
- shelfSpace = shelfSpace
- ) == FitResult.FIT
+ allowedByPolicy(heightResult) &&
+ canStackFitInSpace(
+ heightResult,
+ notifSpace = notifSpace,
+ shelfSpace = shelfSpace
+ ) == FitResult.FIT
}
// How many notifications we can show at heightWithoutLockscreenConstraints
@@ -212,11 +224,12 @@ constructor(
saveSpaceOnLockscreen = true
maxNotifications =
stackHeightSequence.lastIndexWhile { heightResult ->
- canStackFitInSpace(
- heightResult,
- notifSpace = notifSpace,
- shelfSpace = shelfSpace
- ) != FitResult.NO_FIT
+ allowedByPolicy(heightResult) &&
+ canStackFitInSpace(
+ heightResult,
+ notifSpace = notifSpace,
+ shelfSpace = shelfSpace
+ ) != FitResult.NO_FIT
}
log { "\t--- maxNotifications=$maxNotifications" }
}
@@ -318,7 +331,10 @@ constructor(
// Float height of shelf (0 if shelf is not showing), and space before the shelf that
// changes during the lockscreen <=> full shade transition.
- val shelfHeightWithSpaceBefore: Float
+ val shelfHeightWithSpaceBefore: Float,
+
+ /** Whether this stack height includes less at least one important notification. */
+ val includesLessImportantNotification: Boolean
)
private fun computeHeightPerNotificationLimit(
@@ -331,12 +347,15 @@ constructor(
var previous: ExpandableView? = null
val onLockscreen = onLockscreen()
+ var includesLessImportantNotification = false
+
// Only shelf. This should never happen, since we allow 1 view minimum (EmptyViewState).
yield(
StackHeight(
notifsHeight = 0f,
notifsHeightSavingSpace = 0f,
- shelfHeightWithSpaceBefore = shelfHeight
+ shelfHeightWithSpaceBefore = shelfHeight,
+ includesLessImportantNotification = includesLessImportantNotification,
)
)
@@ -362,6 +381,19 @@ constructor(
spaceBeforeShelf + shelfHeight
}
+ if (limitLockScreenToImportant && !includesLessImportantNotification) {
+ val bucket = (currentNotification as? ExpandableNotificationRow)?.entry?.bucket
+ includesLessImportantNotification =
+ when (bucket) {
+ null,
+ BUCKET_MEDIA_CONTROLS,
+ BUCKET_HEADS_UP,
+ BUCKET_FOREGROUND_SERVICE,
+ BUCKET_PRIORITY_PEOPLE -> false
+ else -> true
+ }
+ }
+
log {
"\tcomputeHeightPerNotificationLimit i=$i notifs=$notifications " +
"notifsHeightSavingSpace=$notifsWithCollapsedHun" +
@@ -371,7 +403,8 @@ constructor(
StackHeight(
notifsHeight = notifications,
notifsHeightSavingSpace = notifsWithCollapsedHun,
- shelfHeightWithSpaceBefore = shelfWithSpaceBefore
+ shelfHeightWithSpaceBefore = shelfWithSpaceBefore,
+ includesLessImportantNotification = includesLessImportantNotification,
)
)
}
@@ -382,11 +415,16 @@ constructor(
infiniteIfNegative(
if (NotificationMinimalismPrototype.V1.isEnabled) {
NotificationMinimalismPrototype.V1.maxNotifs
+ } else if (NotificationMinimalismPrototype.V2.isEnabled) {
+ 1
} else {
resources.getInteger(R.integer.keyguard_max_notification_count)
}
)
- maxNotificationsExcludesMedia = NotificationMinimalismPrototype.V1.isEnabled
+ maxNotificationsExcludesMedia =
+ NotificationMinimalismPrototype.V1.isEnabled ||
+ NotificationMinimalismPrototype.V2.isEnabled
+ limitLockScreenToImportant = NotificationMinimalismPrototype.V2.isEnabled
dividerHeight =
max(1f, resources.getDimensionPixelSize(R.dimen.notification_divider_height).toFloat())
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt
index dacafc48fc72..db544ce59aa1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt
@@ -38,16 +38,6 @@ class NotificationPlaceholderRepository @Inject constructor() {
*/
val shadeScrimBounds = MutableStateFlow<ShadeScrimBounds?>(null)
- /**
- * The y-coordinate in px of top of the contents of the notification stack. This value can be
- * negative, if the stack is scrolled such that its top extends beyond the top edge of the
- * screen.
- */
- val stackTop = MutableStateFlow(0f)
-
- /** the bottom-most acceptable y-position for the bottom of the stack / shelf */
- val stackBottom = MutableStateFlow(0f)
-
/** the y position of the top of the HUN area */
val headsUpTop = MutableStateFlow(0f)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
index 365ead699c65..e7acbe3ab0b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
@@ -72,12 +72,6 @@ constructor(
val alphaForBrightnessMirror: StateFlow<Float> =
placeholderRepository.alphaForBrightnessMirror.asStateFlow()
- /** The y-coordinate in px of top of the contents of the notification stack. */
- val stackTop: StateFlow<Float> = placeholderRepository.stackTop.asStateFlow()
-
- /** The y-coordinate in px of bottom of the contents of the notification stack. */
- val stackBottom: StateFlow<Float> = placeholderRepository.stackBottom.asStateFlow()
-
/** The height of the keyguard's available space bounds */
val constrainedAvailableSpace: StateFlow<Int> =
placeholderRepository.constrainedAvailableSpace.asStateFlow()
@@ -121,16 +115,6 @@ constructor(
viewHeightRepository.headsUpHeight.value = height
}
- /** Sets the y-coord in px of the top of the contents of the notification stack. */
- fun setStackTop(stackTop: Float) {
- placeholderRepository.stackTop.value = stackTop
- }
-
- /** Sets the y-coord in px of the bottom of the contents of the notification stack. */
- fun setStackBottom(stackBottom: Float) {
- placeholderRepository.stackBottom.value = stackBottom
- }
-
/** Sets whether the notification stack is scrolled to the top. */
fun setScrolledToTop(scrolledToTop: Boolean) {
placeholderRepository.scrolledToTop.value = scrolledToTop
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index 3c44713a1df5..622d8e7b2307 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -79,8 +79,6 @@ constructor(
}
launch { viewModel.maxAlpha.collect { view.setMaxAlpha(it) } }
- launch { viewModel.stackTop.collect { view.setStackTop(it) } }
- launch { viewModel.stackBottom.collect { view.setStackBottom(it) } }
launch { viewModel.scrolledToTop.collect { view.setScrolledToTop(it) } }
launch { viewModel.headsUpTop.collect { view.setHeadsUpTop(it) } }
launch { viewModel.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) } }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 082f6b6f11aa..61373815db1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -130,10 +130,6 @@ constructor(
val maxAlpha: Flow<Float> =
stackAppearanceInteractor.alphaForBrightnessMirror.dumpValue("maxAlpha")
- /** The y-coordinate in px of top of the contents of the notification stack. */
- val stackTop: Flow<Float> = stackAppearanceInteractor.stackTop.dumpValue("stackTop")
- /** The y-coordinate in px of bottom of the contents of the notification stack. */
- val stackBottom: Flow<Float> = stackAppearanceInteractor.stackBottom.dumpValue("stackBottom")
/**
* Whether the notification stack is scrolled to the top; i.e., it cannot be scrolled down any
* further.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
index 736058ac3a78..97b86e3371f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
-import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlagsClassic
@@ -57,18 +56,6 @@ constructor(
interactor.setShadeScrimBounds(bounds)
}
- /** Notifies that the bounds of the notification placeholder have changed. */
- fun onStackBoundsChanged(
- top: Float,
- bottom: Float,
- ) {
- keyguardInteractor.setNotificationContainerBounds(
- NotificationContainerBounds(top = top, bottom = bottom)
- )
- interactor.setStackTop(top)
- interactor.setStackBottom(bottom)
- }
-
/** Sets the available space */
fun onConstrainedAvailableSpaceChanged(height: Int) {
interactor.setConstrainedAvailableSpace(height)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index b71564627223..fa88be5b638b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1549,7 +1549,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
if (KeyguardWmStateRefactor.isEnabled()) {
- mKeyguardTransitionInteractor.startDismissKeyguardTransition();
+ mKeyguardTransitionInteractor.startDismissKeyguardTransition(
+ "SBKVM#keyguardAuthenticated");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java b/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java
new file mode 100644
index 000000000000..efeb2f919b56
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java
@@ -0,0 +1,322 @@
+/*
+ * 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.theme;
+
+import com.google.ux.material.libmonet.dynamiccolor.ContrastCurve;
+import com.google.ux.material.libmonet.dynamiccolor.DynamicColor;
+import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors;
+import com.google.ux.material.libmonet.dynamiccolor.ToneDeltaPair;
+import com.google.ux.material.libmonet.dynamiccolor.TonePolarity;
+
+class CustomDynamicColors {
+ private final MaterialDynamicColors mMdc;
+
+ CustomDynamicColors(boolean isExtendedFidelity) {
+ this.mMdc = new MaterialDynamicColors(isExtendedFidelity);
+ }
+
+ // CLOCK COLORS
+
+ public DynamicColor widgetBackground() {
+ return new DynamicColor(
+ /* name= */ "widget_background",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> s.isDark ? 20.0 : 95.0,
+ /* isBackground= */ true,
+ /* background= */ null,
+ /* secondBackground= */ null,
+ /* contrastCurve= */ null,
+ /* toneDeltaPair= */ null);
+ }
+
+ public DynamicColor clockHour() {
+ return new DynamicColor(
+ /* name= */ "clock_hour",
+ /* palette= */ (s) -> s.secondaryPalette,
+ /* tone= */ (s) -> s.isDark ? 30.0 : 60.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> widgetBackground(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 4.0, 5.0, 15.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(clockHour(), clockMinute(), 10.0, TonePolarity.DARKER,
+ false));
+ }
+
+ public DynamicColor clockMinute() {
+ return new DynamicColor(
+ /* name= */ "clock_minute",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> s.isDark ? 40.0 : 90.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> widgetBackground(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 6.5, 10.0, 15.0),
+ /* toneDeltaPair= */ null);
+ }
+
+ public DynamicColor clockSecond() {
+ return new DynamicColor(
+ /* name= */ "clock_second",
+ /* palette= */ (s) -> s.tertiaryPalette,
+ /* tone= */ (s) -> s.isDark ? 40.0 : 90.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> widgetBackground(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0),
+ /* toneDeltaPair= */ null);
+ }
+
+ public DynamicColor weatherTemp() {
+ return new DynamicColor(
+ /* name= */ "clock_second",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> s.isDark ? 55.0 : 80.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> widgetBackground(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0),
+ /* toneDeltaPair= */ null);
+ }
+
+ // THEME APP ICONS
+
+ public DynamicColor themeApp() {
+ return new DynamicColor(
+ /* name= */ "theme_app",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> s.isDark ? 90.0 : 30.0, // Adjusted values
+ /* isBackground= */ true,
+ /* background= */ null,
+ /* secondBackground= */ null,
+ /* contrastCurve= */ null,
+ /* toneDeltaPair= */ null);
+ }
+
+ public DynamicColor onThemeApp() {
+ return new DynamicColor(
+ /* name= */ "on_theme_app",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> s.isDark ? 40.0 : 80.0, // Adjusted values
+ /* isBackground= */ false,
+ /* background= */ (s) -> themeApp(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 10.0),
+ /* toneDeltaPair= */ null);
+ }
+
+ public DynamicColor themeAppRing() {
+ return new DynamicColor(
+ /* name= */ "theme_app_ring",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> 70.0,
+ /* isBackground= */ true,
+ /* background= */ null,
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
+ /* toneDeltaPair= */ null);
+ }
+
+ public DynamicColor themeNotif() {
+ return new DynamicColor(
+ /* name= */ "theme_notif",
+ /* palette= */ (s) -> s.tertiaryPalette,
+ /* tone= */ (s) -> s.isDark ? 80.0 : 90.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> themeAppRing(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(themeNotif(), themeAppRing(), 10.0, TonePolarity.NEARER,
+ false));
+ }
+
+ // SUPER G COLORS
+
+ public DynamicColor brandA() {
+ return new DynamicColor(
+ /* name= */ "brand_a",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> s.isDark ? 40.0 : 80.0,
+ /* isBackground= */ true,
+ /* background= */ (s) -> mMdc.surfaceContainerLow(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 17.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(brandA(), brandB(), 10.0, TonePolarity.NEARER, false));
+ }
+
+ public DynamicColor brandB() {
+ return new DynamicColor(
+ /* name= */ "brand_b",
+ /* palette= */ (s) -> s.secondaryPalette,
+ /* tone= */ (s) -> s.isDark ? 70.0 : 98.0,
+ /* isBackground= */ true,
+ /* background= */ (s) -> mMdc.surfaceContainerLow(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 3.0, 6.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(brandB(), brandC(), 10.0, TonePolarity.NEARER, false));
+ }
+
+ public DynamicColor brandC() {
+ return new DynamicColor(
+ /* name= */ "brand_c",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> s.isDark ? 50.0 : 60.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> mMdc.surfaceContainerLow(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 9.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(brandC(), brandD(), 10.0, TonePolarity.NEARER, false));
+ }
+
+ public DynamicColor brandD() {
+ return new DynamicColor(
+ /* name= */ "brand_d",
+ /* palette= */ (s) -> s.tertiaryPalette,
+ /* tone= */ (s) -> s.isDark ? 59.0 : 90.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> mMdc.surfaceContainerLow(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 13.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(brandD(), brandA(), 10.0, TonePolarity.NEARER, false));
+ }
+
+ // QUICK SETTING TIILES
+
+ public DynamicColor underSurface() {
+ return new DynamicColor(
+ /* name= */ "under_surface",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> 0.0,
+ /* isBackground= */ true,
+ /* background= */ null,
+ /* secondBackground= */ null,
+ /* contrastCurve= */ null,
+ /* toneDeltaPair= */ null);
+ }
+
+ public DynamicColor shadeActive() {
+ return new DynamicColor(
+ /* name= */ "shade_active",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> 90.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> underSurface(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.5, 7.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(shadeActive(), shadeInactive(), 30.0, TonePolarity.LIGHTER,
+ false));
+ }
+
+ public DynamicColor onShadeActive() {
+ return new DynamicColor(
+ /* name= */ "on_shade_active",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> 10.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> shadeActive(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(onShadeActive(), onShadeActiveVariant(), 20.0,
+ TonePolarity.NEARER, false));
+ }
+
+ public DynamicColor onShadeActiveVariant() {
+ return new DynamicColor(
+ /* name= */ "on_shade_active_variant",
+ /* palette= */ (s) -> s.primaryPalette,
+ /* tone= */ (s) -> 30.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> shadeActive(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(onShadeActiveVariant(), onShadeActive(), 20.0,
+ TonePolarity.NEARER, false));
+ }
+
+ public DynamicColor shadeInactive() {
+ return new DynamicColor(
+ /* name= */ "shade_inactive",
+ /* palette= */ (s) -> s.neutralPalette,
+ /* tone= */ (s) -> 20.0,
+ /* isBackground= */ true,
+ /* background= */ (s) -> underSurface(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
+ /* toneDeltaPair= */(s) -> new ToneDeltaPair(shadeInactive(), shadeDisabled(), 15.0,
+ TonePolarity.LIGHTER, false));
+ }
+
+ public DynamicColor onShadeInactive() {
+ return new DynamicColor(
+ /* name= */ "on_shade_inactive",
+ /* palette= */ (s) -> s.neutralVariantPalette,
+ /* tone= */ (s) -> 90.0,
+ /* isBackground= */ true,
+ /* background= */ (s) -> shadeInactive(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(onShadeInactive(), onShadeInactiveVariant(), 10.0,
+ TonePolarity.NEARER, false));
+ }
+
+ public DynamicColor onShadeInactiveVariant() {
+ return new DynamicColor(
+ /* name= */ "on_shade_inactive_variant",
+ /* palette= */ (s) -> s.neutralVariantPalette,
+ /* tone= */ (s) -> 80.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> shadeInactive(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
+ /* toneDeltaPair= */
+ (s) -> new ToneDeltaPair(onShadeInactiveVariant(), onShadeInactive(), 10.0,
+ TonePolarity.NEARER, false));
+ }
+
+ public DynamicColor shadeDisabled() {
+ return new DynamicColor(
+ /* name= */ "shade_disabled",
+ /* palette= */ (s) -> s.neutralPalette,
+ /* tone= */ (s) -> 4.0,
+ /* isBackground= */ false,
+ /* background= */ (s) -> underSurface(),
+ /* secondBackground= */ null,
+ /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
+ /* toneDeltaPair= */ null);
+ }
+
+ public DynamicColor overviewBackground() {
+ return new DynamicColor(
+ /* name= */ "overview_background",
+ /* palette= */ (s) -> s.neutralVariantPalette,
+ /* tone= */ (s) -> s.isDark ? 80.0 : 35.0,
+ /* isBackground= */ true,
+ /* background= */ null,
+ /* secondBackground= */ null,
+ /* contrastCurve= */null,
+ /* toneDeltaPair= */ null);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
index a983d2f9b78e..35187597bd83 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
@@ -103,5 +103,33 @@ class DynamicColors {
Pair.create("on_tertiary_fixed_variant", mdc.onTertiaryFixedVariant()),
)
}
+
+ @JvmStatic
+ fun getCustomColorsMapped(isExtendedFidelity: Boolean): List<Pair<String, DynamicColor>> {
+ val customMdc = CustomDynamicColors(isExtendedFidelity)
+ return arrayListOf(
+ Pair.create("widget_background", customMdc.widgetBackground()),
+ Pair.create("clock_hour", customMdc.clockHour()),
+ Pair.create("clock_minute", customMdc.clockMinute()),
+ Pair.create("clock_second", customMdc.weatherTemp()),
+ Pair.create("theme_app", customMdc.themeApp()),
+ Pair.create("on_theme_app", customMdc.onThemeApp()),
+ Pair.create("theme_app_ring", customMdc.themeAppRing()),
+ Pair.create("on_theme_app_ring", customMdc.themeNotif()),
+ Pair.create("brand_a", customMdc.brandA()),
+ Pair.create("brand_b", customMdc.brandB()),
+ Pair.create("brand_c", customMdc.brandC()),
+ Pair.create("brand_d", customMdc.brandD()),
+ Pair.create("under_surface", customMdc.underSurface()),
+ Pair.create("shade_active", customMdc.shadeActive()),
+ Pair.create("on_shade_active", customMdc.onShadeActive()),
+ Pair.create("on_shade_active_variant", customMdc.onShadeActiveVariant()),
+ Pair.create("shade_inactive", customMdc.shadeInactive()),
+ Pair.create("on_shade_inactive", customMdc.onShadeInactive()),
+ Pair.create("on_shade_inactive_variant", customMdc.onShadeInactiveVariant()),
+ Pair.create("shade_disabled", customMdc.shadeDisabled()),
+ Pair.create("overview_background", customMdc.overviewBackground())
+ )
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 5c3bbb7ca253..d256c4acd955 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -56,6 +56,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -84,6 +85,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.SecureSettings;
+import com.google.ux.material.libmonet.dynamiccolor.DynamicColor;
import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors;
import org.json.JSONException;
@@ -631,29 +633,33 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
protected FabricatedOverlay createDynamicOverlay() {
FabricatedOverlay overlay = newFabricatedOverlay("dynamic");
- assignDynamicPaletteToOverlay(overlay, true /* isDark */);
- assignDynamicPaletteToOverlay(overlay, false /* isDark */);
- assignFixedColorsToOverlay(overlay);
+ //Themed Colors
+ assignColorsToOverlay(overlay, DynamicColors.allDynamicColorsMapped(mIsFidelityEnabled),
+ false);
+ // Fixed Colors
+ assignColorsToOverlay(overlay, DynamicColors.getFixedColorsMapped(mIsFidelityEnabled),
+ true);
+ //Custom Colors
+ assignColorsToOverlay(overlay, DynamicColors.getCustomColorsMapped(mIsFidelityEnabled),
+ false);
return overlay;
}
- private void assignDynamicPaletteToOverlay(FabricatedOverlay overlay, boolean isDark) {
- String suffix = isDark ? "dark" : "light";
- ColorScheme scheme = isDark ? mDarkColorScheme : mLightColorScheme;
- DynamicColors.allDynamicColorsMapped(mIsFidelityEnabled).forEach(p -> {
- String resourceName = "android:color/system_" + p.first + "_" + suffix;
- int colorValue = p.second.getArgb(scheme.getMaterialScheme());
- overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue,
- null /* configuration */);
- });
- }
+ private void assignColorsToOverlay(FabricatedOverlay overlay,
+ List<Pair<String, DynamicColor>> colors, Boolean isFixed) {
+ colors.forEach(p -> {
+ String prefix = "android:color/system_" + p.first;
- private void assignFixedColorsToOverlay(FabricatedOverlay overlay) {
- DynamicColors.getFixedColorsMapped(mIsFidelityEnabled).forEach(p -> {
- String resourceName = "android:color/system_" + p.first;
- int colorValue = p.second.getArgb(mLightColorScheme.getMaterialScheme());
- overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue,
- null /* configuration */);
+ if (isFixed) {
+ overlay.setResourceValue(prefix, TYPE_INT_COLOR_ARGB8,
+ p.second.getArgb(mLightColorScheme.getMaterialScheme()), null);
+ return;
+ }
+
+ overlay.setResourceValue(prefix + "_light", TYPE_INT_COLOR_ARGB8,
+ p.second.getArgb(mLightColorScheme.getMaterialScheme()), null);
+ overlay.setResourceValue(prefix + "_dark", TYPE_INT_COLOR_ARGB8,
+ p.second.getArgb(mDarkColorScheme.getMaterialScheme()), null);
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
index bfed0c44f6b7..0a1724c189c8 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
@@ -70,8 +70,10 @@ constructor(
val isGuestUserResetting: Boolean = repository.isGuestUserResetting
init {
- resumeSessionReceiver.register()
- resetOrExitSessionReceiver.register()
+ if (applicationContext.userId == UserHandle.USER_SYSTEM) {
+ resumeSessionReceiver.register()
+ resetOrExitSessionReceiver.register()
+ }
}
/** Notifies that the device has finished booting. */
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
index 46ce5f2623de..1ec86a4d1dfc 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
@@ -97,3 +97,12 @@ fun <T> collectFlow(
fun <A, B, R> combineFlows(flow1: Flow<A>, flow2: Flow<B>, bifunction: (A, B) -> R): Flow<R> {
return combine(flow1, flow2, bifunction)
}
+
+fun <A, B, C, R> combineFlows(
+ flow1: Flow<A>,
+ flow2: Flow<B>,
+ flow3: Flow<C>,
+ trifunction: (A, B, C) -> R
+): Flow<R> {
+ return combine(flow1, flow2, flow3, trifunction)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt
index d0d9891a953f..8a5af09f52ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt
@@ -40,7 +40,6 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import org.junit.Before
-import org.junit.Ignore
import org.junit.runner.RunWith
@SmallTest
@@ -1149,7 +1148,6 @@ class LockscreenSceneTransitionInteractorTest : SysuiTestCase() {
*
* In STL there is no guarantee that transitions settle in Idle before continuing.
*/
- @Ignore("Suffers from a race condition that will be fixed in followup CL")
@Test
fun transition_from_ls_scene_interrupted_by_other_from_ls_transition() =
testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 9b2db3e5316c..1f132989b169 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -21,6 +21,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -41,10 +42,9 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
private lateinit var executor: FakeExecutor
@Mock private lateinit var activityTaskManagerService: IActivityTaskManager
-
@Mock private lateinit var keyguardStateController: KeyguardStateController
-
@Mock private lateinit var keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier
+ @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Before
fun setUp() {
@@ -57,6 +57,7 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
activityTaskManagerService = activityTaskManagerService,
keyguardStateController = keyguardStateController,
keyguardSurfaceBehindAnimator = keyguardSurfaceBehindAnimator,
+ keyguardTransitionInteractor = keyguardTransitionInteractor,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
index 9f0e67b60c29..85cc88dd5283 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
@@ -15,11 +15,13 @@
*/
package com.android.systemui.monet
-import androidx.test.filters.SmallTest
import android.testing.AndroidTestingRunner
import android.util.Log
+import android.util.Pair
+import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.theme.DynamicColors
+import com.google.ux.material.libmonet.dynamiccolor.DynamicColor
import com.google.ux.material.libmonet.hct.Hct
import com.google.ux.material.libmonet.scheme.SchemeTonalSpot
import java.io.File
@@ -81,6 +83,10 @@ private fun commentShade(paletteName: String, tone: Int): String {
@SmallTest
@RunWith(AndroidTestingRunner::class)
class ColorSchemeTest : SysuiTestCase() {
+ private val defaultContrast = 0.0
+ private val defaultIsDark = false
+ private val defaultIsFidelity = false
+
@Test
fun generateThemeStyles() {
val document = buildDoc<Any>()
@@ -107,7 +113,7 @@ class ColorSchemeTest : SysuiTestCase() {
}
val style = document.createElement(styleValue.name.lowercase())
- val colorScheme = ColorScheme(sourceColor.toInt(), false, styleValue)
+ val colorScheme = ColorScheme(sourceColor.toInt(), defaultIsDark, styleValue)
style.appendChild(
document.createTextNode(
@@ -139,7 +145,7 @@ class ColorSchemeTest : SysuiTestCase() {
document.appendWithBreak(resources)
// shade colors
- val colorScheme = ColorScheme(GOOGLE_BLUE, false)
+ val colorScheme = ColorScheme(GOOGLE_BLUE, defaultIsDark)
arrayOf(
Triple("accent1", "Primary", colorScheme.accent1),
Triple("accent2", "Secondary", colorScheme.accent2),
@@ -162,24 +168,35 @@ class ColorSchemeTest : SysuiTestCase() {
resources.appendWithBreak(document.createComment(commentRoles), 2)
- // dynamic colors
- arrayOf(false, true).forEach { isDark ->
- val suffix = if (isDark) "_dark" else "_light"
- val dynamicScheme = SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), isDark, 0.5)
- DynamicColors.allDynamicColorsMapped(false).forEach {
- resources.createColorEntry(
- "system_${it.first}$suffix",
- it.second.getArgb(dynamicScheme)
- )
+ fun generateDynamic(pairs: List<Pair<String, DynamicColor>>) {
+ arrayOf(false, true).forEach { isDark ->
+ val suffix = if (isDark) "_dark" else "_light"
+ val dynamicScheme =
+ SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), isDark, defaultContrast)
+ pairs.forEach {
+ resources.createColorEntry(
+ "system_${it.first}$suffix",
+ it.second.getArgb(dynamicScheme)
+ )
+ }
}
}
+ // dynamic colors
+ generateDynamic(DynamicColors.allDynamicColorsMapped(defaultIsFidelity))
+
// fixed colors
- val dynamicScheme = SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), false, 0.5)
- DynamicColors.getFixedColorsMapped(false).forEach {
+ val dynamicScheme =
+ SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), defaultIsDark, defaultContrast)
+ DynamicColors.getFixedColorsMapped(defaultIsFidelity).forEach {
resources.createColorEntry("system_${it.first}", it.second.getArgb(dynamicScheme))
}
+ resources.appendWithBreak(document.createComment(commentRoles), 2)
+
+ // custom colors
+ generateDynamic(DynamicColors.getCustomColorsMapped(defaultIsFidelity))
+
saveFile(document, "role_values.xml")
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
index 5e7d8fb5df02..a10d81f86d8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
@@ -21,7 +21,6 @@ import android.content.Intent
import android.os.Bundle
import android.os.UserHandle
import android.testing.AndroidTestingRunner
-import android.view.View
import android.view.Window
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -49,7 +48,7 @@ class ActionExecutorTest : SysuiTestCase() {
private val intentExecutor = mock<ActionIntentExecutor>()
private val window = mock<Window>()
- private val view = mock<View>()
+ private val viewProxy = mock<ScreenshotShelfViewProxy>()
private val onDismiss = mock<(() -> Unit)>()
private val pendingIntent = mock<PendingIntent>()
@@ -70,16 +69,16 @@ class ActionExecutorTest : SysuiTestCase() {
}
@Test
- fun sendPendingIntent_dismisses() = runTest {
+ fun sendPendingIntent_requestsDismissal() = runTest {
actionExecutor = createActionExecutor()
actionExecutor.sendPendingIntent(pendingIntent)
verify(pendingIntent).send(any(Bundle::class.java))
- verify(onDismiss).invoke()
+ verify(viewProxy).requestDismissal(null)
}
private fun createActionExecutor(): ActionExecutor {
- return ActionExecutor(intentExecutor, testScope, window, view, onDismiss)
+ return ActionExecutor(intentExecutor, testScope, window, viewProxy, onDismiss)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
index 5e53fe16534d..5cd3f66d2cbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
@@ -23,17 +23,18 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableContext
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
+import com.android.systemui.screenshot.proxy.SystemUiProxy
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.util.mockito.mock
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.verify
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
@RunWith(AndroidTestingRunner::class)
class ActionIntentExecutorTest : SysuiTestCase() {
@@ -44,8 +45,9 @@ class ActionIntentExecutorTest : SysuiTestCase() {
private val testableContext = TestableContext(mContext)
private val activityManagerWrapper = mock<ActivityManagerWrapper>()
+ private val systemUiProxy = mock<SystemUiProxy>()
+
private val displayTracker = mock<DisplayTracker>()
- private val keyguardController = mock<ScreenshotKeyguardController>()
private val actionIntentExecutor =
ActionIntentExecutor(
@@ -53,12 +55,12 @@ class ActionIntentExecutorTest : SysuiTestCase() {
activityManagerWrapper,
testScope,
mainDispatcher,
+ systemUiProxy,
displayTracker,
- keyguardController,
)
@Test
- @EnableFlags(Flags.FLAG_SCREENSHOT_ACTION_DISMISS_SYSTEM_WINDOWS)
+ @EnableFlags(Flags.FLAG_FIX_SCREENSHOT_ACTION_DISMISS_SYSTEM_WINDOWS)
fun launchIntent_callsCloseSystemWindows() =
testScope.runTest {
val intent = Intent(Intent.ACTION_EDIT).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index ed7c9568a9db..a5e7a67b21a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -995,9 +995,11 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
.setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null));
// All dynamic colors were added twice: light and dark them
// All fixed colors were added once
+ // All custom dynamic tokens added twice
verify(dynamic, times(
DynamicColors.allDynamicColorsMapped(false).size() * 2
- + DynamicColors.getFixedColorsMapped(false).size())
+ + DynamicColors.getFixedColorsMapped(false).size()
+ + DynamicColors.getCustomColorsMapped(false).size() * 2)
).setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
index 948670f95f97..01795e92d141 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
@@ -18,6 +18,7 @@
package com.android.systemui.user.domain.interactor
import android.app.admin.DevicePolicyManager
+import android.content.Context
import android.content.pm.UserInfo
import android.os.UserHandle
import android.os.UserManager
@@ -59,6 +60,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
@Mock private lateinit var switchUser: (Int) -> Unit
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
+ @Mock private lateinit var otherContext: Context
private lateinit var underTest: GuestUserInteractor
@@ -74,28 +76,30 @@ class GuestUserInteractorTest : SysuiTestCase() {
repository = FakeUserRepository()
repository.setUserInfos(ALL_USERS)
- underTest =
- GuestUserInteractor(
- applicationContext = context,
- applicationScope = scope,
- mainDispatcher = IMMEDIATE,
- backgroundDispatcher = IMMEDIATE,
- manager = manager,
- repository = repository,
- deviceProvisionedController = deviceProvisionedController,
- devicePolicyManager = devicePolicyManager,
- refreshUsersScheduler =
- RefreshUsersScheduler(
- applicationScope = scope,
- mainDispatcher = IMMEDIATE,
- repository = repository,
- ),
- uiEventLogger = uiEventLogger,
- resumeSessionReceiver = resumeSessionReceiver,
- resetOrExitSessionReceiver = resetOrExitSessionReceiver,
- )
+ underTest = initGuestUserInteractor(context)
}
+ private fun initGuestUserInteractor(context: Context) =
+ GuestUserInteractor(
+ applicationContext = context,
+ applicationScope = scope,
+ mainDispatcher = IMMEDIATE,
+ backgroundDispatcher = IMMEDIATE,
+ manager = manager,
+ repository = repository,
+ deviceProvisionedController = deviceProvisionedController,
+ devicePolicyManager = devicePolicyManager,
+ refreshUsersScheduler =
+ RefreshUsersScheduler(
+ applicationScope = scope,
+ mainDispatcher = IMMEDIATE,
+ repository = repository,
+ ),
+ uiEventLogger = uiEventLogger,
+ resumeSessionReceiver = resumeSessionReceiver,
+ resetOrExitSessionReceiver = resetOrExitSessionReceiver,
+ )
+
@Test
fun registersBroadcastReceivers() {
verify(resumeSessionReceiver).register()
@@ -103,6 +107,16 @@ class GuestUserInteractorTest : SysuiTestCase() {
}
@Test
+ fun registersBroadcastReceiversOnlyForSystemUser() {
+ for (i in 1..5) {
+ whenever(otherContext.userId).thenReturn(UserHandle.MIN_SECONDARY_USER_ID + i)
+ initGuestUserInteractor(otherContext)
+ }
+ verify(resumeSessionReceiver).register()
+ verify(resetOrExitSessionReceiver).register()
+ }
+
+ @Test
fun onDeviceBootCompleted_allowedToAdd_createGuest() =
runBlocking(IMMEDIATE) {
setAllowedToAdd()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
index 31848a67698c..e1dcb145f20b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
@@ -1,8 +1,8 @@
package com.android.systemui.util
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.wm.shell.common.FloatingContentCoordinator
@@ -14,7 +14,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FloatingContentCoordinatorTest : SysuiTestCase() {
@@ -198,12 +198,11 @@ class FloatingContentCoordinatorTest : SysuiTestCase() {
}
/**
- * Helper class that uses [floatingCoordinator.findAreaForContentVertically] to move a
- * Rect when needed.
+ * Helper class that uses [floatingCoordinator.findAreaForContentVertically] to move a Rect when
+ * needed.
*/
- inner class FloatingRect(
- private val underlyingRect: Rect
- ) : FloatingContentCoordinator.FloatingContent {
+ inner class FloatingRect(private val underlyingRect: Rect) :
+ FloatingContentCoordinator.FloatingContent {
override fun moveToBounds(bounds: Rect) {
underlyingRect.set(bounds)
}
@@ -216,4 +215,4 @@ class FloatingContentCoordinatorTest : SysuiTestCase() {
return underlyingRect
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
index 436f5b827ec6..457f2bb5d826 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
@@ -19,12 +19,13 @@ package com.android.systemui.util
import android.content.BroadcastReceiver
import android.content.IntentFilter
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.lifecycle.Observer
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
+import java.util.concurrent.Executor
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -38,10 +39,9 @@ import org.mockito.Mockito.anyInt
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
-import java.util.concurrent.Executor
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class RingerModeLiveDataTest : SysuiTestCase() {
@@ -52,16 +52,11 @@ class RingerModeLiveDataTest : SysuiTestCase() {
private val INTENT = "INTENT"
}
- @Mock
- private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock
- private lateinit var valueSupplier: () -> Int
- @Mock
- private lateinit var observer: Observer<Int>
- @Captor
- private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver>
- @Captor
- private lateinit var intentFilterCaptor: ArgumentCaptor<IntentFilter>
+ @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock private lateinit var valueSupplier: () -> Int
+ @Mock private lateinit var observer: Observer<Int>
+ @Captor private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver>
+ @Captor private lateinit var intentFilterCaptor: ArgumentCaptor<IntentFilter>
// Run everything immediately
private val executor = Executor { it.run() }
@@ -88,14 +83,14 @@ class RingerModeLiveDataTest : SysuiTestCase() {
fun testOnActive_broadcastRegistered() {
liveData.observeForever(observer)
verify(broadcastDispatcher)
- .registerReceiver(any(), any(), eq(executor), eq(UserHandle.ALL), anyInt(), any())
+ .registerReceiver(any(), any(), eq(executor), eq(UserHandle.ALL), anyInt(), any())
}
@Test
fun testOnActive_intentFilterHasIntent() {
liveData.observeForever(observer)
- verify(broadcastDispatcher).registerReceiver(any(), capture(intentFilterCaptor), any(),
- any(), anyInt(), any())
+ verify(broadcastDispatcher)
+ .registerReceiver(any(), capture(intentFilterCaptor), any(), any(), anyInt(), any())
assertTrue(intentFilterCaptor.value.hasAction(INTENT))
}
@@ -111,4 +106,4 @@ class RingerModeLiveDataTest : SysuiTestCase() {
liveData.removeObserver(observer)
verify(broadcastDispatcher).unregisterReceiver(any())
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
index b13cb72dc944..6271904b2f04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
@@ -19,10 +19,10 @@ package com.android.systemui.util
import android.app.WallpaperInfo
import android.app.WallpaperManager
import android.os.IBinder
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.View
import android.view.ViewRootImpl
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
@@ -32,36 +32,30 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.doThrow
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
@SmallTest
class WallpaperControllerTest : SysuiTestCase() {
- @Mock
- private lateinit var wallpaperManager: WallpaperManager
- @Mock
- private lateinit var root: View
- @Mock
- private lateinit var viewRootImpl: ViewRootImpl
- @Mock
- private lateinit var windowToken: IBinder
+ @Mock private lateinit var wallpaperManager: WallpaperManager
+ @Mock private lateinit var root: View
+ @Mock private lateinit var viewRootImpl: ViewRootImpl
+ @Mock private lateinit var windowToken: IBinder
private val wallpaperRepository = FakeWallpaperRepository()
- @JvmField
- @Rule
- val mockitoRule = MockitoJUnit.rule()
+ @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
private lateinit var wallaperController: WallpaperController
@@ -92,9 +86,7 @@ class WallpaperControllerTest : SysuiTestCase() {
@Test
fun setUnfoldTransitionZoom_defaultUnfoldTransitionIsDisabled_doesNotUpdateWallpaperZoom() {
- wallpaperRepository.wallpaperInfo.value = createWallpaperInfo(
- useDefaultTransition = false
- )
+ wallpaperRepository.wallpaperInfo.value = createWallpaperInfo(useDefaultTransition = false)
wallaperController.setUnfoldTransitionZoom(0.5f)
@@ -130,7 +122,8 @@ class WallpaperControllerTest : SysuiTestCase() {
@Test
fun setNotificationZoom_exceptionWhenUpdatingZoom_doesNotFail() {
- doThrow(IllegalArgumentException("test exception")).`when`(wallpaperManager)
+ doThrow(IllegalArgumentException("test exception"))
+ .`when`(wallpaperManager)
.setWallpaperZoomOut(any(), anyFloat())
wallaperController.setNotificationShadeZoom(0.5f)
@@ -140,8 +133,7 @@ class WallpaperControllerTest : SysuiTestCase() {
private fun createWallpaperInfo(useDefaultTransition: Boolean = true): WallpaperInfo {
val info = mock(WallpaperInfo::class.java)
- whenever(info.shouldUseDefaultUnfoldTransition())
- .thenReturn(useDefaultTransition)
+ whenever(info.shouldUseDefaultUnfoldTransition()).thenReturn(useDefaultTransition)
return info
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
index 92afb038b321..b26598c80478 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
@@ -16,13 +16,16 @@
package com.android.systemui.util.animation
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
-import org.junit.Test
import java.lang.IllegalArgumentException
+import org.junit.runner.RunWith
+import org.junit.Test
@SmallTest
+@RunWith(AndroidJUnit4::class)
class AnimationUtilTest : SysuiTestCase() {
@Test
fun getMsForFrames_5frames_returns83() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
index 9dfa14dd0784..7dfac0ab2650 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
@@ -22,8 +22,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -39,7 +38,7 @@ import java.util.ArrayList;
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class FakeExecutorTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java
index 78fc6803ea7e..48fb74514b01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java
@@ -24,8 +24,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -39,7 +38,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class MessageRouterImplTest extends SysuiTestCase {
private static final int MESSAGE_A = 0;
private static final int MESSAGE_B = 1;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt
index 15032dc182d6..7ec420f0b6da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.util.concurrency
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.time.FakeSystemClock
@@ -26,7 +26,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class MockExecutorHandlerTest : SysuiTestCase() {
/** Test FakeExecutor that receives non-delayed items to execute. */
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java
index 00f37ae6f6cb..13fff29d89ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java
@@ -18,8 +18,7 @@ package com.android.systemui.util.concurrency;
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -30,7 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class RepeatableExecutorTest extends SysuiTestCase {
private static final int DELAY = 100;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
index b367a603ec67..37015e30781e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
@@ -23,8 +23,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.CoreStartable;
@@ -44,7 +43,7 @@ import java.util.HashSet;
import java.util.Set;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ConditionalCoreStartableTest extends SysuiTestCase {
public static class FakeConditionalCoreStartable extends ConditionalCoreStartable {
interface Callback {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
index ac357ea34be0..b8f581574848 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
@@ -4,7 +4,7 @@ import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ShapeDrawable
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -12,7 +12,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class DrawableSizeTest : SysuiTestCase() {
@@ -32,14 +32,11 @@ class DrawableSizeTest : SysuiTestCase() {
@Test
fun testDownscaleToSize_drawableSmallerThanRequirement_unchanged() {
- val drawable = BitmapDrawable(resources,
- Bitmap.createBitmap(
- resources.displayMetrics,
- 150,
- 150,
- Bitmap.Config.ARGB_8888
- )
- )
+ val drawable =
+ BitmapDrawable(
+ resources,
+ Bitmap.createBitmap(resources.displayMetrics, 150, 150, Bitmap.Config.ARGB_8888)
+ )
val result = DrawableSize.downscaleToSize(resources, drawable, 300, 300)
assertThat(result).isSameInstanceAs(drawable)
}
@@ -48,14 +45,11 @@ class DrawableSizeTest : SysuiTestCase() {
fun testDownscaleToSize_drawableLargerThanRequirementWithDensity_resized() {
// This bitmap would actually fail to resize if the method doesn't check for
// bitmap dimensions inside drawable.
- val drawable = BitmapDrawable(resources,
- Bitmap.createBitmap(
- resources.displayMetrics,
- 150,
- 75,
- Bitmap.Config.ARGB_8888
- )
- )
+ val drawable =
+ BitmapDrawable(
+ resources,
+ Bitmap.createBitmap(resources.displayMetrics, 150, 75, Bitmap.Config.ARGB_8888)
+ )
val result = DrawableSize.downscaleToSize(resources, drawable, 75, 75)
assertThat(result).isNotSameInstanceAs(drawable)
@@ -65,9 +59,9 @@ class DrawableSizeTest : SysuiTestCase() {
@Test
fun testDownscaleToSize_drawableAnimated_unchanged() {
- val drawable = resources.getDrawable(android.R.drawable.stat_sys_download,
- resources.newTheme())
+ val drawable =
+ resources.getDrawable(android.R.drawable.stat_sys_download, resources.newTheme())
val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
assertThat(result).isSameInstanceAs(drawable)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
index 7d0d57b4037a..e2ce50ccb6da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
@@ -16,7 +16,7 @@
package com.android.systemui.util.kotlin
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.time.FakeSystemClock
@@ -47,7 +47,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class PairwiseFlowTest : SysuiTestCase() {
@Test
fun simple() = runBlocking {
@@ -89,7 +89,9 @@ class PairwiseFlowTest : SysuiTestCase() {
initRun = true
"initial"
}
- ) { prev: String, next: String -> "$prev|$next" }
+ ) { prev: String, next: String ->
+ "$prev|$next"
+ }
)
.emitsExactly("initial|val1", "val1|val2")
assertThat(initRun).isTrue()
@@ -104,7 +106,9 @@ class PairwiseFlowTest : SysuiTestCase() {
initRun = true
"initial"
}
- ) { prev: String, next: String -> "$prev|$next" }
+ ) { prev: String, next: String ->
+ "$prev|$next"
+ }
)
.emitsNothing()
// Even though the flow will not emit anything, the initial value function should still get
@@ -120,7 +124,9 @@ class PairwiseFlowTest : SysuiTestCase() {
initRun = true
"initial"
}
- ) { prev: String, next: String -> "$prev|$next" }
+ ) { prev: String, next: String ->
+ "$prev|$next"
+ }
// Since the flow isn't collected, ensure [initialValueFun] isn't run.
assertThat(initRun).isFalse()
@@ -146,7 +152,7 @@ class PairwiseFlowTest : SysuiTestCase() {
}
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SetChangesFlowTest : SysuiTestCase() {
@Test
fun simple() = runBlocking {
@@ -198,7 +204,7 @@ class SetChangesFlowTest : SysuiTestCase() {
}
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SampleFlowTest : SysuiTestCase() {
@Test
fun simple() = runBlocking {
@@ -240,7 +246,7 @@ class SampleFlowTest : SysuiTestCase() {
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ThrottleFlowTest : SysuiTestCase() {
@Test
@@ -248,13 +254,16 @@ class ThrottleFlowTest : SysuiTestCase() {
// Arrange
val choreographer = createChoreographer(this)
val output = mutableListOf<Int>()
- val collectJob = backgroundScope.launch {
- flow {
- emit(1)
- delay(1000)
- emit(2)
- }.throttle(1000, choreographer.fakeClock).toList(output)
- }
+ val collectJob =
+ backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(1000)
+ emit(2)
+ }
+ .throttle(1000, choreographer.fakeClock)
+ .toList(output)
+ }
// Act
choreographer.advanceAndRun(0)
@@ -283,13 +292,16 @@ class ThrottleFlowTest : SysuiTestCase() {
// Arrange
val choreographer = createChoreographer(this)
val output = mutableListOf<Int>()
- val collectJob = backgroundScope.launch {
- flow {
- emit(1)
- delay(500)
- emit(2)
- }.throttle(1000, choreographer.fakeClock).toList(output)
- }
+ val collectJob =
+ backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(500)
+ emit(2)
+ }
+ .throttle(1000, choreographer.fakeClock)
+ .toList(output)
+ }
// Act
choreographer.advanceAndRun(0)
@@ -319,15 +331,18 @@ class ThrottleFlowTest : SysuiTestCase() {
// Arrange
val choreographer = createChoreographer(this)
val output = mutableListOf<Int>()
- val collectJob = backgroundScope.launch {
- flow {
- emit(1)
- delay(500)
- emit(2)
- delay(500)
- emit(3)
- }.throttle(1000, choreographer.fakeClock).toList(output)
- }
+ val collectJob =
+ backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(500)
+ emit(2)
+ delay(500)
+ emit(3)
+ }
+ .throttle(1000, choreographer.fakeClock)
+ .toList(output)
+ }
// Act
choreographer.advanceAndRun(0)
@@ -357,15 +372,18 @@ class ThrottleFlowTest : SysuiTestCase() {
// Arrange
val choreographer = createChoreographer(this)
val output = mutableListOf<Int>()
- val collectJob = backgroundScope.launch {
- flow {
- emit(1)
- delay(500)
- emit(2)
- delay(250)
- emit(3)
- }.throttle(1000, choreographer.fakeClock).toList(output)
- }
+ val collectJob =
+ backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(500)
+ emit(2)
+ delay(250)
+ emit(3)
+ }
+ .throttle(1000, choreographer.fakeClock)
+ .toList(output)
+ }
// Act
choreographer.advanceAndRun(0)
@@ -391,15 +409,16 @@ class ThrottleFlowTest : SysuiTestCase() {
collectJob.cancel()
}
- private fun createChoreographer(testScope: TestScope) = object {
- val fakeClock = FakeSystemClock()
+ private fun createChoreographer(testScope: TestScope) =
+ object {
+ val fakeClock = FakeSystemClock()
- fun advanceAndRun(millis: Long) {
- fakeClock.advanceTime(millis)
- testScope.advanceTimeBy(millis)
- testScope.runCurrent()
+ fun advanceAndRun(millis: Long) {
+ fakeClock.advanceTime(millis)
+ testScope.advanceTimeBy(millis)
+ testScope.runCurrent()
+ }
}
- }
}
private fun <T> assertThatFlow(flow: Flow<T>) =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
index 4ca1fd39682d..c31b287fddce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.util.kotlin
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import java.util.concurrent.atomic.AtomicLong
@@ -31,43 +31,42 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class IpcSerializerTest : SysuiTestCase() {
private val serializer = IpcSerializer()
@Ignore("b/253046405")
@Test
- fun serializeManyIncomingIpcs(): Unit = runBlocking(Dispatchers.Main.immediate) {
- val processor = launch(start = CoroutineStart.LAZY) { serializer.process() }
- withContext(Dispatchers.IO) {
- val lastEvaluatedTime = AtomicLong(System.currentTimeMillis())
- // First, launch many serialization requests in parallel
- repeat(100_000) {
- launch(Dispatchers.Unconfined) {
- val enqueuedTime = System.currentTimeMillis()
- serializer.runSerialized {
- val last = lastEvaluatedTime.getAndSet(enqueuedTime)
- assertTrue(
- "expected $last less than or equal to $enqueuedTime ",
- last <= enqueuedTime,
- )
+ fun serializeManyIncomingIpcs(): Unit =
+ runBlocking(Dispatchers.Main.immediate) {
+ val processor = launch(start = CoroutineStart.LAZY) { serializer.process() }
+ withContext(Dispatchers.IO) {
+ val lastEvaluatedTime = AtomicLong(System.currentTimeMillis())
+ // First, launch many serialization requests in parallel
+ repeat(100_000) {
+ launch(Dispatchers.Unconfined) {
+ val enqueuedTime = System.currentTimeMillis()
+ serializer.runSerialized {
+ val last = lastEvaluatedTime.getAndSet(enqueuedTime)
+ assertTrue(
+ "expected $last less than or equal to $enqueuedTime ",
+ last <= enqueuedTime,
+ )
+ }
}
}
+ // Then, process them all in the order they came in.
+ processor.start()
}
- // Then, process them all in the order they came in.
- processor.start()
+ // All done, stop processing
+ processor.cancel()
}
- // All done, stop processing
- processor.cancel()
- }
@Test(timeout = 5000)
fun serializeOnOneThread_doesNotDeadlock() = runBlocking {
val job = launch { serializer.process() }
- repeat(100) {
- serializer.runSerializedBlocking { }
- }
+ repeat(100) { serializer.runSerializedBlocking {} }
job.cancel()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
index 2013bb0a547e..8bfff9c209e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
@@ -27,13 +27,13 @@ import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.junit.runners.Parameterized.Parameters
import org.mockito.Mock
import org.mockito.MockitoAnnotations
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(Parameterized::class)
+@RunWith(ParameterizedAndroidJunit4::class)
internal class PackageManagerExtComponentEnabledTest(private val testCase: TestCase) :
SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
index 6848b836a348..b2f7c1aa0384 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
@@ -16,7 +16,7 @@
package com.android.systemui.util.kotlin
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -28,7 +28,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class RaceSuspendTest : SysuiTestCase() {
@Test
fun raceSimple() = runBlocking {
@@ -46,10 +46,11 @@ class RaceSuspendTest : SysuiTestCase() {
@Test
fun raceImmediate() = runBlocking {
assertThat(
- race<Int>(
- { 1 },
- { 2 },
+ race<Int>(
+ { 1 },
+ { 2 },
+ )
)
- ).isEqualTo(1)
+ .isEqualTo(1)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
index 84129beea92a..300c29852ead 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
@@ -26,9 +26,9 @@ import static org.mockito.Mockito.verify;
import android.content.res.Resources;
import android.hardware.Sensor;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -46,7 +46,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class PostureDependentProximitySensorTest extends SysuiTestCase {
@Mock private Resources mResources;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
index 19dbf9aa3c13..5dd008ac10f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
@@ -23,9 +23,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -40,7 +40,7 @@ import org.junit.runner.RunWith;
import java.util.function.Consumer;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class ProximityCheckTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
index 5e7557896145..0eab74eb3cfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
@@ -24,9 +24,9 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -40,7 +40,7 @@ import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class ProximitySensorImplDualTest extends SysuiTestCase {
private ProximitySensor mProximitySensor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
index 752cd3211161..f44c842ad2eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
@@ -21,9 +21,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -40,7 +40,7 @@ import org.mockito.MockitoAnnotations;
* Tests for ProximitySensor that rely on a single hardware sensor.
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class ProximitySensorImplSingleTest extends SysuiTestCase {
private ProximitySensor mProximitySensor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
index 8d26c877f4cf..a54afad617bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
@@ -30,8 +30,8 @@ import android.content.Intent;
import android.content.pm.UserInfo;
import android.os.IBinder;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -49,7 +49,7 @@ import java.util.List;
import java.util.Objects;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ObservableServiceConnectionTest extends SysuiTestCase {
static class Foo {
int mValue;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java
index a2fd288ef33e..a70b00c8972d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java
@@ -24,8 +24,8 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -38,7 +38,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class PackageObserverTest extends SysuiTestCase {
@Mock
Context mContext;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java
index 55c49ee4360d..ef10fdf63741 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java
@@ -19,8 +19,7 @@ package com.android.systemui.util.service;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -37,7 +36,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class PersistentConnectionManagerTest extends SysuiTestCase {
private static final int MAX_RETRIES = 5;
private static final int RETRY_DELAY_MS = 1000;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
index f65caee24e34..99f6303ad73d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
@@ -28,8 +28,8 @@ import static org.mockito.Mockito.verify;
import android.database.ContentObserver;
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -44,7 +44,7 @@ import java.util.Collection;
import java.util.Map;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class FakeSettingsTest extends SysuiTestCase {
@Mock
ContentObserver mContentObserver;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
index 913759f77013..88b2630bd78f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.util.settings.repository
import android.content.pm.UserInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -33,11 +34,10 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class UserAwareSecureSettingsRepositoryTest : SysuiTestCase() {
private val dispatcher = StandardTestDispatcher()
@@ -48,11 +48,12 @@ class UserAwareSecureSettingsRepositoryTest : SysuiTestCase() {
@Before
fun setup() {
- repository = UserAwareSecureSettingsRepositoryImpl(
- secureSettings,
- userRepository,
- dispatcher,
- )
+ repository =
+ UserAwareSecureSettingsRepositoryImpl(
+ secureSettings,
+ userRepository,
+ dispatcher,
+ )
userRepository.setUserInfos(USER_INFOS)
setSettingValueForUser(enabled = true, userInfo = SETTING_ENABLED_USER)
setSettingValueForUser(enabled = false, userInfo = SETTING_DISABLED_USER)
@@ -105,4 +106,4 @@ class UserAwareSecureSettingsRepositoryTest : SysuiTestCase() {
val SETTING_DISABLED_USER = UserInfo(/* id= */ 1, "user2", /* flags= */ 0)
val USER_INFOS = listOf(SETTING_ENABLED_USER, SETTING_DISABLED_USER)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
index 94100fe7f4c4..6637d5f8de92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.util.ui
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -30,7 +30,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class AnimatedValueTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
index e3cd9b2d6eaf..3dcb82811408 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
@@ -19,17 +19,20 @@ package com.android.systemui.util.view
import android.graphics.Rect
import android.view.View
import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.spy
import org.mockito.Mockito.`when`
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ViewUtilTest : SysuiTestCase() {
private val viewUtil = ViewUtil()
private lateinit var view: View
@@ -45,11 +48,13 @@ class ViewUtilTest : SysuiTestCase() {
location[1] = VIEW_TOP
`when`(view.locationOnScreen).thenReturn(location)
doAnswer { invocation ->
- val pos = invocation.arguments[0] as IntArray
- pos[0] = VIEW_LEFT
- pos[1] = VIEW_TOP
- null
- }.`when`(view).getLocationInWindow(any())
+ val pos = invocation.arguments[0] as IntArray
+ pos[0] = VIEW_LEFT
+ pos[1] = VIEW_TOP
+ null
+ }
+ .`when`(view)
+ .getLocationInWindow(any())
}
@Test
@@ -59,9 +64,8 @@ class ViewUtilTest : SysuiTestCase() {
@Test
fun touchIsWithinView_onTopLeftCorner_returnsTrue() {
- assertThat(viewUtil.touchIsWithinView(
- view, VIEW_LEFT.toFloat(), VIEW_TOP.toFloat())
- ).isTrue()
+ assertThat(viewUtil.touchIsWithinView(view, VIEW_LEFT.toFloat(), VIEW_TOP.toFloat()))
+ .isTrue()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
index ed07ad2a0976..207c35da1892 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
@@ -35,15 +35,18 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
import java.util.List;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
+
@SmallTest
-@RunWith(Parameterized.class)
+@RunWith(ParameterizedAndroidJunit4.class)
public class WakeLockTest extends SysuiTestCase {
- @Parameterized.Parameters(name = "{0}")
+ @Parameters(name = "{0}")
public static List<FlagsParameterization> getFlags() {
return FlagsParameterization.allCombinationsOf(
Flags.FLAG_DELAYED_WAKELOCK_RELEASE_ON_BACKGROUND_THREAD);
@@ -114,4 +117,4 @@ public class WakeLockTest extends SysuiTestCase {
// shouldn't throw an exception on production builds
mWakeLock.release(WHY);
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 2bd584eac5e3..562ac0c15a0b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -27,6 +27,8 @@ import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
+import androidx.annotation.NonNull;
+
import com.android.internal.logging.InstanceId;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
@@ -36,6 +38,7 @@ import com.android.systemui.util.time.FakeSystemClock;
import kotlin.Unit;
import java.util.ArrayList;
+import java.util.function.Consumer;
/**
* Combined builder for constructing a NotificationEntry and its associated StatusBarNotification
@@ -73,6 +76,20 @@ public class NotificationEntryBuilder {
mCreationTime = source.getCreationTime();
}
+ /** Allows the caller to sub-build the ranking */
+ @NonNull
+ public NotificationEntryBuilder updateRanking(@NonNull Consumer<RankingBuilder> rankingUpdater) {
+ rankingUpdater.accept(mRankingBuilder);
+ return this;
+ }
+
+ /** Allows the caller to sub-build the SBN */
+ @NonNull
+ public NotificationEntryBuilder updateSbn(@NonNull Consumer<SbnBuilder> sbnUpdater) {
+ sbnUpdater.accept(mSbnBuilder);
+ return this;
+ }
+
/** Update an the parent on an existing entry */
public static void setNewParent(NotificationEntry entry, GroupEntry parent) {
entry.setParent(parent);
diff --git a/proto/src/am_capabilities.proto b/proto/src/am_capabilities.proto
index fc9f7a4590bd..c2b3ac2aaa78 100644
--- a/proto/src/am_capabilities.proto
+++ b/proto/src/am_capabilities.proto
@@ -15,8 +15,16 @@ message FrameworkCapability {
string name = 1;
}
+message VMInfo {
+ // The value of the "java.vm.name" system property
+ string name = 1;
+ // The value of the "java.vm.version" system property
+ string version = 2;
+}
+
message Capabilities {
repeated Capability values = 1;
repeated VMCapability vm_capabilities = 2;
repeated FrameworkCapability framework_capabilities = 3;
+ VMInfo vm_info = 4;
}
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index bc608c5ac0c0..95cbb6b2130a 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -221,7 +221,9 @@ sh_test_host {
data: [
":framework-minus-apex.ravenwood.stats",
":framework-minus-apex.ravenwood.apis",
+ ":framework-minus-apex.ravenwood.keep_all",
":services.core.ravenwood.stats",
":services.core.ravenwood.apis",
+ ":services.core.ravenwood.keep_all",
],
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java
new file mode 100644
index 000000000000..4992c4bcc77a
--- /dev/null
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java
@@ -0,0 +1,753 @@
+/*
+ * 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.platform.test.ravenwood;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.IntentSender.SendIntentException;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.view.Display;
+import android.view.DisplayAdjustments;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A subclass of Context with all the abstract methods replaced with concrete methods.
+ *
+ * <p>In order to make sure it implements all the abstract methods, we intentionally keep it
+ * non-abstract.
+ */
+public class RavenwoodBaseContext extends Context {
+ RavenwoodBaseContext() {
+ // Only usable by ravenwood.
+ }
+
+ private static RuntimeException notSupported() {
+ return new RuntimeException("This Context API is not yet supported under"
+ + " the Ravenwood deviceless testing environment. Contact g/ravenwood");
+ }
+
+ @Override
+ public AssetManager getAssets() {
+ throw notSupported();
+ }
+
+ @Override
+ public Resources getResources() {
+ throw notSupported();
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ throw notSupported();
+ }
+
+ @Override
+ public ContentResolver getContentResolver() {
+ throw notSupported();
+ }
+
+ @Override
+ public Looper getMainLooper() {
+ throw notSupported();
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ throw notSupported();
+ }
+
+ @Override
+ public void setTheme(int resid) {
+ throw notSupported();
+ }
+
+ @Override
+ public Theme getTheme() {
+ throw notSupported();
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ throw notSupported();
+ }
+
+ @Override
+ public String getPackageName() {
+ throw notSupported();
+ }
+
+ @Override
+ public String getBasePackageName() {
+ throw notSupported();
+ }
+
+ @Override
+ public ApplicationInfo getApplicationInfo() {
+ throw notSupported();
+ }
+
+ @Override
+ public String getPackageResourcePath() {
+ throw notSupported();
+ }
+
+ @Override
+ public String getPackageCodePath() {
+ throw notSupported();
+ }
+
+ @Override
+ public SharedPreferences getSharedPreferences(String name, int mode) {
+ throw notSupported();
+ }
+
+ @Override
+ public SharedPreferences getSharedPreferences(File file, int mode) {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean deleteSharedPreferences(String name) {
+ throw notSupported();
+ }
+
+ @Override
+ public void reloadSharedPreferences() {
+ throw notSupported();
+ }
+
+ @Override
+ public FileInputStream openFileInput(String name) throws FileNotFoundException {
+ throw notSupported();
+ }
+
+ @Override
+ public FileOutputStream openFileOutput(String name, int mode) throws FileNotFoundException {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean deleteFile(String name) {
+ throw notSupported();
+ }
+
+ @Override
+ public File getFileStreamPath(String name) {
+ throw notSupported();
+ }
+
+ @Override
+ public File getSharedPreferencesPath(String name) {
+ throw notSupported();
+ }
+
+ @Override
+ public File getDataDir() {
+ throw notSupported();
+ }
+
+ @Override
+ public File getFilesDir() {
+ throw notSupported();
+ }
+
+ @Override
+ public File getNoBackupFilesDir() {
+ throw notSupported();
+ }
+
+ @Override
+ public File getExternalFilesDir(String type) {
+ throw notSupported();
+ }
+
+ @Override
+ public File[] getExternalFilesDirs(String type) {
+ throw notSupported();
+ }
+
+ @Override
+ public File getObbDir() {
+ throw notSupported();
+ }
+
+ @Override
+ public File[] getObbDirs() {
+ throw notSupported();
+ }
+
+ @Override
+ public File getCacheDir() {
+ throw notSupported();
+ }
+
+ @Override
+ public File getCodeCacheDir() {
+ throw notSupported();
+ }
+
+ @Override
+ public File getExternalCacheDir() {
+ throw notSupported();
+ }
+
+ @Override
+ public File getPreloadsFileCache() {
+ throw notSupported();
+ }
+
+ @Override
+ public File[] getExternalCacheDirs() {
+ throw notSupported();
+ }
+
+ @Override
+ public File[] getExternalMediaDirs() {
+ throw notSupported();
+ }
+
+ @Override
+ public String[] fileList() {
+ throw notSupported();
+ }
+
+ @Override
+ public File getDir(String name, int mode) {
+ throw notSupported();
+ }
+
+ @Override
+ public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
+ throw notSupported();
+ }
+
+ @Override
+ public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
+ DatabaseErrorHandler errorHandler) {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean moveDatabaseFrom(Context sourceContext, String name) {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean deleteDatabase(String name) {
+ throw notSupported();
+ }
+
+ @Override
+ public File getDatabasePath(String name) {
+ throw notSupported();
+ }
+
+ @Override
+ public String[] databaseList() {
+ throw notSupported();
+ }
+
+ @Override
+ public Drawable getWallpaper() {
+ throw notSupported();
+ }
+
+ @Override
+ public Drawable peekWallpaper() {
+ throw notSupported();
+ }
+
+ @Override
+ public int getWallpaperDesiredMinimumWidth() {
+ throw notSupported();
+ }
+
+ @Override
+ public int getWallpaperDesiredMinimumHeight() {
+ throw notSupported();
+ }
+
+ @Override
+ public void setWallpaper(Bitmap bitmap) throws IOException {
+ throw notSupported();
+ }
+
+ @Override
+ public void setWallpaper(InputStream data) throws IOException {
+ throw notSupported();
+ }
+
+ @Override
+ public void clearWallpaper() throws IOException {
+ throw notSupported();
+ }
+
+ @Override
+ public void startActivity(Intent intent) {
+ throw notSupported();
+ }
+
+ @Override
+ public void startActivity(Intent intent, Bundle options) {
+ throw notSupported();
+ }
+
+ @Override
+ public void startActivities(Intent[] intents) {
+ throw notSupported();
+ }
+
+ @Override
+ public void startActivities(Intent[] intents, Bundle options) {
+ throw notSupported();
+ }
+
+ @Override
+ public void startIntentSender(IntentSender intent, Intent fillInIntent, int flagsMask,
+ int flagsValues, int extraFlags) throws SendIntentException {
+ throw notSupported();
+ }
+
+ @Override
+ public void startIntentSender(IntentSender intent, Intent fillInIntent, int flagsMask,
+ int flagsValues, int extraFlags, Bundle options) throws SendIntentException {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent, String receiverPermission) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+ int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission,
+ Bundle options) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission,
+ int appOp) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
+ int initialCode, String initialData, Bundle initialExtras) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp, Bundle options,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendStickyBroadcast(Intent intent) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+ throw notSupported();
+
+ }
+
+ @Override
+ public void removeStickyBroadcast(Intent intent) {
+ throw notSupported();
+
+ }
+
+ @Override
+ public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
+ throw notSupported();
+ }
+
+ @Override
+ public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
+ throw notSupported();
+
+ }
+
+ @Override
+ public void sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ throw notSupported();
+ }
+
+ @Override
+ public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
+ throw notSupported();
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ throw notSupported();
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
+ throw notSupported();
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler) {
+ throw notSupported();
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler, int flags) {
+ throw notSupported();
+ }
+
+ @Override
+ public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, String broadcastPermission, Handler scheduler) {
+ throw notSupported();
+ }
+
+ @Override
+ public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+ throw notSupported();
+ }
+
+ @Override
+ public void unregisterReceiver(BroadcastReceiver receiver) {
+ throw notSupported();
+ }
+
+ @Override
+ public ComponentName startService(Intent service) {
+ throw notSupported();
+ }
+
+ @Override
+ public ComponentName startForegroundService(Intent service) {
+ throw notSupported();
+ }
+
+ @Override
+ public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean stopService(Intent service) {
+ throw notSupported();
+ }
+
+ @Override
+ public ComponentName startServiceAsUser(Intent service, UserHandle user) {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean stopServiceAsUser(Intent service, UserHandle user) {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags) {
+ throw notSupported();
+ }
+
+ @Override
+ public void unbindService(ServiceConnection conn) {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean startInstrumentation(ComponentName className, String profileFile,
+ Bundle arguments) {
+ throw notSupported();
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ throw notSupported();
+ }
+
+ @Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkCallingPermission(String permission) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkSelfPermission(String permission) {
+ throw notSupported();
+ }
+
+ @Override
+ public void enforcePermission(String permission, int pid, int uid, String message) {
+ throw notSupported();
+ }
+
+ @Override
+ public void enforceCallingPermission(String permission, String message) {
+ throw notSupported();
+ }
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ throw notSupported();
+ }
+
+ @Override
+ public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
+ throw notSupported();
+ }
+
+ @Override
+ public void revokeUriPermission(Uri uri, int modeFlags) {
+ throw notSupported();
+ }
+
+ @Override
+ public void revokeUriPermission(String toPackage, Uri uri, int modeFlags) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkCallingUriPermission(Uri uri, int modeFlags) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
+ throw notSupported();
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, String readPermission, String writePermission,
+ int pid, int uid, int modeFlags) {
+ throw notSupported();
+ }
+
+ @Override
+ public void enforceUriPermission(Uri uri, int pid, int uid, int modeFlags, String message) {
+ throw notSupported();
+ }
+
+ @Override
+ public void enforceCallingUriPermission(Uri uri, int modeFlags, String message) {
+ throw notSupported();
+ }
+
+ @Override
+ public void enforceCallingOrSelfUriPermission(Uri uri, int modeFlags, String message) {
+ throw notSupported();
+ }
+
+ @Override
+ public void enforceUriPermission(Uri uri, String readPermission, String writePermission,
+ int pid, int uid, int modeFlags, String message) {
+ throw notSupported();
+ }
+
+ @Override
+ public Context createPackageContext(String packageName, int flags)
+ throws NameNotFoundException {
+ throw notSupported();
+ }
+
+ @Override
+ public Context createApplicationContext(ApplicationInfo application, int flags)
+ throws NameNotFoundException {
+ throw notSupported();
+ }
+
+ @Override
+ public Context createContextForSplit(String splitName) throws NameNotFoundException {
+ throw notSupported();
+ }
+
+ @Override
+ public Context createConfigurationContext(Configuration overrideConfiguration) {
+ throw notSupported();
+ }
+
+ @Override
+ public Context createDisplayContext(Display display) {
+ throw notSupported();
+ }
+
+ @Override
+ public Context createDeviceProtectedStorageContext() {
+ throw notSupported();
+ }
+
+ @Override
+ public Context createCredentialProtectedStorageContext() {
+ throw notSupported();
+ }
+
+ @Override
+ public DisplayAdjustments getDisplayAdjustments(int displayId) {
+ throw notSupported();
+ }
+
+ @Override
+ public int getDisplayId() {
+ throw notSupported();
+ }
+
+ @Override
+ public void updateDisplay(int displayId) {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean isDeviceProtectedStorage() {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean isCredentialProtectedStorage() {
+ throw notSupported();
+ }
+
+ @Override
+ public boolean canLoadUnsafeResources() {
+ throw notSupported();
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
index 109ef76b535f..1dd5e1ddd630 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
@@ -28,7 +28,6 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.ravenwood.example.BlueManager;
import android.ravenwood.example.RedManager;
-import android.test.mock.MockContext;
import android.util.ArrayMap;
import android.util.Singleton;
@@ -36,7 +35,7 @@ import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
-public class RavenwoodContext extends MockContext {
+public class RavenwoodContext extends RavenwoodBaseContext {
private final String mPackageName;
private final HandlerThread mMainThread;
diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh
index cf58bd2f3717..43b61a46b747 100755
--- a/ravenwood/scripts/ravenwood-stats-collector.sh
+++ b/ravenwood/scripts/ravenwood-stats-collector.sh
@@ -18,8 +18,14 @@
set -e
# Output files
-stats=/tmp/ravenwood-stats-all.csv
-apis=/tmp/ravenwood-apis-all.csv
+out_dir=/tmp/ravenwood
+stats=$out_dir/ravenwood-stats-all.csv
+apis=$out_dir/ravenwood-apis-all.csv
+keep_all_dir=$out_dir/ravenwood-keep-all/
+
+rm -fr $out_dir
+mkdir -p $out_dir
+mkdir -p $keep_all_dir
# Where the input files are.
path=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/ravenwood-stats-checker/x86_64/
@@ -76,3 +82,7 @@ collect_apis() {
collect_stats $stats
collect_apis $apis
+
+cp *keep_all.txt $keep_all_dir
+echo "Keep all files created at:"
+find $keep_all_dir -type f \ No newline at end of file
diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
index e452299373f8..d856f6d669eb 100644
--- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
@@ -1,5 +1,7 @@
# Only classes listed here can use the Ravenwood annotations.
+com.android.internal.ravenwood.*
+
com.android.internal.display.BrightnessSynchronizer
com.android.internal.util.ArrayUtils
com.android.internal.logging.MetricsLogger
diff --git a/ravenwood/texts/ravenwood-framework-policies.txt b/ravenwood/texts/ravenwood-framework-policies.txt
index 371c3acab144..9d29a051d092 100644
--- a/ravenwood/texts/ravenwood-framework-policies.txt
+++ b/ravenwood/texts/ravenwood-framework-policies.txt
@@ -1,59 +1,59 @@
# Ravenwood "policy" file for framework-minus-apex.
# Keep all AIDL interfaces
-class :aidl stubclass
+class :aidl keepclass
# Keep all feature flag implementations
-class :feature_flags stubclass
+class :feature_flags keepclass
# Keep all sysprops generated code implementations
-class :sysprops stubclass
+class :sysprops keepclass
# Exported to Mainline modules; cannot use annotations
-class com.android.internal.util.FastXmlSerializer stubclass
-class com.android.internal.util.FileRotator stubclass
-class com.android.internal.util.HexDump stubclass
-class com.android.internal.util.IndentingPrintWriter stubclass
-class com.android.internal.util.LocalLog stubclass
-class com.android.internal.util.MessageUtils stubclass
-class com.android.internal.util.TokenBucket stubclass
-class android.os.HandlerExecutor stubclass
-class android.util.BackupUtils stubclass
-class android.util.IndentingPrintWriter stubclass
-class android.util.LocalLog stubclass
-class android.util.Pair stubclass
-class android.util.Rational stubclass
+class com.android.internal.util.FastXmlSerializer keepclass
+class com.android.internal.util.FileRotator keepclass
+class com.android.internal.util.HexDump keepclass
+class com.android.internal.util.IndentingPrintWriter keepclass
+class com.android.internal.util.LocalLog keepclass
+class com.android.internal.util.MessageUtils keepclass
+class com.android.internal.util.TokenBucket keepclass
+class android.os.HandlerExecutor keepclass
+class android.util.BackupUtils keepclass
+class android.util.IndentingPrintWriter keepclass
+class android.util.LocalLog keepclass
+class android.util.Pair keepclass
+class android.util.Rational keepclass
# From modules-utils; cannot use annotations
-class com.android.internal.util.Preconditions stubclass
-class com.android.internal.logging.InstanceId stubclass
-class com.android.internal.logging.InstanceIdSequence stubclass
-class com.android.internal.logging.UiEvent stubclass
-class com.android.internal.logging.UiEventLogger stubclass
+class com.android.internal.util.Preconditions keepclass
+class com.android.internal.logging.InstanceId keepclass
+class com.android.internal.logging.InstanceIdSequence keepclass
+class com.android.internal.logging.UiEvent keepclass
+class com.android.internal.logging.UiEventLogger keepclass
# From modules-utils; cannot use annotations
-class com.android.modules.utils.BinaryXmlPullParser stubclass
-class com.android.modules.utils.BinaryXmlSerializer stubclass
-class com.android.modules.utils.FastDataInput stubclass
-class com.android.modules.utils.FastDataOutput stubclass
-class com.android.modules.utils.ModifiedUtf8 stubclass
-class com.android.modules.utils.TypedXmlPullParser stubclass
-class com.android.modules.utils.TypedXmlSerializer stubclass
+class com.android.modules.utils.BinaryXmlPullParser keepclass
+class com.android.modules.utils.BinaryXmlSerializer keepclass
+class com.android.modules.utils.FastDataInput keepclass
+class com.android.modules.utils.FastDataOutput keepclass
+class com.android.modules.utils.ModifiedUtf8 keepclass
+class com.android.modules.utils.TypedXmlPullParser keepclass
+class com.android.modules.utils.TypedXmlSerializer keepclass
# Uri
-class android.net.Uri stubclass
-class android.net.UriCodec stubclass
+class android.net.Uri keepclass
+class android.net.UriCodec keepclass
# Telephony
-class android.telephony.PinResult stubclass
+class android.telephony.PinResult keepclass
# Just enough to support mocking, no further functionality
-class android.content.BroadcastReceiver stub
- method <init> ()V stub
-class android.content.Context stub
- method <init> ()V stub
- method getSystemService (Ljava/lang/Class;)Ljava/lang/Object; stub
-class android.content.pm.PackageManager stub
- method <init> ()V stub
-class android.text.ClipboardManager stub
- method <init> ()V stub
+class android.content.BroadcastReceiver keep
+ method <init> ()V keep
+class android.content.Context keep
+ method <init> ()V keep
+ method getSystemService (Ljava/lang/Class;)Ljava/lang/Object; keep
+class android.content.pm.PackageManager keep
+ method <init> ()V keep
+class android.text.ClipboardManager keep
+ method <init> ()V keep
diff --git a/ravenwood/texts/ravenwood-services-policies.txt b/ravenwood/texts/ravenwood-services-policies.txt
index d8d563e05435..5cdb4f74d7c0 100644
--- a/ravenwood/texts/ravenwood-services-policies.txt
+++ b/ravenwood/texts/ravenwood-services-policies.txt
@@ -1,7 +1,7 @@
# Ravenwood "policy" file for services.core.
# Keep all AIDL interfaces
-class :aidl stubclass
+class :aidl keepclass
# Keep all feature flag implementations
-class :feature_flags stubclass
+class :feature_flags keepclass
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index 468b9ab5710e..219b788448e8 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -36,6 +36,7 @@ import android.view.inputmethod.InlineSuggestionsResponse;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback;
import com.android.internal.inputmethod.IInlineSuggestionsResponseCallback;
+import com.android.internal.inputmethod.InlineSuggestionsRequestCallback;
import com.android.internal.inputmethod.InlineSuggestionsRequestInfo;
import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -376,8 +377,8 @@ final class AutofillInlineSuggestionsRequestSession {
/**
* Internal implementation of {@link IInlineSuggestionsRequestCallback}.
*/
- private static final class InlineSuggestionsRequestCallbackImpl extends
- IInlineSuggestionsRequestCallback.Stub {
+ private static final class InlineSuggestionsRequestCallbackImpl
+ implements InlineSuggestionsRequestCallback {
private final WeakReference<AutofillInlineSuggestionsRequestSession> mSession;
@@ -388,7 +389,7 @@ final class AutofillInlineSuggestionsRequestSession {
@BinderThread
@Override
- public void onInlineSuggestionsUnsupported() throws RemoteException {
+ public void onInlineSuggestionsUnsupported() {
if (sDebug) Slog.d(TAG, "onInlineSuggestionsUnsupported() called.");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
@@ -412,7 +413,7 @@ final class AutofillInlineSuggestionsRequestSession {
}
@Override
- public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException {
+ public void onInputMethodStartInput(AutofillId imeFieldId) {
if (sVerbose) Slog.v(TAG, "onInputMethodStartInput() received on " + imeFieldId);
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
@@ -423,7 +424,7 @@ final class AutofillInlineSuggestionsRequestSession {
}
@Override
- public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException {
+ public void onInputMethodShowInputRequested(boolean requestResult) {
if (sVerbose) {
Slog.v(TAG, "onInputMethodShowInputRequested() received: " + requestResult);
}
@@ -454,7 +455,7 @@ final class AutofillInlineSuggestionsRequestSession {
}
@Override
- public void onInputMethodFinishInput() throws RemoteException {
+ public void onInputMethodFinishInput() {
if (sVerbose) Slog.v(TAG, "onInputMethodFinishInput() received");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
@@ -466,7 +467,7 @@ final class AutofillInlineSuggestionsRequestSession {
@BinderThread
@Override
- public void onInlineSuggestionsSessionInvalidated() throws RemoteException {
+ public void onInlineSuggestionsSessionInvalidated() {
if (sDebug) Slog.d(TAG, "onInlineSuggestionsSessionInvalidated() called.");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
index 0e66fbc020a1..71a182225013 100644
--- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
+++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.os.Build;
import android.util.Slog;
+import com.google.security.cryptauth.lib.securegcm.ukey2.AlertException;
import com.google.security.cryptauth.lib.securegcm.ukey2.BadHandleException;
import com.google.security.cryptauth.lib.securegcm.ukey2.CryptoException;
import com.google.security.cryptauth.lib.securegcm.ukey2.D2DConnectionContextV1;
@@ -203,7 +204,8 @@ public class SecureChannel {
*
* This method must only be called from one of the two participants.
*/
- public void establishSecureConnection() throws IOException, SecureChannelException {
+ public void establishSecureConnection() throws IOException,
+ SecureChannelException, HandshakeException {
if (isSecured()) {
Slog.d(TAG, "Channel is already secure.");
return;
@@ -334,7 +336,7 @@ public class SecureChannel {
}
}
- private void initiateHandshake() throws IOException, BadHandleException {
+ private void initiateHandshake() throws IOException, BadHandleException , HandshakeException {
if (mConnectionContext != null) {
Slog.d(TAG, "Ukey2 handshake is already completed.");
return;
@@ -394,8 +396,8 @@ public class SecureChannel {
}
}
- private void exchangeHandshake()
- throws IOException, HandshakeException, BadHandleException, CryptoException {
+ private void exchangeHandshake() throws IOException, HandshakeException,
+ BadHandleException, CryptoException, AlertException {
if (mConnectionContext != null) {
Slog.d(TAG, "Ukey2 handshake is already completed.");
return;
diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
index 9a73a2d75419..f5db6e962d01 100644
--- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
+++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
@@ -27,9 +27,9 @@ import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static com.android.server.contextualsearch.flags.Flags.enableExcludePersistentUi;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
@@ -286,13 +286,11 @@ public class ContextualSearchManagerService extends SystemService {
}
final ScreenCapture.ScreenshotHardwareBuffer shb;
if (mWmInternal != null) {
- if (enableExcludePersistentUi()) {
- shb = mWmInternal.takeAssistScreenshot(
- Set.of(TYPE_STATUS_BAR, TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL));
- } else {
- shb = mWmInternal.takeAssistScreenshot(/* windowTypesToExclude= */ Set.of());
- }
-
+ shb = mWmInternal.takeAssistScreenshot(Set.of(
+ TYPE_STATUS_BAR,
+ TYPE_NAVIGATION_BAR,
+ TYPE_NAVIGATION_BAR_PANEL,
+ TYPE_POINTER));
} else {
shb = null;
}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index d04dbc2f417e..d9e6186639ce 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -870,6 +870,7 @@ public final class PinnerService extends SystemService {
}
synchronized (this) {
pinnedApp.mFiles.add(pf);
+ mPinnedFiles.put(pf.fileName, pf);
}
apkPinSizeLimit -= pf.bytesPinned;
@@ -1341,18 +1342,6 @@ public final class PinnerService extends SystemService {
public List<PinnedFileStat> getPinnerStats() {
ArrayList<PinnedFileStat> stats = new ArrayList<>();
- Collection<PinnedApp> pinnedApps;
- synchronized(this) {
- pinnedApps = mPinnedApps.values();
- }
- for (PinnedApp pinnedApp : pinnedApps) {
- for (PinnedFile pf : pinnedApp.mFiles) {
- PinnedFileStat stat =
- new PinnedFileStat(pf.fileName, pf.bytesPinned, pf.groupName);
- stats.add(stat);
- }
- }
-
Collection<PinnedFile> pinnedFiles;
synchronized(this) {
pinnedFiles = mPinnedFiles.values();
diff --git a/services/core/java/com/android/server/WallpaperUpdateReceiver.java b/services/core/java/com/android/server/WallpaperUpdateReceiver.java
index 2812233815a6..42391a55fed6 100644
--- a/services/core/java/com/android/server/WallpaperUpdateReceiver.java
+++ b/services/core/java/com/android/server/WallpaperUpdateReceiver.java
@@ -24,7 +24,6 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.ParcelFileDescriptor;
import android.util.Slog;
@@ -59,10 +58,10 @@ public class WallpaperUpdateReceiver extends BroadcastReceiver {
return;
}
if (DEBUG) Slog.d(TAG, "Set customized default_wallpaper.");
- Bitmap blank = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
- // set a blank wallpaper to force a redraw of default_wallpaper
- wallpaperManager.setBitmap(blank);
- wallpaperManager.setResource(com.android.internal.R.drawable.default_wallpaper);
+ // Check if it is not a live wallpaper set
+ if (wallpaperManager.getWallpaperInfo() == null) {
+ wallpaperManager.clearWallpaper();
+ }
} catch (Exception e) {
Slog.w(TAG, "Failed to customize system wallpaper." + e);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 94bf813d3696..9be0e1ff464e 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3783,6 +3783,14 @@ public final class ActiveServices {
return fgsInfo.getLastFgsStartTime() + Math.max(0, timeLimit - fgsInfo.getTotalRuntime());
}
+ private TimeLimitedFgsInfo getFgsTimeLimitedInfo(int uid, int fgsType) {
+ final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(uid);
+ if (fgsInfo != null) {
+ return fgsInfo.get(fgsType);
+ }
+ return null;
+ }
+
private void maybeUpdateFgsTrackingLocked(ServiceRecord sr, int previousFgsType) {
final int previouslyTimeLimitedType = getTimeLimitedFgsType(previousFgsType);
if (previouslyTimeLimitedType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE
@@ -3793,16 +3801,12 @@ public final class ActiveServices {
if (previouslyTimeLimitedType != ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) {
// FGS is switching types and the previous type was time-limited so update the runtime.
- final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid);
- if (fgsInfo != null) {
- final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(previouslyTimeLimitedType);
- if (fgsTypeInfo != null) {
- // Update the total runtime for the previous time-limited fgs type.
- fgsTypeInfo.updateTotalRuntime();
- // TODO(b/330399444): handle the case where an app is running 2 services of the
- // same time-limited type in parallel and stops one of them which leads to the
- // second running one gaining additional runtime.
- }
+ final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(
+ sr.appInfo.uid, previouslyTimeLimitedType);
+ if (fgsTypeInfo != null) {
+ // Update the total runtime for the previous time-limited fgs type.
+ fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis());
+ fgsTypeInfo.decNumParallelServices();
}
if (!sr.isFgsTimeLimited()) {
@@ -3825,10 +3829,10 @@ public final class ActiveServices {
final int timeLimitedFgsType = getTimeLimitedFgsType(sr.foregroundServiceType);
TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedFgsType);
if (fgsTypeInfo == null) {
- fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowUptime);
+ fgsTypeInfo = sr.createTimeLimitedFgsInfo();
fgsInfo.put(timeLimitedFgsType, fgsTypeInfo);
}
- fgsTypeInfo.setLastFgsStartTime(nowUptime);
+ fgsTypeInfo.noteFgsFgsStart(nowUptime);
// We'll cancel the previous ANR timer and start a fresh one below.
mFGSAnrTimer.cancel(sr);
@@ -3852,13 +3856,12 @@ public final class ActiveServices {
return; // if the current fgs type is not time-limited, return.
}
- final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid);
- if (fgsInfo != null) {
- final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedType);
- if (fgsTypeInfo != null) {
- // Update the total runtime for the previous time-limited fgs type.
- fgsTypeInfo.updateTotalRuntime();
- }
+ final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(
+ sr.appInfo.uid, timeLimitedType);
+ if (fgsTypeInfo != null) {
+ // Update the total runtime for the previous time-limited fgs type.
+ fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis());
+ fgsTypeInfo.decNumParallelServices();
}
Slog.d(TAG_SERVICE, "Stop FGS timeout: " + sr);
mFGSAnrTimer.cancel(sr);
@@ -3913,24 +3916,21 @@ public final class ActiveServices {
mFGSAnrTimer.accept(sr);
traceInstant("FGS timed out: ", sr);
- final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid);
- if (fgsInfo != null) {
- final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(fgsType);
- if (fgsTypeInfo != null) {
- // Update total runtime for the time-limited fgs type and mark it as timed out.
- fgsTypeInfo.updateTotalRuntime();
- fgsTypeInfo.setTimeLimitExceededAt(nowUptime);
-
- logFGSStateChangeLocked(sr,
- FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT,
- nowUptime > fgsTypeInfo.getLastFgsStartTime()
- ? (int) (nowUptime - fgsTypeInfo.getLastFgsStartTime()) : 0,
- FGS_STOP_REASON_UNKNOWN,
- FGS_TYPE_POLICY_CHECK_UNKNOWN,
- FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA,
- false /* fgsRestrictionRecalculated */
- );
- }
+ final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType);
+ if (fgsTypeInfo != null) {
+ // Update total runtime for the time-limited fgs type and mark it as timed out.
+ fgsTypeInfo.updateTotalRuntime(nowUptime);
+ fgsTypeInfo.setTimeLimitExceededAt(nowUptime);
+
+ logFGSStateChangeLocked(sr,
+ FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT,
+ nowUptime > fgsTypeInfo.getFirstFgsStartUptime()
+ ? (int) (nowUptime - fgsTypeInfo.getFirstFgsStartUptime()) : 0,
+ FGS_STOP_REASON_UNKNOWN,
+ FGS_TYPE_POLICY_CHECK_UNKNOWN,
+ FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA,
+ false /* fgsRestrictionRecalculated */
+ );
}
try {
@@ -3949,6 +3949,16 @@ public final class ActiveServices {
if (fgsType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) {
return; // no timed out FGS type was found (either it was stopped or it switched types)
}
+
+ synchronized (mAm) {
+ final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType);
+ if (fgsTypeInfo != null) {
+ // Runtime is already updated when the service times out - if the app didn't
+ // stop the service, decrement the number of parallel running services here.
+ fgsTypeInfo.decNumParallelServices();
+ }
+ }
+
final String reason = "A foreground service of type "
+ ServiceInfo.foregroundServiceTypeToLabel(fgsType)
+ " did not stop within its timeout: " + sr.getComponentName();
@@ -3958,7 +3968,6 @@ public final class ActiveServices {
Slog.wtf(TAG, reason);
return;
}
-
if (android.app.Flags.enableFgsTimeoutCrashBehavior()) {
// Crash the app
synchronized (mAm) {
@@ -4005,7 +4014,6 @@ public final class ActiveServices {
private void stopServiceAndUpdateAllowlistManagerLocked(ServiceRecord service) {
maybeStopShortFgsTimeoutLocked(service);
- maybeStopFgsTimeoutLocked(service);
final ProcessServiceRecord psr = service.app.mServices;
psr.stopService(service);
psr.updateBoundClientUids();
@@ -6291,7 +6299,6 @@ public final class ActiveServices {
Slog.w(TAG_SERVICE, "Short FGS brought down without stopping: " + r);
maybeStopShortFgsTimeoutLocked(r);
}
- maybeStopFgsTimeoutLocked(r);
// Report to all of the connections that the service is no longer
// available.
@@ -6416,7 +6423,6 @@ public final class ActiveServices {
final boolean exitingFg = r.isForeground;
if (exitingFg) {
maybeStopShortFgsTimeoutLocked(r);
- maybeStopFgsTimeoutLocked(r);
decActiveForegroundAppLocked(smap, r);
synchronized (mAm.mProcessStats.mLock) {
ServiceState stracker = r.getTracker();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 46ed1fd79874..008d7b20c5fd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -598,6 +598,9 @@ public class ActivityManagerService extends IActivityManager.Stub
// as one line, but close enough for now.
static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100;
+ // How many seconds should the system wait before terminating the spawned logcat process.
+ static final int LOGCAT_TIMEOUT_SEC = 10;
+
// Necessary ApplicationInfo flags to mark an app as persistent
static final int PERSISTENT_MASK =
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
@@ -9939,126 +9942,70 @@ public class ActivityManagerService extends IActivityManager.Stub
// If process is null, we are being called from some internal code
// and may be about to die -- run this synchronously.
final boolean runSynchronously = process == null;
- Thread worker =
- new Thread("Error dump: " + dropboxTag) {
- @Override
- public void run() {
- if (report != null) {
- sb.append(report);
- }
-
- String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
- String maxBytesSetting =
- Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag;
- int lines =
- Build.IS_USER
- ? 0
- : Settings.Global.getInt(
- mContext.getContentResolver(), logcatSetting, 0);
- int dropboxMaxSize =
- Settings.Global.getInt(
- mContext.getContentResolver(),
- maxBytesSetting,
- DROPBOX_DEFAULT_MAX_SIZE);
-
- if (dataFile != null) {
- // Attach the stack traces file to the report so collectors can load
- // them
- // by file if they have access.
- sb.append(DATA_FILE_PATH_HEADER)
- .append(dataFile.getAbsolutePath())
- .append('\n');
-
- int maxDataFileSize =
- dropboxMaxSize
- - sb.length()
- - lines * RESERVED_BYTES_PER_LOGCAT_LINE
- - DATA_FILE_PATH_FOOTER.length();
-
- if (maxDataFileSize > 0) {
- // Inline dataFile contents if there is room.
- try {
- sb.append(
- FileUtils.readTextFile(
- dataFile,
- maxDataFileSize,
- "\n\n[[TRUNCATED]]\n"));
- } catch (IOException e) {
- Slog.e(TAG, "Error reading " + dataFile, e);
- }
- }
-
- // Always append the footer, even there wasn't enough space to inline
- // the
- // dataFile contents.
- sb.append(DATA_FILE_PATH_FOOTER);
- }
-
- if (crashInfo != null && crashInfo.stackTrace != null) {
- sb.append(crashInfo.stackTrace);
- }
-
- if (lines > 0 && !runSynchronously) {
- sb.append("\n");
-
- InputStreamReader input = null;
- try {
- java.lang.Process logcat =
- new ProcessBuilder(
- // Time out after 10s of inactivity, but
- // kill logcat with SEGV
- // so we can investigate why it didn't
- // finish.
- "/system/bin/timeout",
- "-i",
- "-s",
- "SEGV",
- "10s",
- // Merge several logcat streams, and take
- // the last N lines.
- "/system/bin/logcat",
- "-v",
- "threadtime",
- "-b",
- "events",
- "-b",
- "system",
- "-b",
- "main",
- "-b",
- "crash",
- "-t",
- String.valueOf(lines))
- .redirectErrorStream(true)
- .start();
-
- try {
- logcat.getOutputStream().close();
- } catch (IOException e) {
- }
- try {
- logcat.getErrorStream().close();
- } catch (IOException e) {
- }
- input = new InputStreamReader(logcat.getInputStream());
-
- int num;
- char[] buf = new char[8192];
- while ((num = input.read(buf)) > 0) sb.append(buf, 0, num);
- } catch (IOException e) {
- Slog.e(TAG, "Error running logcat", e);
- } finally {
- if (input != null)
- try {
- input.close();
- } catch (IOException e) {
- }
- }
+ Thread worker = new Thread("Error dump: " + dropboxTag) {
+ @Override
+ public void run() {
+ if (report != null) {
+ sb.append(report);
+ }
+
+ String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
+ String kerLogSetting = Settings.Global.ERROR_KERNEL_LOG_PREFIX + dropboxTag;
+ String maxBytesSetting = Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag;
+ int logcatLines = Build.IS_USER
+ ? 0
+ : Settings.Global.getInt(mContext.getContentResolver(), logcatSetting, 0);
+ int kernelLogLines = Build.IS_USER
+ ? 0
+ : Settings.Global.getInt(mContext.getContentResolver(), kerLogSetting, 0);
+ int dropboxMaxSize = Settings.Global.getInt(
+ mContext.getContentResolver(), maxBytesSetting, DROPBOX_DEFAULT_MAX_SIZE);
+
+ if (dataFile != null) {
+ // Attach the stack traces file to the report so collectors can load them
+ // by file if they have access.
+ sb.append(DATA_FILE_PATH_HEADER)
+ .append(dataFile.getAbsolutePath()).append('\n');
+
+ int maxDataFileSize = dropboxMaxSize
+ - sb.length()
+ - logcatLines * RESERVED_BYTES_PER_LOGCAT_LINE
+ - kernelLogLines * RESERVED_BYTES_PER_LOGCAT_LINE
+ - DATA_FILE_PATH_FOOTER.length();
+
+ if (maxDataFileSize > 0) {
+ // Inline dataFile contents if there is room.
+ try {
+ sb.append(FileUtils.readTextFile(dataFile, maxDataFileSize,
+ "\n\n[[TRUNCATED]]\n"));
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading " + dataFile, e);
}
+ }
+ // Always append the footer, even there wasn't enough space to inline the
+ // dataFile contents.
+ sb.append(DATA_FILE_PATH_FOOTER);
+ }
- dbox.addText(dropboxTag, sb.toString());
+ if (crashInfo != null && crashInfo.stackTrace != null) {
+ sb.append(crashInfo.stackTrace);
+ }
+ boolean shouldAddLogs = logcatLines > 0 || kernelLogLines > 0;
+ if (!runSynchronously && shouldAddLogs) {
+ sb.append("\n");
+ if (logcatLines > 0) {
+ fetchLogcatBuffers(sb, logcatLines, LOGCAT_TIMEOUT_SEC,
+ List.of("events", "system", "main", "crash"));
}
- };
+ if (kernelLogLines > 0) {
+ fetchLogcatBuffers(sb, kernelLogLines, LOGCAT_TIMEOUT_SEC / 2,
+ List.of("kernel"));
+ }
+ }
+
+ dbox.addText(dropboxTag, sb.toString());
+ }
+ };
if (runSynchronously) {
final int oldMask = StrictMode.allowThreadDiskWritesMask();
@@ -10321,6 +10268,67 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
+ * Retrieves logs from specified logcat buffers and appends them to a StringBuilder
+ * in the supplied order. The method executes a logcat command to fetch specific
+ * log entries from the supplied buffers.
+ *
+ * @param sb the StringBuilder to append the logcat output to.
+ * @param lines the number of lines to retrieve.
+ * @param timeout the maximum allowed time in seconds for logcat to run before being terminated.
+ * @param buffers the list of log buffers from which to retrieve logs.
+ */
+ private static void fetchLogcatBuffers(StringBuilder sb, int lines,
+ int timeout, List<String> buffers) {
+
+ if (buffers.size() == 0 || lines <= 0 || timeout <= 0) {
+ return;
+ }
+
+ List<String> command = new ArrayList<>(10 + (2 * buffers.size()));
+ // Time out after 10s of inactivity, but kill logcat with SEGV
+ // so we can investigate why it didn't finish.
+ command.add("/system/bin/timeout");
+ command.add("-i");
+ command.add("-s");
+ command.add("SEGV");
+ command.add(timeout + "s");
+
+ // Merge several logcat streams, and take the last N lines.
+ command.add("/system/bin/logcat");
+ command.add("-v");
+ // This adds a timestamp and thread info to each log line.
+ command.add("threadtime");
+ for (String buffer : buffers) {
+ command.add("-b");
+ command.add(buffer);
+ }
+ // Limit the output to the last N lines.
+ command.add("-t");
+ command.add(String.valueOf(lines));
+
+ try {
+ java.lang.Process proc =
+ new ProcessBuilder(command).redirectErrorStream(true).start();
+
+ // Close the output stream immediately as we do not send input to the process.
+ try {
+ proc.getOutputStream().close();
+ } catch (IOException e) {
+ }
+
+ try (InputStreamReader reader = new InputStreamReader(proc.getInputStream())) {
+ char[] buffer = new char[8192];
+ int numRead;
+ while ((numRead = reader.read(buffer, 0, buffer.length)) > 0) {
+ sb.append(buffer, 0, numRead);
+ }
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Error running logcat", e);
+ }
+ }
+
+ /**
* Check if the calling process has the permission to dump given package,
* throw SecurityException if it doesn't have the permission.
*
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index a182a106ed8c..bbd432340e8f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -130,6 +130,7 @@ import com.android.server.am.nano.Capabilities;
import com.android.server.am.nano.Capability;
import com.android.server.am.nano.FrameworkCapability;
import com.android.server.am.nano.VMCapability;
+import com.android.server.am.nano.VMInfo;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.Slogf;
@@ -460,6 +461,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
return -1;
}
}
+ String vmName = System.getProperty("java.vm.name", "?");
+ String vmVersion = System.getProperty("java.vm.version", "?");
if (outputAsProtobuf) {
Capabilities capabilities = new Capabilities();
@@ -486,6 +489,11 @@ final class ActivityManagerShellCommand extends ShellCommand {
capabilities.frameworkCapabilities[i] = cap;
}
+ VMInfo vmInfo = new VMInfo();
+ vmInfo.name = vmName;
+ vmInfo.version = vmVersion;
+ capabilities.vmInfo = vmInfo;
+
try {
getRawOutputStream().write(Capabilities.toByteArray(capabilities));
} catch (IOException e) {
@@ -505,6 +513,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
for (String capability : Debug.getFeatureList()) {
pw.println("framework:" + capability);
}
+ pw.println("vm_name:" + vmName);
+ pw.println("vm_version:" + vmVersion);
}
return 0;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 8eca4fc0d2ff..218434049869 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -690,10 +690,14 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
private long mTimeLimitExceededAt = Long.MIN_VALUE;
@UptimeMillisLong
private long mTotalRuntime = 0;
+ private int mNumParallelServices = 0;
- TimeLimitedFgsInfo(@UptimeMillisLong long startTime) {
- mFirstFgsStartUptime = startTime;
- mFirstFgsStartRealtime = SystemClock.elapsedRealtime();
+ public void noteFgsFgsStart(@UptimeMillisLong long startTime) {
+ mNumParallelServices++;
+ if (mNumParallelServices == 1) {
+ mFirstFgsStartUptime = startTime;
+ mFirstFgsStartRealtime = SystemClock.elapsedRealtime();
+ }
mLastFgsStartTime = startTime;
}
@@ -707,17 +711,23 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
return mFirstFgsStartRealtime;
}
- public void setLastFgsStartTime(@UptimeMillisLong long startTime) {
- mLastFgsStartTime = startTime;
- }
-
@UptimeMillisLong
public long getLastFgsStartTime() {
return mLastFgsStartTime;
}
- public void updateTotalRuntime() {
- mTotalRuntime += SystemClock.uptimeMillis() - mLastFgsStartTime;
+ public void decNumParallelServices() {
+ if (mNumParallelServices > 0) {
+ mNumParallelServices--;
+ }
+ if (mNumParallelServices == 0) {
+ mLastFgsStartTime = 0;
+ }
+ }
+
+ public void updateTotalRuntime(@UptimeMillisLong long nowUptime) {
+ mTotalRuntime += nowUptime - mLastFgsStartTime;
+ mLastFgsStartTime = nowUptime;
}
@UptimeMillisLong
@@ -735,6 +745,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
public void reset() {
+ mNumParallelServices = 0;
mFirstFgsStartUptime = 0;
mFirstFgsStartRealtime = 0;
mLastFgsStartTime = 0;
@@ -1872,8 +1883,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
/**
* Called when a time-limited FGS starts.
*/
- public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@UptimeMillisLong long nowUptime) {
- return new TimeLimitedFgsInfo(nowUptime);
+ public TimeLimitedFgsInfo createTimeLimitedFgsInfo() {
+ return new TimeLimitedFgsInfo();
}
/**
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index d9c3ab806888..30d12e670a6c 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -1189,7 +1189,11 @@ public class AutomaticBrightnessController {
update();
}
- void switchMode(@AutomaticBrightnessMode int mode) {
+ /**
+ * Responsible for switching the AutomaticBrightnessMode of the associated display. Also takes
+ * care of resetting the short term model wherever required
+ */
+ public void switchMode(@AutomaticBrightnessMode int mode) {
if (!mBrightnessMappingStrategyMap.contains(mode)) {
return;
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 70a1014a0c8c..875fd059d612 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -84,6 +84,7 @@ import com.android.server.display.brightness.BrightnessUtils;
import com.android.server.display.brightness.DisplayBrightnessController;
import com.android.server.display.brightness.clamper.BrightnessClamperController;
import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy2;
+import com.android.server.display.brightness.strategy.DisplayBrightnessStrategyConstants;
import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
import com.android.server.display.config.HysteresisLevels;
@@ -1333,12 +1334,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mDisplayStateController.shouldPerformScreenOffTransition());
state = mPowerState.getScreenState();
- // Switch to doze auto-brightness mode if needed
- if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null
- && !mAutomaticBrightnessController.isInIdleMode()) {
- mAutomaticBrightnessController.switchMode(Display.isDozeState(state)
- ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
- }
DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController
.updateBrightness(mPowerRequest, state);
@@ -1372,6 +1367,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final boolean wasShortTermModelActive =
mAutomaticBrightnessStrategy.isShortTermModelActive();
if (!mFlags.isRefactorDisplayPowerControllerEnabled()) {
+ // Switch to doze auto-brightness mode if needed
+ if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null
+ && !mAutomaticBrightnessController.isInIdleMode()) {
+ mAutomaticBrightnessController.switchMode(Display.isDozeState(state)
+ ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
+ }
+
mAutomaticBrightnessStrategy.setAutoBrightnessState(state,
mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(),
mBrightnessReasonTemp.getReason(), mPowerRequest.policy,
@@ -1440,45 +1442,52 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
brightnessState = clampScreenBrightness(brightnessState);
}
- // If there's an offload session, we need to set the initial doze brightness before
- // the offload session starts controlling the brightness.
- // During the transition DOZE_SUSPEND -> DOZE -> DOZE_SUSPEND, this brightness strategy
- // will be selected again, meaning that no new brightness will be sent to the hardware and
- // the display will stay at the brightness level set by the offload session.
- if (Float.isNaN(brightnessState) && mFlags.isDisplayOffloadEnabled()
- && Display.isDozeState(state) && mDisplayOffloadSession != null) {
- if (mAutomaticBrightnessController != null
- && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
- // Use the auto-brightness curve and the last observed lux
- rawBrightnessState = mAutomaticBrightnessController
- .getAutomaticScreenBrightnessBasedOnLastUsedLux(
- mTempBrightnessEvent);
- } else {
- rawBrightnessState = getDozeBrightnessForOffload();
- mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags()
- | BrightnessEvent.FLAG_DOZE_SCALE);
- }
-
- if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) {
- brightnessState = clampScreenBrightness(rawBrightnessState);
- mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL);
-
+ if (Display.isDozeState(state)) {
+ // If there's an offload session, we need to set the initial doze brightness before
+ // the offload session starts controlling the brightness.
+ // During the transition DOZE_SUSPEND -> DOZE -> DOZE_SUSPEND, this brightness strategy
+ // will be selected again, meaning that no new brightness will be sent to the hardware
+ // and the display will stay at the brightness level set by the offload session.
+ if ((Float.isNaN(brightnessState)
+ || displayBrightnessState.getDisplayBrightnessStrategyName()
+ .equals(DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME))
+ && mFlags.isDisplayOffloadEnabled()
+ && mDisplayOffloadSession != null) {
if (mAutomaticBrightnessController != null
&& mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
- // Keep the brightness in the setting so that we can use it after the screen
- // turns on, until a lux sample becomes available. We don't do this when
- // auto-brightness is disabled - in that situation we still want to use
- // the last brightness from when the screen was on.
- updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState;
+ // Use the auto-brightness curve and the last observed lux
+ rawBrightnessState = mAutomaticBrightnessController
+ .getAutomaticScreenBrightnessBasedOnLastUsedLux(
+ mTempBrightnessEvent);
+ } else {
+ rawBrightnessState = getDozeBrightnessForOffload();
+ mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags()
+ | BrightnessEvent.FLAG_DOZE_SCALE);
+ }
+
+ if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) {
+ brightnessState = clampScreenBrightness(rawBrightnessState);
+ mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL);
+
+ if (mAutomaticBrightnessController != null
+ && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
+ // Keep the brightness in the setting so that we can use it after the screen
+ // turns on, until a lux sample becomes available. We don't do this when
+ // auto-brightness is disabled - in that situation we still want to use
+ // the last brightness from when the screen was on.
+ updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState;
+ }
}
}
- }
- // Use default brightness when dozing unless overridden.
- if (Float.isNaN(brightnessState) && Display.isDozeState(state)) {
- rawBrightnessState = mScreenBrightnessDozeConfig;
- brightnessState = clampScreenBrightness(rawBrightnessState);
- mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
+ // Use default brightness when dozing unless overridden.
+ if (Float.isNaN(brightnessState)
+ || displayBrightnessState.getDisplayBrightnessStrategyName()
+ .equals(DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME)) {
+ rawBrightnessState = mScreenBrightnessDozeConfig;
+ brightnessState = clampScreenBrightness(rawBrightnessState);
+ mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
+ }
}
if (!mFlags.isRefactorDisplayPowerControllerEnabled()) {
@@ -1502,7 +1511,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
// Apply manual brightness.
- if (Float.isNaN(brightnessState)) {
+ if (Float.isNaN(brightnessState) && !mFlags.isRefactorDisplayPowerControllerEnabled()) {
rawBrightnessState = currentBrightnessSetting;
brightnessState = clampScreenBrightness(rawBrightnessState);
if (brightnessState != currentBrightnessSetting) {
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index 22a21a6c113c..feec4e6b2259 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -32,6 +32,7 @@ import com.android.server.display.brightness.strategy.AutomaticBrightnessStrateg
import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
+import com.android.server.display.brightness.strategy.FallbackBrightnessStrategy;
import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy;
import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy;
@@ -85,6 +86,9 @@ public class DisplayBrightnessStrategySelector {
@Nullable
private final AutoBrightnessFallbackStrategy mAutoBrightnessFallbackStrategy;
+ @Nullable
+ private final FallbackBrightnessStrategy mFallbackBrightnessStrategy;
+
// A collective representation of all the strategies that the selector is aware of. This is
// non null, but the strategies this is tracking can be null
@NonNull
@@ -118,7 +122,8 @@ public class DisplayBrightnessStrategySelector {
mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy();
mAutomaticBrightnessStrategy1 =
(!mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null
- : injector.getAutomaticBrightnessStrategy1(context, displayId);
+ : injector.getAutomaticBrightnessStrategy1(context, displayId,
+ mDisplayManagerFlags);
mAutomaticBrightnessStrategy2 =
(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null
: injector.getAutomaticBrightnessStrategy2(context, displayId);
@@ -134,11 +139,14 @@ public class DisplayBrightnessStrategySelector {
} else {
mOffloadBrightnessStrategy = null;
}
+ mFallbackBrightnessStrategy = (mDisplayManagerFlags
+ .isRefactorDisplayPowerControllerEnabled())
+ ? injector.getFallbackBrightnessStrategy() : null;
mDisplayBrightnessStrategies = new DisplayBrightnessStrategy[]{mInvalidBrightnessStrategy,
mScreenOffBrightnessStrategy, mDozeBrightnessStrategy, mFollowerBrightnessStrategy,
mBoostBrightnessStrategy, mOverrideBrightnessStrategy, mTemporaryBrightnessStrategy,
mAutomaticBrightnessStrategy1, mOffloadBrightnessStrategy,
- mAutoBrightnessFallbackStrategy};
+ mAutoBrightnessFallbackStrategy, mFallbackBrightnessStrategy};
mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean(
R.bool.config_allowAutoBrightnessWhileDozing);
mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName();
@@ -179,6 +187,12 @@ public class DisplayBrightnessStrategySelector {
displayBrightnessStrategy = mOffloadBrightnessStrategy;
} else if (isAutoBrightnessFallbackStrategyValid()) {
displayBrightnessStrategy = mAutoBrightnessFallbackStrategy;
+ } else {
+ // This will become the ultimate fallback strategy once the flag has been fully rolled
+ // out
+ if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) {
+ displayBrightnessStrategy = mFallbackBrightnessStrategy;
+ }
}
if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) {
@@ -330,8 +344,8 @@ public class DisplayBrightnessStrategySelector {
}
AutomaticBrightnessStrategy getAutomaticBrightnessStrategy1(Context context,
- int displayId) {
- return new AutomaticBrightnessStrategy(context, displayId);
+ int displayId, DisplayManagerFlags displayManagerFlags) {
+ return new AutomaticBrightnessStrategy(context, displayId, displayManagerFlags);
}
AutomaticBrightnessStrategy2 getAutomaticBrightnessStrategy2(Context context,
@@ -347,5 +361,9 @@ public class DisplayBrightnessStrategySelector {
AutoBrightnessFallbackStrategy getAutoBrightnessFallbackStrategy() {
return new AutoBrightnessFallbackStrategy(/* injector= */ null);
}
+
+ FallbackBrightnessStrategy getFallbackBrightnessStrategy() {
+ return new FallbackBrightnessStrategy();
+ }
}
}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index 23052286d9ec..f809a49fd3d3 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -17,6 +17,9 @@ package com.android.server.display.brightness.strategy;
import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
+
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.display.BrightnessConfiguration;
@@ -33,6 +36,7 @@ import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.brightness.BrightnessUtils;
import com.android.server.display.brightness.StrategyExecutionRequest;
import com.android.server.display.brightness.StrategySelectionNotifyRequest;
+import com.android.server.display.feature.DisplayManagerFlags;
import java.io.PrintWriter;
@@ -98,19 +102,24 @@ public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2
private Injector mInjector;
+ private DisplayManagerFlags mDisplayManagerFlags;
+
@VisibleForTesting
- AutomaticBrightnessStrategy(Context context, int displayId, Injector injector) {
+ AutomaticBrightnessStrategy(Context context, int displayId, Injector injector,
+ DisplayManagerFlags displayManagerFlags) {
super(context, displayId);
mContext = context;
mDisplayId = displayId;
mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ mDisplayManagerFlags = displayManagerFlags;
mInjector = (injector == null) ? new RealInjector() : injector;
}
- public AutomaticBrightnessStrategy(Context context, int displayId) {
- this(context, displayId, null);
+ public AutomaticBrightnessStrategy(Context context, int displayId,
+ DisplayManagerFlags displayManagerFlags) {
+ this(context, displayId, null, displayManagerFlags);
}
/**
@@ -120,6 +129,7 @@ public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2
public void setAutoBrightnessState(int targetDisplayState,
boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy,
float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) {
+ switchMode(targetDisplayState);
final boolean autoBrightnessEnabledInDoze =
allowAutoBrightnessWhileDozingConfig && policy == POLICY_DOZE;
mIsAutoBrightnessEnabled = shouldUseAutoBrightness()
@@ -479,6 +489,16 @@ public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2
}
}
+
+ private void switchMode(int state) {
+ if (mDisplayManagerFlags.areAutoBrightnessModesEnabled()
+ && mAutomaticBrightnessController != null
+ && !mAutomaticBrightnessController.isInIdleMode()) {
+ mAutomaticBrightnessController.switchMode(Display.isDozeState(state)
+ ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
+ }
+ }
+
/**
* Evaluates if there are any temporary auto-brightness adjustments which is not applied yet.
* Temporary brightness adjustments happen when the user moves the brightness slider in the
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java
index 504683a55735..7b2f2b9d307b 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java
@@ -18,4 +18,5 @@ package com.android.server.display.brightness.strategy;
public class DisplayBrightnessStrategyConstants {
static final String INVALID_BRIGHTNESS_STRATEGY_NAME = "InvalidBrightnessStrategy";
+ public static final String FALLBACK_BRIGHTNESS_STRATEGY_NAME = "FallbackBrightnessStrategy";
}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
new file mode 100644
index 000000000000..3463649aa000
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+import android.annotation.NonNull;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.StrategyExecutionRequest;
+import com.android.server.display.brightness.StrategySelectionNotifyRequest;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the brightness of the associated display when no other strategy qualifies for
+ * setting up the brightness state. This strategy is also being used for evaluating the
+ * display brightness state when we have a manually set brightness. This is a temporary state, and
+ * the logic for evaluating the manual brightness will be moved to a separate strategy
+ */
+public class FallbackBrightnessStrategy implements DisplayBrightnessStrategy{
+ @Override
+ public DisplayBrightnessState updateBrightness(
+ StrategyExecutionRequest strategyExecutionRequest) {
+ BrightnessReason brightnessReason = new BrightnessReason();
+ brightnessReason.setReason(BrightnessReason.REASON_MANUAL);
+ return new DisplayBrightnessState.Builder()
+ .setBrightness(strategyExecutionRequest.getCurrentScreenBrightness())
+ .setSdrBrightness(strategyExecutionRequest.getCurrentScreenBrightness())
+ .setBrightnessReason(brightnessReason)
+ .setDisplayBrightnessStrategyName(getName())
+ // The fallback brightness might change due to clamping. Make sure we tell the rest
+ // of the system by updating the setting
+ .setShouldUpdateScreenBrightnessSetting(true)
+ .build();
+ }
+
+ @NonNull
+ @Override
+ public String getName() {
+ return DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME;
+ }
+
+ @Override
+ public int getReason() {
+ return BrightnessReason.REASON_MANUAL;
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+
+ }
+
+ @Override
+ public void strategySelectionPostProcessor(
+ StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
+
+ }
+}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 816242df639d..c6aef7fb3540 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -249,14 +249,14 @@ final class DreamController {
mCurrentDream.mAppTask = appTask;
}
- void setDreamHasFocus(boolean hasFocus) {
+ void setDreamIsObscured(boolean isObscured) {
if (mCurrentDream != null) {
- mCurrentDream.mDreamHasFocus = hasFocus;
+ mCurrentDream.mDreamIsObscured = isObscured;
}
}
- boolean dreamHasFocus() {
- return mCurrentDream != null && mCurrentDream.mDreamHasFocus;
+ boolean dreamIsFrontmost() {
+ return mCurrentDream != null && mCurrentDream.dreamIsFrontmost();
}
/**
@@ -451,7 +451,7 @@ final class DreamController {
private String mStopReason;
private long mDreamStartTime;
public boolean mWakingGently;
- public boolean mDreamHasFocus;
+ private boolean mDreamIsObscured;
private final Runnable mStopPreviousDreamsIfNeeded = this::stopPreviousDreamsIfNeeded;
private final Runnable mReleaseWakeLockIfNeeded = this::releaseWakeLockIfNeeded;
@@ -549,5 +549,9 @@ final class DreamController {
mHandler.removeCallbacks(mReleaseWakeLockIfNeeded);
}
}
+
+ boolean dreamIsFrontmost() {
+ return !mDreamIsObscured;
+ }
}
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 2def5aed2478..18a9986d34ba 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -20,7 +20,7 @@ import static android.Manifest.permission.BIND_DREAM_SERVICE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.service.dreams.Flags.dreamTracksFocus;
+import static android.service.dreams.Flags.dreamHandlesBeingObscured;
import static com.android.server.wm.ActivityInterceptorCallback.DREAM_MANAGER_ORDERED_ID;
@@ -428,7 +428,7 @@ public final class DreamManagerService extends SystemService {
// Can't start dreaming if we are already dreaming and the dream has focus. If we are
// dreaming but the dream does not have focus, then the dream can be brought to the
// front so it does have focus.
- if (isScreenOn && isDreamingInternal() && dreamHasFocus()) {
+ if (isScreenOn && isDreamingInternal() && dreamIsFrontmost()) {
return false;
}
@@ -463,9 +463,10 @@ public final class DreamManagerService extends SystemService {
}
}
- private boolean dreamHasFocus() {
- // Dreams always had focus before they were able to track it.
- return !dreamTracksFocus() || mController.dreamHasFocus();
+ private boolean dreamIsFrontmost() {
+ // Dreams were always considered frontmost before they began tracking whether they are
+ // obscured.
+ return !dreamHandlesBeingObscured() || mController.dreamIsFrontmost();
}
protected void requestStartDreamFromShell() {
@@ -473,7 +474,7 @@ public final class DreamManagerService extends SystemService {
}
private void requestDreamInternal() {
- if (isDreamingInternal() && !dreamHasFocus() && mController.bringDreamToFront()) {
+ if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()) {
return;
}
@@ -1159,10 +1160,16 @@ public final class DreamManagerService extends SystemService {
}
@Override
- public void onDreamFocusChanged(boolean hasFocus) {
+ public void setDreamIsObscured(boolean isObscured) {
+ if (!dreamHandlesBeingObscured()) {
+ return;
+ }
+
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
final long ident = Binder.clearCallingIdentity();
try {
- mController.setDreamHasFocus(hasFocus);
+ mHandler.post(() -> mController.setDreamIsObscured(isObscured));
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java
index b47631c35e38..d32a5ed60094 100644
--- a/services/core/java/com/android/server/input/InputManagerInternal.java
+++ b/services/core/java/com/android/server/input/InputManagerInternal.java
@@ -218,4 +218,13 @@ public abstract class InputManagerInternal {
* display, external peripherals, fingerprint sensor, etc.
*/
public abstract void notifyUserActivity();
+
+ /**
+ * Get the device ID of the {@link InputDevice} that used most recently.
+ *
+ * @return the last used input device ID, or
+ * {@link android.os.IInputConstants#INVALID_INPUT_DEVICE_ID} if no device has been used
+ * since boot.
+ */
+ public abstract int getLastUsedInputDeviceId();
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 83179914c746..8685d2c45762 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3204,6 +3204,11 @@ public class InputManagerService extends IInputManager.Stub
public void setStylusButtonMotionEventsEnabled(boolean enabled) {
mNative.setStylusButtonMotionEventsEnabled(enabled);
}
+
+ @Override
+ public int getLastUsedInputDeviceId() {
+ return mNative.getLastUsedInputDeviceId();
+ }
}
@Override
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index f742360484f5..0208a325a1d5 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -271,6 +271,15 @@ interface NativeInputManagerService {
void setInputMethodConnectionIsActive(boolean isActive);
+ /**
+ * Get the device ID of the InputDevice that used most recently.
+ *
+ * @return the last used input device ID, or
+ * {@link android.os.IInputConstants#INVALID_INPUT_DEVICE_ID} if no device has been used
+ * since boot.
+ */
+ int getLastUsedInputDeviceId();
+
/** The native implementation of InputManagerService methods. */
class NativeImpl implements NativeInputManagerService {
/** Pointer to native input manager service object, used by native code. */
@@ -544,5 +553,8 @@ interface NativeInputManagerService {
@Override
public native void setInputMethodConnectionIsActive(boolean isActive);
+
+ @Override
+ public native int getLastUsedInputDeviceId();
}
}
diff --git a/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java b/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java
index 00bc7517bebd..ad98b4a8db13 100644
--- a/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java
+++ b/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java
@@ -29,6 +29,7 @@ import android.view.inputmethod.InputMethodInfo;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback;
import com.android.internal.inputmethod.IInlineSuggestionsResponseCallback;
+import com.android.internal.inputmethod.InlineSuggestionsRequestCallback;
import com.android.internal.inputmethod.InlineSuggestionsRequestInfo;
/**
@@ -49,12 +50,12 @@ final class AutofillSuggestionsController {
private static final class CreateInlineSuggestionsRequest {
@NonNull final InlineSuggestionsRequestInfo mRequestInfo;
- @NonNull final IInlineSuggestionsRequestCallback mCallback;
+ @NonNull final InlineSuggestionsRequestCallback mCallback;
@NonNull final String mPackageName;
CreateInlineSuggestionsRequest(
@NonNull InlineSuggestionsRequestInfo requestInfo,
- @NonNull IInlineSuggestionsRequestCallback callback,
+ @NonNull InlineSuggestionsRequestCallback callback,
@NonNull String packageName) {
mRequestInfo = requestInfo;
mCallback = callback;
@@ -78,7 +79,7 @@ final class AutofillSuggestionsController {
*/
@GuardedBy("ImfLock.class")
@Nullable
- private IInlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback;
+ private InlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback;
AutofillSuggestionsController(@NonNull InputMethodManagerService service) {
mService = service;
@@ -97,33 +98,30 @@ final class AutofillSuggestionsController {
@GuardedBy("ImfLock.class")
void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
- InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback,
+ InlineSuggestionsRequestInfo requestInfo, InlineSuggestionsRequestCallback callback,
boolean touchExplorationEnabled) {
clearPendingInlineSuggestionsRequest();
mInlineSuggestionsRequestCallback = callback;
final InputMethodInfo imi = mService.queryInputMethodForCurrentUserLocked(
mService.getSelectedMethodIdLocked());
- try {
- if (userId == mService.getCurrentImeUserIdLocked()
- && imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) {
- mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest(
- requestInfo, callback, imi.getPackageName());
- if (mService.getCurMethodLocked() != null) {
- // In the normal case when the IME is connected, we can make the request here.
- performOnCreateInlineSuggestionsRequest();
- } else {
- // Otherwise, the next time the IME connection is established,
- // InputMethodBindingController.mMainConnection#onServiceConnected() will call
- // into #performOnCreateInlineSuggestionsRequestLocked() to make the request.
- if (DEBUG) {
- Slog.d(TAG, "IME not connected. Delaying inline suggestions request.");
- }
- }
+
+ if (userId == mService.getCurrentImeUserIdLocked()
+ && imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) {
+ mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest(
+ requestInfo, callback, imi.getPackageName());
+ if (mService.getCurMethodLocked() != null) {
+ // In the normal case when the IME is connected, we can make the request here.
+ performOnCreateInlineSuggestionsRequest();
} else {
- callback.onInlineSuggestionsUnsupported();
+ // Otherwise, the next time the IME connection is established,
+ // InputMethodBindingController.mMainConnection#onServiceConnected() will call
+ // into #performOnCreateInlineSuggestionsRequestLocked() to make the request.
+ if (DEBUG) {
+ Slog.d(TAG, "IME not connected. Delaying inline suggestions request.");
+ }
}
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
+ } else {
+ callback.onInlineSuggestionsUnsupported();
}
}
@@ -166,11 +164,7 @@ final class AutofillSuggestionsController {
@GuardedBy("ImfLock.class")
void invalidateAutofillSession() {
if (mInlineSuggestionsRequestCallback != null) {
- try {
- mInlineSuggestionsRequestCallback.onInlineSuggestionsSessionInvalidated();
- } catch (RemoteException e) {
- Slog.e(TAG, "Cannot invalidate autofill session.", e);
- }
+ mInlineSuggestionsRequestCallback.onInlineSuggestionsSessionInvalidated();
}
}
@@ -180,13 +174,13 @@ final class AutofillSuggestionsController {
*/
private final class InlineSuggestionsRequestCallbackDecorator
extends IInlineSuggestionsRequestCallback.Stub {
- @NonNull private final IInlineSuggestionsRequestCallback mCallback;
+ @NonNull private final InlineSuggestionsRequestCallback mCallback;
@NonNull private final String mImePackageName;
private final int mImeDisplayId;
@NonNull private final IBinder mImeToken;
InlineSuggestionsRequestCallbackDecorator(
- @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String imePackageName,
+ @NonNull InlineSuggestionsRequestCallback callback, @NonNull String imePackageName,
int displayId, @NonNull IBinder imeToken) {
mCallback = callback;
mImePackageName = imePackageName;
@@ -195,7 +189,7 @@ final class AutofillSuggestionsController {
}
@Override
- public void onInlineSuggestionsUnsupported() throws RemoteException {
+ public void onInlineSuggestionsUnsupported() {
mCallback.onInlineSuggestionsUnsupported();
}
@@ -220,32 +214,32 @@ final class AutofillSuggestionsController {
}
@Override
- public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException {
+ public void onInputMethodStartInput(AutofillId imeFieldId) {
mCallback.onInputMethodStartInput(imeFieldId);
}
@Override
- public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException {
+ public void onInputMethodShowInputRequested(boolean requestResult) {
mCallback.onInputMethodShowInputRequested(requestResult);
}
@Override
- public void onInputMethodStartInputView() throws RemoteException {
+ public void onInputMethodStartInputView() {
mCallback.onInputMethodStartInputView();
}
@Override
- public void onInputMethodFinishInputView() throws RemoteException {
+ public void onInputMethodFinishInputView() {
mCallback.onInputMethodFinishInputView();
}
@Override
- public void onInputMethodFinishInput() throws RemoteException {
+ public void onInputMethodFinishInput() {
mCallback.onInputMethodFinishInput();
}
@Override
- public void onInlineSuggestionsSessionInvalidated() throws RemoteException {
+ public void onInlineSuggestionsSessionInvalidated() {
mCallback.onInlineSuggestionsSessionInvalidated();
}
}
diff --git a/services/core/java/com/android/server/inputmethod/ImeBindingState.java b/services/core/java/com/android/server/inputmethod/ImeBindingState.java
index 4c20c3b9784a..f78ea84efb77 100644
--- a/services/core/java/com/android/server/inputmethod/ImeBindingState.java
+++ b/services/core/java/com/android/server/inputmethod/ImeBindingState.java
@@ -21,7 +21,9 @@ import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_FOCU
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.os.IBinder;
+import android.os.UserHandle;
import android.util.Printer;
import android.util.proto.ProtoOutputStream;
import android.view.WindowManager;
@@ -36,6 +38,9 @@ import com.android.server.wm.WindowManagerInternal;
*/
final class ImeBindingState {
+ @UserIdInt
+ final int mUserId;
+
/**
* The last window token that we confirmed to be focused. This is always updated upon
* reports from the input method client. If the window state is already changed before the
@@ -90,6 +95,7 @@ final class ImeBindingState {
static ImeBindingState newEmptyState() {
return new ImeBindingState(
+ /*userId=*/ UserHandle.USER_NULL,
/*focusedWindow=*/ null,
/*focusedWindowSoftInputMode=*/ SOFT_INPUT_STATE_UNSPECIFIED,
/*focusedWindowClient=*/ null,
@@ -97,10 +103,12 @@ final class ImeBindingState {
);
}
- ImeBindingState(@Nullable IBinder focusedWindow,
+ ImeBindingState(@UserIdInt int userId,
+ @Nullable IBinder focusedWindow,
@SoftInputModeFlags int focusedWindowSoftInputMode,
@Nullable ClientState focusedWindowClient,
@Nullable EditorInfo focusedWindowEditorInfo) {
+ mUserId = userId;
mFocusedWindow = focusedWindow;
mFocusedWindowSoftInputMode = focusedWindowSoftInputMode;
mFocusedWindowClient = focusedWindowClient;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index e8543f225ef0..dace67f2c462 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -25,7 +25,7 @@ import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InputMethodInfo;
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
-import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback;
+import com.android.internal.inputmethod.InlineSuggestionsRequestCallback;
import com.android.internal.inputmethod.InlineSuggestionsRequestInfo;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.server.LocalServices;
@@ -86,11 +86,11 @@ public abstract class InputMethodManagerInternal {
*
* @param userId the user ID to be queried
* @param requestInfo information needed to create an {@link InlineSuggestionsRequest}.
- * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request
+ * @param cb {@link InlineSuggestionsRequestCallback} used to pass back the request
* object
*/
public abstract void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
- InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb);
+ InlineSuggestionsRequestInfo requestInfo, InlineSuggestionsRequestCallback cb);
/**
* Force switch to the enabled input method by {@code imeId} for current user. If the input
@@ -263,7 +263,7 @@ public abstract class InputMethodManagerInternal {
@Override
public void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
InlineSuggestionsRequestInfo requestInfo,
- IInlineSuggestionsRequestCallback cb) {
+ InlineSuggestionsRequestCallback cb) {
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 67df99279242..954f9bcd9c43 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -147,7 +147,6 @@ import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
import com.android.internal.inputmethod.IBooleanListener;
import com.android.internal.inputmethod.IConnectionlessHandwritingCallback;
import com.android.internal.inputmethod.IImeTracker;
-import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethod;
import com.android.internal.inputmethod.IInputMethodClient;
@@ -157,6 +156,7 @@ import com.android.internal.inputmethod.IInputMethodSessionCallback;
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.inputmethod.IRemoteInputConnection;
import com.android.internal.inputmethod.ImeTracing;
+import com.android.internal.inputmethod.InlineSuggestionsRequestCallback;
import com.android.internal.inputmethod.InlineSuggestionsRequestInfo;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.InputMethodDebug;
@@ -533,21 +533,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
EditorInfo mCurEditorInfo;
/**
- * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
- * connected to or in the process of connecting to.
- *
- * <p>This can be {@code null} when no input method is connected.</p>
- *
- * @see #getSelectedMethodIdLocked()
- */
- @GuardedBy("ImfLock.class")
- @Nullable
- private String getCurIdLocked() {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- return userData.mBindingController.getCurId();
- }
-
- /**
* The current subtype of the current input method.
*/
@MultiUserUnawareField
@@ -577,16 +562,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
boolean mInFullscreenMode;
/**
- * The Intent used to connect to the current input method.
- */
- @GuardedBy("ImfLock.class")
- @Nullable
- private Intent getCurIntentLocked() {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- return userData.mBindingController.getCurIntent();
- }
-
- /**
* The token we have made for the currently active input method, to
* identify it in the future.
*/
@@ -632,15 +607,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
/**
- * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntentLocked()}.
- */
- @GuardedBy("ImfLock.class")
- private int getCurMethodUidLocked() {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- return userData.mBindingController.getCurMethodUid();
- }
-
- /**
* Have we called mCurMethod.bindInput()?
*/
@MultiUserUnawareField
@@ -1058,8 +1024,16 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
private void onFinishPackageChangesInternal() {
+ final int userId = getChangingUserId();
+
+ // Instantiating InputMethodInfo requires disk I/O.
+ // Do them before acquiring the lock to minimize the chances of ANR (b/340221861).
+ final var newMethodMapWithoutAdditionalSubtypes =
+ queryInputMethodServicesInternal(mContext, userId,
+ AdditionalSubtypeMap.EMPTY_MAP, DirectBootAwareness.AUTO)
+ .getMethodMap();
+
synchronized (ImfLock.class) {
- final int userId = getChangingUserId();
final boolean isCurrentUser = (userId == mCurrentUserId);
final AdditionalSubtypeMap additionalSubtypeMap =
AdditionalSubtypeMapRepository.get(userId);
@@ -1111,9 +1085,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
&& !(additionalSubtypeChanged || shouldRebuildInputMethodListLocked())) {
return;
}
-
- final InputMethodSettings newSettings = queryInputMethodServicesInternal(mContext,
- userId, newAdditionalSubtypeMap, DirectBootAwareness.AUTO);
+ final var newMethodMap = newMethodMapWithoutAdditionalSubtypes
+ .applyAdditionalSubtypes(newAdditionalSubtypeMap);
+ final InputMethodSettings newSettings =
+ InputMethodSettings.create(newMethodMap, userId);
InputMethodSettingsRepository.put(userId, newSettings);
if (!isCurrentUser) {
return;
@@ -2011,8 +1986,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
final StartInputInfo info = new StartInputInfo(mCurrentUserId,
getCurTokenLocked(),
- mCurTokenDisplayId, getCurIdLocked(), startInputReason, restarting,
- UserHandle.getUserId(mCurClient.mUid),
+ mCurTokenDisplayId, userData.mBindingController.getCurId(), startInputReason,
+ restarting, UserHandle.getUserId(mCurClient.mUid),
mCurClient.mSelfReportedDisplayId, mImeBindingState.mFocusedWindow, mCurEditorInfo,
mImeBindingState.mFocusedWindowSoftInputMode,
userData.mBindingController.getSequenceNumber());
@@ -2026,8 +2001,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
if (mCurrentUserId == UserHandle.getUserId(
mCurClient.mUid)) {
- mPackageManagerInternal.grantImplicitAccess(mCurrentUserId,
- null /* intent */, UserHandle.getAppId(getCurMethodUidLocked()),
+ mPackageManagerInternal.grantImplicitAccess(mCurrentUserId, null /* intent */,
+ UserHandle.getAppId(userData.mBindingController.getCurMethodUid()),
mCurClient.mUid, true /* direct */);
}
@@ -2048,7 +2023,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
null /* resultReceiver */, SoftInputShowHideReason.ATTACH_NEW_INPUT);
}
- final var curId = getCurIdLocked();
+ final var curId = userData.mBindingController.getCurId();
final InputMethodInfo curInputMethodInfo = InputMethodSettingsRepository.get(mCurrentUserId)
.getMethodMap().get(curId);
final boolean suppressesSpellChecker =
@@ -2337,7 +2312,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
requestClientSessionForAccessibilityLocked(cs);
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
- null, null, null, getCurIdLocked(),
+ null, null, null,
+ userData.mBindingController.getCurId(),
userData.mBindingController.getSequenceNumber(), false);
} else {
final long lastBindTime = userData.mBindingController.getLastBindTime();
@@ -2352,7 +2328,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// to see if we can get back in touch with the service.
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, null, getCurIdLocked(),
+ null, null, null,
+ userData.mBindingController.getCurId(),
userData.mBindingController.getSequenceNumber(), false);
} else {
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
@@ -2707,7 +2684,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// When the IME switcher dialog is shown, the IME switcher button should be hidden.
if (mMenuController.getSwitchingDialogLocked() != null) return false;
// When we are switching IMEs, the IME switcher button should be hidden.
- if (!Objects.equals(getCurIdLocked(), getSelectedMethodIdLocked())) {
+ final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ if (!Objects.equals(userData.mBindingController.getCurId(), getSelectedMethodIdLocked())) {
return false;
}
if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
@@ -2869,8 +2847,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
} else {
vis &= ~InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
}
+ final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var curId = userData.mBindingController.getCurId();
if (mMenuController.getSwitchingDialogLocked() != null
- || !Objects.equals(getCurIdLocked(), getSelectedMethodIdLocked())) {
+ || !Objects.equals(curId, getSelectedMethodIdLocked())) {
// When the IME switcher dialog is shown, or we are switching IMEs,
// the back button should be in the default state (as if the IME is not shown).
backDisposition = InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING;
@@ -3741,7 +3721,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
null, null, null, null, -1, false);
}
- mImeBindingState = new ImeBindingState(windowToken, softInputMode, cs, editorInfo);
+ mImeBindingState = new ImeBindingState(userData.mUserId, windowToken, softInputMode, cs,
+ editorInfo);
mFocusedWindowPerceptible.put(windowToken, true);
// We want to start input before showing the IME, but after closing
@@ -3831,10 +3812,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
if (mCurrentUserId != UserHandle.getUserId(uid)) {
return false;
}
- if (getCurIntentLocked() != null && InputMethodUtils.checkIfPackageBelongsToUid(
- mPackageManagerInternal,
- uid,
- getCurIntentLocked().getComponent().getPackageName())) {
+ final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ final var curIntent = userData.mBindingController.getCurIntent();
+ if (curIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
+ mPackageManagerInternal, uid, curIntent.getComponent().getPackageName())) {
return true;
}
return false;
@@ -4438,7 +4419,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
if (mCurEditorInfo != null) {
mCurEditorInfo.dumpDebug(proto, CUR_ATTRIBUTE);
}
- proto.write(CUR_ID, getCurIdLocked());
+ proto.write(CUR_ID, userData.mBindingController.getCurId());
mVisibilityStateComputer.dumpDebug(proto, fieldId);
proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked()));
@@ -4895,7 +4876,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
if (mCurClient == null || mCurClient.mClient == null) {
return;
}
- if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(getCurMethodUidLocked())) {
+ // TODO(b/325515685): user data must be retrieved by a userId parameter
+ final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+ if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(
+ userData.mBindingController.getCurMethodUid())) {
// Handle IME visibility when interactive changed before finishing the input to
// ensure we preserve the last state as possible.
final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.onInteractiveChanged(
@@ -5502,7 +5486,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Override
public void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
- InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) {
+ InlineSuggestionsRequestInfo requestInfo, InlineSuggestionsRequestCallback cb) {
// Get the device global touch exploration state before lock to avoid deadlock.
final boolean touchExplorationEnabled = AccessibilityManagerInternal.get()
.isTouchExplorationEnabled(userId);
@@ -5648,7 +5632,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final InputBindResult res = new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION,
imeSession, accessibilityInputMethodSessions, /* channel= */ null,
- getCurIdLocked(),
+ userData.mBindingController.getCurId(),
userData.mBindingController.getSequenceNumber(),
/* isInputMethodSuppressingSpellChecker= */ false);
mCurClient.mClient.onBindAccessibilityService(res, accessibilityConnectionId);
@@ -5901,7 +5885,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
p.println(" mFocusedWindowPerceptible=" + mFocusedWindowPerceptible);
mImeBindingState.dump(/* prefix= */ " ", p);
- p.println(" mCurId=" + getCurIdLocked()
+ p.println(" mCurId=" + userData.mBindingController.getCurId()
+ " mHaveConnection=" + userData.mBindingController.hasMainConnection()
+ " mBoundToMethod=" + mBoundToMethod + " mVisibleBound="
+ userData.mBindingController.isVisibleBound());
@@ -5920,7 +5904,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
p.println(" mCurToken=" + getCurTokenLocked());
p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
p.println(" mCurHostInputToken=" + mAutofillController.getCurHostInputToken());
- p.println(" mCurIntent=" + getCurIntentLocked());
+ p.println(" mCurIntent=" + userData.mBindingController.getCurIntent());
method = getCurMethodLocked();
p.println(" mCurMethod=" + getCurMethodLocked());
p.println(" mEnabledSession=" + mEnabledSession);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMap.java b/services/core/java/com/android/server/inputmethod/InputMethodMap.java
index a8e5e2ef4f72..221309e4bf3e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMap.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMap.java
@@ -75,4 +75,28 @@ final class InputMethodMap {
int size() {
return mMap.size();
}
+
+ @AnyThread
+ @NonNull
+ public InputMethodMap applyAdditionalSubtypes(
+ @NonNull AdditionalSubtypeMap additionalSubtypeMap) {
+ if (additionalSubtypeMap.isEmpty()) {
+ return this;
+ }
+ final int size = size();
+ final ArrayMap<String, InputMethodInfo> newMethodMap = new ArrayMap<>(size);
+ boolean updated = false;
+ for (int i = 0; i < size; ++i) {
+ final var imi = valueAt(i);
+ final var imeId = imi.getId();
+ final var newAdditionalSubtypes = additionalSubtypeMap.get(imeId);
+ if (newAdditionalSubtypes == null || newAdditionalSubtypes.isEmpty()) {
+ newMethodMap.put(imi.getId(), imi);
+ } else {
+ newMethodMap.put(imi.getId(), new InputMethodInfo(imi, newAdditionalSubtypes));
+ updated = true;
+ }
+ }
+ return updated ? InputMethodMap.of(newMethodMap) : this;
+ }
}
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 a0dbfa082978..ec94e2be2c59 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -412,10 +412,15 @@ import java.util.concurrent.atomic.AtomicInteger;
/* package */
synchronized void addTransaction(
ContextHubServiceTransaction transaction) throws IllegalStateException {
+ if (transaction == null) {
+ return;
+ }
+
if (mTransactionQueue.size() == MAX_PENDING_REQUESTS) {
throw new IllegalStateException("Transaction queue is full (capacity = "
+ MAX_PENDING_REQUESTS + ")");
}
+
mTransactionQueue.add(transaction);
mTransactionRecordDeque.add(new TransactionRecord(transaction.toString()));
@@ -517,7 +522,10 @@ import java.util.concurrent.atomic.AtomicInteger;
* the caller has obtained a lock on this ContextHubTransactionManager object.
*/
private void removeTransactionAndStartNext() {
- mTimeoutFuture.cancel(false /* mayInterruptIfRunning */);
+ if (mTimeoutFuture != null) {
+ mTimeoutFuture.cancel(/* mayInterruptIfRunning= */ false);
+ mTimeoutFuture = null;
+ }
ContextHubServiceTransaction transaction = mTransactionQueue.remove();
transaction.setComplete();
diff --git a/services/core/java/com/android/server/net/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java
index d25f52973085..5ea3e70f7957 100644
--- a/services/core/java/com/android/server/net/NetworkManagementService.java
+++ b/services/core/java/com/android/server/net/NetworkManagementService.java
@@ -20,6 +20,9 @@ import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
@@ -31,6 +34,9 @@ import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_BACKGROUND;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_ALLOW;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_USER;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
@@ -143,6 +149,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
private final Object mQuotaLock = new Object();
private final Object mRulesLock = new Object();
+ private final boolean mUseMeteredFirewallChains;
+
/** Set of interfaces with active quotas. */
@GuardedBy("mQuotaLock")
private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
@@ -150,9 +158,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@GuardedBy("mQuotaLock")
private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
/** Set of UIDs denied on metered networks. */
+ // TODO: b/336693007 - Remove once NPMS has completely migrated to metered firewall chains.
@GuardedBy("mRulesLock")
private SparseBooleanArray mUidRejectOnMetered = new SparseBooleanArray();
/** Set of UIDs allowed on metered networks. */
+ // TODO: b/336693007 - Remove once NPMS has completely migrated to metered firewall chains.
@GuardedBy("mRulesLock")
private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray();
/** Set of UIDs with cleartext penalties. */
@@ -196,10 +206,32 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@GuardedBy("mRulesLock")
private final SparseIntArray mUidFirewallBackgroundRules = new SparseIntArray();
+ /**
+ * Contains the per-UID firewall rules that are used to allowlist the app from metered-network
+ * restrictions when data saver is enabled.
+ */
+ @GuardedBy("mRulesLock")
+ private final SparseIntArray mUidMeteredFirewallAllowRules = new SparseIntArray();
+
+ /**
+ * Contains the per-UID firewall rules that are used to deny app access to metered networks
+ * due to user action.
+ */
+ @GuardedBy("mRulesLock")
+ private final SparseIntArray mUidMeteredFirewallDenyUserRules = new SparseIntArray();
+
+ /**
+ * Contains the per-UID firewall rules that are used to deny app access to metered networks
+ * due to admin action.
+ */
+ @GuardedBy("mRulesLock")
+ private final SparseIntArray mUidMeteredFirewallDenyAdminRules = new SparseIntArray();
+
/** Set of states for the child firewall chains. True if the chain is active. */
@GuardedBy("mRulesLock")
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
+ // TODO: b/336693007 - Remove once NPMS has completely migrated to metered firewall chains.
@GuardedBy("mQuotaLock")
private volatile boolean mDataSaverMode;
@@ -217,6 +249,15 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
mContext = context;
mDeps = deps;
+ mUseMeteredFirewallChains = Flags.useMeteredFirewallChains();
+
+ if (mUseMeteredFirewallChains) {
+ // These firewalls are always on and currently ConnectivityService does not allow
+ // changing their enabled state.
+ mFirewallChainStates.put(FIREWALL_CHAIN_METERED_DENY_USER, true);
+ mFirewallChainStates.put(FIREWALL_CHAIN_METERED_DENY_ADMIN, true);
+ }
+
mDaemonHandler = new Handler(FgThread.get().getLooper());
mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
@@ -410,33 +451,39 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
}
}
- SparseBooleanArray uidRejectOnQuota = null;
- SparseBooleanArray uidAcceptOnQuota = null;
- synchronized (mRulesLock) {
- size = mUidRejectOnMetered.size();
- if (size > 0) {
- if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered denylist rules");
- uidRejectOnQuota = mUidRejectOnMetered;
- mUidRejectOnMetered = new SparseBooleanArray();
- }
+ if (!mUseMeteredFirewallChains) {
+ SparseBooleanArray uidRejectOnQuota = null;
+ SparseBooleanArray uidAcceptOnQuota = null;
+ synchronized (mRulesLock) {
+ size = mUidRejectOnMetered.size();
+ if (size > 0) {
+ if (DBG) {
+ Slog.d(TAG, "Pushing " + size + " UIDs to metered denylist rules");
+ }
+ uidRejectOnQuota = mUidRejectOnMetered;
+ mUidRejectOnMetered = new SparseBooleanArray();
+ }
- size = mUidAllowOnMetered.size();
- if (size > 0) {
- if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered allowlist rules");
- uidAcceptOnQuota = mUidAllowOnMetered;
- mUidAllowOnMetered = new SparseBooleanArray();
+ size = mUidAllowOnMetered.size();
+ if (size > 0) {
+ if (DBG) {
+ Slog.d(TAG, "Pushing " + size + " UIDs to metered allowlist rules");
+ }
+ uidAcceptOnQuota = mUidAllowOnMetered;
+ mUidAllowOnMetered = new SparseBooleanArray();
+ }
}
- }
- if (uidRejectOnQuota != null) {
- for (int i = 0; i < uidRejectOnQuota.size(); i++) {
- setUidOnMeteredNetworkDenylist(uidRejectOnQuota.keyAt(i),
- uidRejectOnQuota.valueAt(i));
+ if (uidRejectOnQuota != null) {
+ for (int i = 0; i < uidRejectOnQuota.size(); i++) {
+ setUidOnMeteredNetworkDenylist(uidRejectOnQuota.keyAt(i),
+ uidRejectOnQuota.valueAt(i));
+ }
}
- }
- if (uidAcceptOnQuota != null) {
- for (int i = 0; i < uidAcceptOnQuota.size(); i++) {
- setUidOnMeteredNetworkAllowlist(uidAcceptOnQuota.keyAt(i),
- uidAcceptOnQuota.valueAt(i));
+ if (uidAcceptOnQuota != null) {
+ for (int i = 0; i < uidAcceptOnQuota.size(); i++) {
+ setUidOnMeteredNetworkAllowlist(uidAcceptOnQuota.keyAt(i),
+ uidAcceptOnQuota.valueAt(i));
+ }
}
}
@@ -459,8 +506,16 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
syncFirewallChainLocked(FIREWALL_CHAIN_RESTRICTED, "restricted ");
syncFirewallChainLocked(FIREWALL_CHAIN_LOW_POWER_STANDBY, "low power standby ");
syncFirewallChainLocked(FIREWALL_CHAIN_BACKGROUND, FIREWALL_CHAIN_NAME_BACKGROUND);
+ if (mUseMeteredFirewallChains) {
+ syncFirewallChainLocked(FIREWALL_CHAIN_METERED_ALLOW,
+ FIREWALL_CHAIN_NAME_METERED_ALLOW);
+ syncFirewallChainLocked(FIREWALL_CHAIN_METERED_DENY_USER,
+ FIREWALL_CHAIN_NAME_METERED_DENY_USER);
+ syncFirewallChainLocked(FIREWALL_CHAIN_METERED_DENY_ADMIN,
+ FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN);
+ }
- final int[] chains = {
+ final int[] chainsToEnable = {
FIREWALL_CHAIN_STANDBY,
FIREWALL_CHAIN_DOZABLE,
FIREWALL_CHAIN_POWERSAVE,
@@ -469,14 +524,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
FIREWALL_CHAIN_BACKGROUND,
};
- for (int chain : chains) {
+ for (int chain : chainsToEnable) {
if (getFirewallChainState(chain)) {
setFirewallChainEnabled(chain, true);
}
}
}
-
try {
getBatteryStats().noteNetworkStatsEnabled();
} catch (RemoteException e) {
@@ -1077,6 +1131,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
mContext.getSystemService(ConnectivityManager.class)
.setDataSaverEnabled(enable);
mDataSaverMode = enable;
+ if (mUseMeteredFirewallChains) {
+ // Copy mDataSaverMode state to FIREWALL_CHAIN_METERED_ALLOW
+ // until ConnectivityService allows manipulation of the data saver mode via
+ // FIREWALL_CHAIN_METERED_ALLOW.
+ synchronized (mRulesLock) {
+ mFirewallChainStates.put(FIREWALL_CHAIN_METERED_ALLOW, enable);
+ }
+ }
return true;
} else {
final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
@@ -1191,9 +1253,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
setFirewallChainState(chain, enable);
}
- final String chainName = getFirewallChainName(chain);
- if (chain == FIREWALL_CHAIN_NONE) {
- throw new IllegalArgumentException("Bad child chain: " + chainName);
+ if (!isValidFirewallChainForSetEnabled(chain)) {
+ throw new IllegalArgumentException("Invalid chain for setFirewallChainEnabled: "
+ + NetworkPolicyLogger.getFirewallChainName(chain));
}
final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
@@ -1205,38 +1267,29 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
}
}
- private String getFirewallChainName(int chain) {
- switch (chain) {
- case FIREWALL_CHAIN_STANDBY:
- return FIREWALL_CHAIN_NAME_STANDBY;
- case FIREWALL_CHAIN_DOZABLE:
- return FIREWALL_CHAIN_NAME_DOZABLE;
- case FIREWALL_CHAIN_POWERSAVE:
- return FIREWALL_CHAIN_NAME_POWERSAVE;
- case FIREWALL_CHAIN_RESTRICTED:
- return FIREWALL_CHAIN_NAME_RESTRICTED;
- case FIREWALL_CHAIN_LOW_POWER_STANDBY:
- return FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY;
- case FIREWALL_CHAIN_BACKGROUND:
- return FIREWALL_CHAIN_NAME_BACKGROUND;
- default:
- throw new IllegalArgumentException("Bad child chain: " + chain);
- }
+ private boolean isValidFirewallChainForSetEnabled(int chain) {
+ return switch (chain) {
+ case FIREWALL_CHAIN_STANDBY, FIREWALL_CHAIN_DOZABLE, FIREWALL_CHAIN_POWERSAVE,
+ FIREWALL_CHAIN_RESTRICTED, FIREWALL_CHAIN_LOW_POWER_STANDBY,
+ FIREWALL_CHAIN_BACKGROUND -> true;
+ // METERED_* firewall chains are not yet supported by
+ // ConnectivityService#setFirewallChainEnabled.
+ default -> false;
+ };
}
private int getFirewallType(int chain) {
switch (chain) {
case FIREWALL_CHAIN_STANDBY:
+ case FIREWALL_CHAIN_METERED_DENY_ADMIN:
+ case FIREWALL_CHAIN_METERED_DENY_USER:
return FIREWALL_DENYLIST;
case FIREWALL_CHAIN_DOZABLE:
- return FIREWALL_ALLOWLIST;
case FIREWALL_CHAIN_POWERSAVE:
- return FIREWALL_ALLOWLIST;
case FIREWALL_CHAIN_RESTRICTED:
- return FIREWALL_ALLOWLIST;
case FIREWALL_CHAIN_LOW_POWER_STANDBY:
- return FIREWALL_ALLOWLIST;
case FIREWALL_CHAIN_BACKGROUND:
+ case FIREWALL_CHAIN_METERED_ALLOW:
return FIREWALL_ALLOWLIST;
default:
return isFirewallEnabled() ? FIREWALL_ALLOWLIST : FIREWALL_DENYLIST;
@@ -1360,6 +1413,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
return mUidFirewallLowPowerStandbyRules;
case FIREWALL_CHAIN_BACKGROUND:
return mUidFirewallBackgroundRules;
+ case FIREWALL_CHAIN_METERED_ALLOW:
+ return mUidMeteredFirewallAllowRules;
+ case FIREWALL_CHAIN_METERED_DENY_USER:
+ return mUidMeteredFirewallDenyUserRules;
+ case FIREWALL_CHAIN_METERED_DENY_ADMIN:
+ return mUidMeteredFirewallDenyAdminRules;
case FIREWALL_CHAIN_NONE:
return mUidFirewallRules;
default:
@@ -1378,6 +1437,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ pw.println("Flags:");
+ pw.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": " + mUseMeteredFirewallChains);
+ pw.println();
+
synchronized (mQuotaLock) {
pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
@@ -1416,6 +1479,27 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
pw.print("UID firewall background chain enabled: ");
pw.println(getFirewallChainState(FIREWALL_CHAIN_BACKGROUND));
dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_BACKGROUND, mUidFirewallBackgroundRules);
+
+ pw.print("UID firewall metered allow chain enabled (Data saver mode): ");
+ // getFirewallChainState should maintain a duplicated state from mDataSaverMode when
+ // mUseMeteredFirewallChains is enabled.
+ pw.println(getFirewallChainState(FIREWALL_CHAIN_METERED_ALLOW));
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_METERED_ALLOW,
+ mUidMeteredFirewallAllowRules);
+
+ pw.print("UID firewall metered deny_user chain enabled (always-on): ");
+ // This always-on state should be reflected by getFirewallChainState when
+ // mUseMeteredFirewallChains is enabled.
+ pw.println(getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_USER));
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_METERED_DENY_USER,
+ mUidMeteredFirewallDenyUserRules);
+
+ pw.print("UID firewall metered deny_admin chain enabled (always-on): ");
+ // This always-on state should be reflected by getFirewallChainState when
+ // mUseMeteredFirewallChains is enabled.
+ pw.println(getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_ADMIN));
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN,
+ mUidMeteredFirewallDenyAdminRules);
}
pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
@@ -1520,14 +1604,40 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because it is in background");
return true;
}
- if (mUidRejectOnMetered.get(uid)) {
- if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of no metered data"
- + " in the background");
- return true;
- }
- if (mDataSaverMode && !mUidAllowOnMetered.get(uid)) {
- if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
- return true;
+ if (mUseMeteredFirewallChains) {
+ if (getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_USER)
+ && mUidMeteredFirewallDenyUserRules.get(uid) == FIREWALL_RULE_DENY) {
+ if (DBG) {
+ Slog.d(TAG, "Uid " + uid + " restricted because of user-restricted metered"
+ + " data in the background");
+ }
+ return true;
+ }
+ if (getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_ADMIN)
+ && mUidMeteredFirewallDenyAdminRules.get(uid) == FIREWALL_RULE_DENY) {
+ if (DBG) {
+ Slog.d(TAG, "Uid " + uid + " restricted because of admin-restricted metered"
+ + " data in the background");
+ }
+ return true;
+ }
+ if (getFirewallChainState(FIREWALL_CHAIN_METERED_ALLOW)
+ && mUidMeteredFirewallAllowRules.get(uid) != FIREWALL_RULE_ALLOW) {
+ if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
+ return true;
+ }
+ } else {
+ if (mUidRejectOnMetered.get(uid)) {
+ if (DBG) {
+ Slog.d(TAG, "Uid " + uid
+ + " restricted because of no metered data in the background");
+ }
+ return true;
+ }
+ if (mDataSaverMode && !mUidAllowOnMetered.get(uid)) {
+ if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
+ return true;
+ }
}
return false;
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 8e2d7780204a..681aa8aef219 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -19,6 +19,9 @@ import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
@@ -28,6 +31,9 @@ import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_BACKGROUND;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_ALLOW;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_USER;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
@@ -379,7 +385,7 @@ public class NetworkPolicyLogger {
return "Interfaces of netId=" + netId + " changed to " + newIfaces;
}
- private static String getFirewallChainName(int chain) {
+ static String getFirewallChainName(int chain) {
switch (chain) {
case FIREWALL_CHAIN_DOZABLE:
return FIREWALL_CHAIN_NAME_DOZABLE;
@@ -393,6 +399,12 @@ public class NetworkPolicyLogger {
return FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY;
case FIREWALL_CHAIN_BACKGROUND:
return FIREWALL_CHAIN_NAME_BACKGROUND;
+ case FIREWALL_CHAIN_METERED_ALLOW:
+ return FIREWALL_CHAIN_NAME_METERED_ALLOW;
+ case FIREWALL_CHAIN_METERED_DENY_USER:
+ return FIREWALL_CHAIN_NAME_METERED_DENY_USER;
+ case FIREWALL_CHAIN_METERED_DENY_ADMIN:
+ return FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN;
default:
return String.valueOf(chain);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 22f5332e150c..c60ac3a74ebd 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -60,6 +60,9 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
@@ -514,6 +517,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private boolean mBackgroundNetworkRestricted;
+ /**
+ * Whether or not metered firewall chains should be used for uid policy controlling access to
+ * metered networks.
+ */
+ private boolean mUseMeteredFirewallChains;
+
// See main javadoc for instructions on how to use these locks.
final Object mUidRulesFirstLock = new Object();
final Object mNetworkPoliciesSecondLock = new Object();
@@ -997,6 +1006,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mAppStandby = LocalServices.getService(AppStandbyInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mUseMeteredFirewallChains = Flags.useMeteredFirewallChains();
+
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
updatePowerSaveAllowlistUL();
@@ -4030,8 +4041,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.println();
fout.println("Flags:");
- fout.println("Network blocked for TOP_SLEEPING and above: "
+ fout.println(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE + ": "
+ mBackgroundNetworkRestricted);
+ fout.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": "
+ + mUseMeteredFirewallChains);
fout.println();
fout.println("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
@@ -5373,23 +5386,44 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
postUidRulesChangedMsg(uid, uidRules);
}
- // Note that the conditionals below are for avoiding unnecessary calls to netd.
- // TODO: Measure the performance for doing a no-op call to netd so that we can
- // remove the conditionals to simplify the logic below. We can also further reduce
- // some calls to netd if they turn out to be costly.
- final int denylistReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
- | BLOCKED_METERED_REASON_USER_RESTRICTED;
- if ((oldEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE
- || (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE) {
- setMeteredNetworkDenylist(uid,
- (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE);
- }
- final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
- | ALLOWED_METERED_REASON_USER_EXEMPTED;
- if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
- || (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
- setMeteredNetworkAllowlist(uid,
- (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
+ if (mUseMeteredFirewallChains) {
+ if ((newEffectiveBlockedReasons & BLOCKED_METERED_REASON_ADMIN_DISABLED)
+ != BLOCKED_REASON_NONE) {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_DENY_ADMIN, uid, FIREWALL_RULE_DENY);
+ } else {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_DENY_ADMIN, uid, FIREWALL_RULE_DEFAULT);
+ }
+ if ((newEffectiveBlockedReasons & BLOCKED_METERED_REASON_USER_RESTRICTED)
+ != BLOCKED_REASON_NONE) {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_DENY);
+ } else {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_DEFAULT);
+ }
+ if ((newAllowedReasons & (ALLOWED_METERED_REASON_FOREGROUND
+ | ALLOWED_METERED_REASON_USER_EXEMPTED)) != ALLOWED_REASON_NONE) {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_ALLOW);
+ } else {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_DEFAULT);
+ }
+ } else {
+ // Note that the conditionals below are for avoiding unnecessary calls to netd.
+ // TODO: Measure the performance for doing a no-op call to netd so that we can
+ // remove the conditionals to simplify the logic below. We can also further reduce
+ // some calls to netd if they turn out to be costly.
+ final int denylistReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
+ | BLOCKED_METERED_REASON_USER_RESTRICTED;
+ if ((oldEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE
+ || (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE) {
+ setMeteredNetworkDenylist(uid,
+ (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE);
+ }
+ final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
+ | ALLOWED_METERED_REASON_USER_EXEMPTED;
+ if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
+ || (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
+ setMeteredNetworkAllowlist(uid,
+ (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
+ }
}
}
@@ -6149,6 +6183,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} else if (chain == FIREWALL_CHAIN_BACKGROUND) {
mUidFirewallBackgroundRules.put(uid, rule);
}
+ // Note that we do not need keep a separate cache of uid rules for chains that we do
+ // not call #setUidFirewallRulesUL for.
try {
mNetworkManager.setFirewallUidRule(chain, uid, rule);
@@ -6206,10 +6242,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
FIREWALL_RULE_DEFAULT);
mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, uid,
FIREWALL_RULE_DEFAULT);
- mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
- mLogger.meteredAllowlistChanged(uid, false);
- mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
- mLogger.meteredDenylistChanged(uid, false);
+ if (mUseMeteredFirewallChains) {
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_USER, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_METERED_ALLOW, uid,
+ FIREWALL_RULE_DEFAULT);
+ } else {
+ mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
+ mLogger.meteredAllowlistChanged(uid, false);
+ mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
+ mLogger.meteredDenylistChanged(uid, false);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem resetting firewall uid rules for " + uid, e);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/net/flags.aconfig b/services/core/java/com/android/server/net/flags.aconfig
index d9491de52d87..e986dd81b94b 100644
--- a/services/core/java/com/android/server/net/flags.aconfig
+++ b/services/core/java/com/android/server/net/flags.aconfig
@@ -7,3 +7,13 @@ flag {
description: "Block network access for apps in a low importance background state"
bug: "304347838"
}
+
+flag {
+ name: "use_metered_firewall_chains"
+ namespace: "backstage_power"
+ description: "Use metered firewall chains to control access to metered networks"
+ bug: "336693007"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java b/services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java
index 681dd0b49f4e..eb3f1e1e5363 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java
@@ -33,6 +33,7 @@ import android.graphics.Bitmap;
import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -41,7 +42,10 @@ import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
+import com.android.internal.infra.AndroidFuture;
+
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeoutException;
/**
* Util methods for ensuring the Bundle passed in various methods are read-only and restricted to
@@ -84,10 +88,9 @@ public class BundleUtil {
} else if (obj instanceof SharedMemory) {
((SharedMemory) obj).setProtect(PROT_READ);
} else if (obj instanceof Bitmap) {
- if (((Bitmap) obj).isMutable()) {
- throw new BadParcelableException(
- "Encountered a mutable Bitmap in the Bundle at key : " + key);
- }
+ validateBitmap((Bitmap) obj);
+ } else if (obj instanceof Parcelable[]) {
+ validateParcelableArray((Parcelable[]) obj);
} else {
throw new BadParcelableException(
"Unsupported Parcelable type encountered in the Bundle: "
@@ -128,17 +131,15 @@ public class BundleUtil {
if (obj instanceof ParcelFileDescriptor) {
validatePfdReadOnly((ParcelFileDescriptor) obj);
} else if (obj instanceof Bitmap) {
- if (((Bitmap) obj).isMutable()) {
- throw new BadParcelableException(
- "Encountered a mutable Bitmap in the Bundle at key : " + key);
- }
+ validateBitmap((Bitmap) obj);
+ } else if (obj instanceof Parcelable[]) {
+ validateParcelableArray((Parcelable[]) obj);
} else {
throw new BadParcelableException(
"Unsupported Parcelable type encountered in the Bundle: "
+ obj.getClass().getSimpleName());
}
}
- Log.e(TAG, "validateResponseParams : Finished");
}
/**
@@ -183,7 +184,8 @@ public class BundleUtil {
public static IStreamingResponseCallback wrapWithValidation(
IStreamingResponseCallback streamingResponseCallback,
- Executor resourceClosingExecutor) {
+ Executor resourceClosingExecutor,
+ AndroidFuture future) {
return new IStreamingResponseCallback.Stub() {
@Override
public void onNewContent(Bundle processedResult) throws RemoteException {
@@ -203,6 +205,7 @@ public class BundleUtil {
streamingResponseCallback.onSuccess(resultBundle);
} finally {
resourceClosingExecutor.execute(() -> tryCloseResource(resultBundle));
+ future.complete(null);
}
}
@@ -210,6 +213,7 @@ public class BundleUtil {
public void onFailure(int errorCode, String errorMessage,
PersistableBundle errorParams) throws RemoteException {
streamingResponseCallback.onFailure(errorCode, errorMessage, errorParams);
+ future.completeExceptionally(new TimeoutException());
}
@Override
@@ -237,7 +241,8 @@ public class BundleUtil {
}
public static IResponseCallback wrapWithValidation(IResponseCallback responseCallback,
- Executor resourceClosingExecutor) {
+ Executor resourceClosingExecutor,
+ AndroidFuture future) {
return new IResponseCallback.Stub() {
@Override
public void onSuccess(Bundle resultBundle)
@@ -247,6 +252,7 @@ public class BundleUtil {
responseCallback.onSuccess(resultBundle);
} finally {
resourceClosingExecutor.execute(() -> tryCloseResource(resultBundle));
+ future.complete(null);
}
}
@@ -254,6 +260,7 @@ public class BundleUtil {
public void onFailure(int errorCode, String errorMessage,
PersistableBundle errorParams) throws RemoteException {
responseCallback.onFailure(errorCode, errorMessage, errorParams);
+ future.completeExceptionally(new TimeoutException());
}
@Override
@@ -280,17 +287,20 @@ public class BundleUtil {
}
- public static ITokenInfoCallback wrapWithValidation(ITokenInfoCallback responseCallback) {
+ public static ITokenInfoCallback wrapWithValidation(ITokenInfoCallback responseCallback,
+ AndroidFuture future) {
return new ITokenInfoCallback.Stub() {
@Override
public void onSuccess(TokenInfo tokenInfo) throws RemoteException {
responseCallback.onSuccess(tokenInfo);
+ future.complete(null);
}
@Override
public void onFailure(int errorCode, String errorMessage, PersistableBundle errorParams)
throws RemoteException {
responseCallback.onFailure(errorCode, errorMessage, errorParams);
+ future.completeExceptionally(new TimeoutException());
}
};
}
@@ -310,6 +320,26 @@ public class BundleUtil {
}
}
+ private static void validateParcelableArray(Parcelable[] parcelables) {
+ if (parcelables.length > 0
+ && parcelables[0] instanceof ParcelFileDescriptor) {
+ // Safe to cast
+ validatePfdsReadOnly(parcelables);
+ } else if (parcelables.length > 0
+ && parcelables[0] instanceof Bitmap) {
+ validateBitmapsImmutable(parcelables);
+ } else {
+ throw new BadParcelableException(
+ "Could not cast to any known parcelable array");
+ }
+ }
+
+ public static void validatePfdsReadOnly(Parcelable[] pfds) {
+ for (Parcelable pfd : pfds) {
+ validatePfdReadOnly((ParcelFileDescriptor) pfd);
+ }
+ }
+
public static void validatePfdReadOnly(ParcelFileDescriptor pfd) {
if (pfd == null) {
return;
@@ -326,6 +356,19 @@ public class BundleUtil {
}
}
+ private static void validateBitmap(Bitmap obj) {
+ if (obj.isMutable()) {
+ throw new BadParcelableException(
+ "Encountered a mutable Bitmap in the Bundle at key : " + obj);
+ }
+ }
+
+ private static void validateBitmapsImmutable(Parcelable[] bitmaps) {
+ for (Parcelable bitmap : bitmaps) {
+ validateBitmap((Bitmap) bitmap);
+ }
+ }
+
public static void tryCloseResource(Bundle bundle) {
if (bundle == null || bundle.isEmpty() || !bundle.hasFileDescriptors()) {
return;
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index 235e3cd7c9d2..b2e861cf2876 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -33,6 +33,7 @@ import android.annotation.RequiresPermission;
import android.app.AppGlobals;
import android.app.ondeviceintelligence.DownloadCallback;
import android.app.ondeviceintelligence.Feature;
+import android.app.ondeviceintelligence.FeatureDetails;
import android.app.ondeviceintelligence.IDownloadCallback;
import android.app.ondeviceintelligence.IFeatureCallback;
import android.app.ondeviceintelligence.IFeatureDetailsCallback;
@@ -64,6 +65,7 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.provider.Settings;
import android.service.ondeviceintelligence.IOnDeviceIntelligenceService;
import android.service.ondeviceintelligence.IOnDeviceSandboxedInferenceService;
import android.service.ondeviceintelligence.IProcessingUpdateStatusCallback;
@@ -82,13 +84,17 @@ import com.android.internal.infra.ServiceConnector;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.ondeviceintelligence.callbacks.ListenableDownloadCallback;
import java.io.FileDescriptor;
import java.io.IOException;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* This is the system service for handling calls on the
@@ -135,7 +141,6 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
@GuardedBy("mLock")
private String[] mTemporaryServiceNames;
-
@GuardedBy("mLock")
private String[] mTemporaryBroadcastKeys;
@GuardedBy("mLock")
@@ -145,6 +150,8 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
* Handler used to reset the temporary service names.
*/
private Handler mTemporaryHandler;
+ private final @NonNull Handler mMainHandler = new Handler(Looper.getMainLooper());
+
public OnDeviceIntelligenceManagerService(Context context) {
super(context);
@@ -204,8 +211,16 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
return;
}
ensureRemoteIntelligenceServiceInitialized();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.getVersion(remoteCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.getVersion(new RemoteCallback(
+ result -> {
+ remoteCallback.sendResult(result);
+ future.complete(null);
+ }));
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
}
@Override
@@ -225,8 +240,25 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteIntelligenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.getFeature(callerUid, id, featureCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.getFeature(callerUid, id, new IFeatureCallback.Stub() {
+ @Override
+ public void onSuccess(Feature result) throws RemoteException {
+ featureCallback.onSuccess(result);
+ future.complete(null);
+ }
+
+ @Override
+ public void onFailure(int errorCode, String errorMessage,
+ PersistableBundle errorParams) throws RemoteException {
+ featureCallback.onFailure(errorCode, errorMessage, errorParams);
+ future.completeExceptionally(new TimeoutException());
+ }
+ });
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
}
@Override
@@ -246,9 +278,29 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteIntelligenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.listFeatures(callerUid,
- listFeaturesCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.listFeatures(callerUid,
+ new IListFeaturesCallback.Stub() {
+ @Override
+ public void onSuccess(List<Feature> result)
+ throws RemoteException {
+ listFeaturesCallback.onSuccess(result);
+ future.complete(null);
+ }
+
+ @Override
+ public void onFailure(int errorCode, String errorMessage,
+ PersistableBundle errorParams)
+ throws RemoteException {
+ listFeaturesCallback.onFailure(errorCode, errorMessage,
+ errorParams);
+ future.completeExceptionally(new TimeoutException());
+ }
+ });
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
}
@Override
@@ -270,9 +322,29 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteIntelligenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.getFeatureDetails(callerUid, feature,
- featureDetailsCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.getFeatureDetails(callerUid, feature,
+ new IFeatureDetailsCallback.Stub() {
+ @Override
+ public void onSuccess(FeatureDetails result)
+ throws RemoteException {
+ future.complete(null);
+ featureDetailsCallback.onSuccess(result);
+ }
+
+ @Override
+ public void onFailure(int errorCode, String errorMessage,
+ PersistableBundle errorParams)
+ throws RemoteException {
+ future.completeExceptionally(null);
+ featureDetailsCallback.onFailure(errorCode,
+ errorMessage, errorParams);
+ }
+ });
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
}
@Override
@@ -293,10 +365,20 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteIntelligenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.requestFeatureDownload(callerUid, feature,
- wrapCancellationFuture(cancellationSignalFuture),
- downloadCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ ListenableDownloadCallback listenableDownloadCallback =
+ new ListenableDownloadCallback(
+ downloadCallback,
+ mMainHandler, future, getIdleTimeoutMs());
+ service.requestFeatureDownload(callerUid, feature,
+ wrapCancellationFuture(cancellationSignalFuture),
+ listenableDownloadCallback);
+ return future; // this future has no timeout because, actual download
+ // might take long, but we fail early if there is no progress callbacks.
+ }
+ );
}
@@ -323,11 +405,15 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteInferenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- result = mRemoteInferenceService.post(
- service -> service.requestTokenInfo(callerUid, feature,
- request,
- wrapCancellationFuture(cancellationSignalFuture),
- wrapWithValidation(tokenInfoCallback)));
+ result = mRemoteInferenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.requestTokenInfo(callerUid, feature,
+ request,
+ wrapCancellationFuture(cancellationSignalFuture),
+ wrapWithValidation(tokenInfoCallback, future));
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
result.whenCompleteAsync((c, e) -> BundleUtil.tryCloseResource(request),
resourceClosingExecutor);
} finally {
@@ -362,13 +448,18 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteInferenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- result = mRemoteInferenceService.post(
- service -> service.processRequest(callerUid, feature,
- request,
- requestType,
- wrapCancellationFuture(cancellationSignalFuture),
- wrapProcessingFuture(processingSignalFuture),
- wrapWithValidation(responseCallback, resourceClosingExecutor)));
+ result = mRemoteInferenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.processRequest(callerUid, feature,
+ request,
+ requestType,
+ wrapCancellationFuture(cancellationSignalFuture),
+ wrapProcessingFuture(processingSignalFuture),
+ wrapWithValidation(responseCallback,
+ resourceClosingExecutor, future));
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
result.whenCompleteAsync((c, e) -> BundleUtil.tryCloseResource(request),
resourceClosingExecutor);
} finally {
@@ -402,13 +493,18 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteInferenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- result = mRemoteInferenceService.post(
- service -> service.processRequestStreaming(callerUid,
- feature,
- request, requestType,
- wrapCancellationFuture(cancellationSignalFuture),
- wrapProcessingFuture(processingSignalFuture),
- streamingCallback));
+ result = mRemoteInferenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.processRequestStreaming(callerUid,
+ feature,
+ request, requestType,
+ wrapCancellationFuture(cancellationSignalFuture),
+ wrapProcessingFuture(processingSignalFuture),
+ wrapWithValidation(streamingCallback,
+ resourceClosingExecutor, future));
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
result.whenCompleteAsync((c, e) -> BundleUtil.tryCloseResource(request),
resourceClosingExecutor);
} finally {
@@ -859,4 +955,10 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
return mTemporaryHandler;
}
+
+ private long getIdleTimeoutMs() {
+ return Settings.Secure.getLongForUser(mContext.getContentResolver(),
+ Settings.Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS, TimeUnit.HOURS.toMillis(1),
+ mContext.getUserId());
+ }
}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java
index 48258d7bea72..ac9747aa83b3 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java
@@ -22,17 +22,21 @@ import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.provider.Settings;
import android.service.ondeviceintelligence.IOnDeviceIntelligenceService;
import android.service.ondeviceintelligence.OnDeviceIntelligenceService;
import com.android.internal.infra.ServiceConnector;
+import java.util.concurrent.TimeUnit;
+
/**
* Manages the connection to the remote on-device intelligence service. Also, handles unbinding
* logic set by the service implementation via a Secure Settings flag.
*/
public class RemoteOnDeviceIntelligenceService extends
ServiceConnector.Impl<IOnDeviceIntelligenceService> {
+ private static final long LONG_TIMEOUT = TimeUnit.HOURS.toMillis(4);
private static final String TAG =
RemoteOnDeviceIntelligenceService.class.getSimpleName();
@@ -48,9 +52,15 @@ public class RemoteOnDeviceIntelligenceService extends
}
@Override
+ protected long getRequestTimeoutMs() {
+ return LONG_TIMEOUT;
+ }
+
+ @Override
protected long getAutoDisconnectTimeoutMs() {
- // Disable automatic unbinding.
- // TODO: add logic to fetch this flag via SecureSettings.
- return -1;
+ return Settings.Secure.getLongForUser(mContext.getContentResolver(),
+ Settings.Secure.ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS,
+ TimeUnit.SECONDS.toMillis(30),
+ mContext.getUserId());
}
}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java
index 69ba1d2fb599..18b13838ea7c 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java
@@ -22,18 +22,24 @@ import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.provider.Settings;
import android.service.ondeviceintelligence.IOnDeviceSandboxedInferenceService;
import android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService;
import com.android.internal.infra.ServiceConnector;
+import java.util.concurrent.TimeUnit;
+
/**
- * Manages the connection to the remote on-device sand boxed inference service. Also, handles unbinding
+ * Manages the connection to the remote on-device sand boxed inference service. Also, handles
+ * unbinding
* logic set by the service implementation via a SecureSettings flag.
*/
public class RemoteOnDeviceSandboxedInferenceService extends
ServiceConnector.Impl<IOnDeviceSandboxedInferenceService> {
+ private static final long LONG_TIMEOUT = TimeUnit.HOURS.toMillis(1);
+
/**
* Creates an instance of {@link ServiceConnector}
*
@@ -54,11 +60,17 @@ public class RemoteOnDeviceSandboxedInferenceService extends
connect();
}
+ @Override
+ protected long getRequestTimeoutMs() {
+ return LONG_TIMEOUT;
+ }
+
@Override
protected long getAutoDisconnectTimeoutMs() {
- // Disable automatic unbinding.
- // TODO: add logic to fetch this flag via SecureSettings.
- return -1;
+ return Settings.Secure.getLongForUser(mContext.getContentResolver(),
+ Settings.Secure.ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS,
+ TimeUnit.SECONDS.toMillis(30),
+ mContext.getUserId());
}
}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/callbacks/ListenableDownloadCallback.java b/services/core/java/com/android/server/ondeviceintelligence/callbacks/ListenableDownloadCallback.java
new file mode 100644
index 000000000000..32f0698a8f9c
--- /dev/null
+++ b/services/core/java/com/android/server/ondeviceintelligence/callbacks/ListenableDownloadCallback.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.ondeviceintelligence.callbacks;
+
+import android.app.ondeviceintelligence.IDownloadCallback;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This class extends the {@link IDownloadCallback} and adds a timeout Runnable to the callback
+ * such that, in the case where the callback methods are not invoked, we do not have to wait for
+ * timeout based on {@link #onDownloadCompleted} which might take minutes or hours to complete in
+ * some cases. Instead, in such cases we rely on the remote service sending progress updates and if
+ * there are *no* progress callbacks in the duration of {@link #idleTimeoutMs}, we can assume the
+ * download will not complete and enabling faster cleanup.
+ */
+public class ListenableDownloadCallback extends IDownloadCallback.Stub implements Runnable {
+ private final IDownloadCallback callback;
+ private final Handler handler;
+ private final AndroidFuture future;
+ private final long idleTimeoutMs;
+
+ /**
+ * Constructor to create a ListenableDownloadCallback.
+ *
+ * @param callback callback to send download updates to caller.
+ * @param handler handler to schedule timeout runnable.
+ * @param future future to complete to signal the callback has reached a terminal state.
+ * @param idleTimeoutMs timeout within which download updates should be received.
+ */
+ public ListenableDownloadCallback(IDownloadCallback callback, Handler handler,
+ AndroidFuture future,
+ long idleTimeoutMs) {
+ this.callback = callback;
+ this.handler = handler;
+ this.future = future;
+ this.idleTimeoutMs = idleTimeoutMs;
+ handler.postDelayed(this,
+ idleTimeoutMs); // init the timeout runnable in case no callback is ever invoked
+ }
+
+ @Override
+ public void onDownloadStarted(long bytesToDownload) throws RemoteException {
+ callback.onDownloadStarted(bytesToDownload);
+ handler.removeCallbacks(this);
+ handler.postDelayed(this, idleTimeoutMs);
+ }
+
+ @Override
+ public void onDownloadProgress(long bytesDownloaded) throws RemoteException {
+ callback.onDownloadProgress(bytesDownloaded);
+ handler.removeCallbacks(this); // remove previously queued timeout tasks.
+ handler.postDelayed(this, idleTimeoutMs); // queue fresh timeout task for next update.
+ }
+
+ @Override
+ public void onDownloadFailed(int failureStatus,
+ String errorMessage, PersistableBundle errorParams) throws RemoteException {
+ callback.onDownloadFailed(failureStatus, errorMessage, errorParams);
+ handler.removeCallbacks(this);
+ future.completeExceptionally(new TimeoutException());
+ }
+
+ @Override
+ public void onDownloadCompleted(
+ android.os.PersistableBundle downloadParams) throws RemoteException {
+ callback.onDownloadCompleted(downloadParams);
+ handler.removeCallbacks(this);
+ future.complete(null);
+ }
+
+ @Override
+ public void run() {
+ future.completeExceptionally(
+ new TimeoutException()); // complete the future as we haven't received updates
+ // for download progress.
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b1976cd0d13b..4ff345fbedf9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -600,8 +600,11 @@ public class UserManagerService extends IUserManager.Stub {
public void onReceive(Context context, Intent intent) {
if (isAutoLockForPrivateSpaceEnabled()) {
if (ACTION_SCREEN_OFF.equals(intent.getAction())) {
+ Slog.d(LOG_TAG, "SCREEN_OFF broadcast received");
maybeScheduleMessageToAutoLockPrivateSpace();
} else if (ACTION_SCREEN_ON.equals(intent.getAction())) {
+ Slog.d(LOG_TAG, "SCREEN_ON broadcast received, "
+ + "removing queued message to auto-lock private space");
// Remove any queued messages since the device is interactive again
mHandler.removeCallbacksAndMessages(PRIVATE_SPACE_AUTO_LOCK_MESSAGE_TOKEN);
}
@@ -619,6 +622,8 @@ public class UserManagerService extends IUserManager.Stub {
getMainUserIdUnchecked());
if (privateSpaceAutoLockPreference
!= Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY) {
+ Slogf.d(LOG_TAG, "Not scheduling auto-lock on inactivity,"
+ + "preference is set to %d", privateSpaceAutoLockPreference);
return;
}
int privateProfileUserId = getPrivateProfileUserId();
@@ -632,6 +637,7 @@ public class UserManagerService extends IUserManager.Stub {
@VisibleForTesting
void scheduleMessageToAutoLockPrivateSpace(int userId, Object token,
long delayInMillis) {
+ Slog.i(LOG_TAG, "Scheduling auto-lock message");
mHandler.postDelayed(() -> {
final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
if (powerManager != null && !powerManager.isInteractive()) {
@@ -1060,8 +1066,6 @@ public class UserManagerService extends IUserManager.Stub {
if (isAutoLockingPrivateSpaceOnRestartsEnabled()) {
autoLockPrivateSpace();
}
-
- markEphemeralUsersForRemoval();
}
private boolean isAutoLockingPrivateSpaceOnRestartsEnabled() {
@@ -1098,21 +1102,6 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- /** Marks all ephemeral users as slated for deletion. **/
- private void markEphemeralUsersForRemoval() {
- synchronized (mUsersLock) {
- final int userSize = mUsers.size();
- for (int i = 0; i < userSize; i++) {
- final UserInfo ui = mUsers.valueAt(i).info;
- if (ui.isEphemeral() && !ui.preCreated && ui.id != UserHandle.USER_SYSTEM) {
- addRemovingUserIdLocked(ui.id);
- ui.partial = true;
- ui.flags |= UserInfo.FLAG_DISABLED;
- }
- }
- }
- }
-
/* Prunes out any partially created or partially removed users. */
private void cleanupPartialUsers() {
ArrayList<UserInfo> partials = new ArrayList<>();
@@ -4223,6 +4212,13 @@ public class UserManagerService extends IUserManager.Stub {
|| mNextSerialNumber <= userData.info.id) {
mNextSerialNumber = userData.info.id + 1;
}
+ if (userData.info.isEphemeral() && !userData.info.preCreated
+ && userData.info.id != UserHandle.USER_SYSTEM) {
+ // Mark ephemeral user as slated for deletion.
+ addRemovingUserIdLocked(userData.info.id);
+ userData.info.partial = true;
+ userData.info.flags |= UserInfo.FLAG_DISABLED;
+ }
}
}
} else if (name.equals(TAG_GUEST_RESTRICTIONS)) {
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 b26b6162b734..3b9ad1915478 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -64,7 +64,6 @@ import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STA
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__UNKNOWN;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.Flags.addMobileBytesTransferByProcStatePuller;
-import static com.android.server.stats.Flags.statsPullNetworkStatsManagerInitOrderFix;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
import static com.android.server.stats.pull.ProcfsMemoryUtil.getProcessCmdlines;
@@ -434,12 +433,6 @@ public class StatsPullAtomService extends SystemService {
public static final boolean ENABLE_MOBILE_DATA_STATS_AGGREGATED_PULLER =
addMobileBytesTransferByProcStatePuller();
- /**
- * Whether or not to enable the mNetworkStatsManager initialization order fix
- */
- private static final boolean ENABLE_NETWORK_STATS_MANAGER_INIT_ORDER_FIX =
- statsPullNetworkStatsManagerInitOrderFix();
-
// Puller locks
private final Object mDataBytesTransferLock = new Object();
private final Object mBluetoothBytesTransferLock = new Object();
@@ -843,7 +836,7 @@ public class StatsPullAtomService extends SystemService {
registerEventListeners();
});
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- if (ENABLE_NETWORK_STATS_MANAGER_INIT_ORDER_FIX) {
+ if (true) {
initNetworkStatsManager();
}
BackgroundThread.getHandler().post(() -> {
@@ -866,7 +859,7 @@ public class StatsPullAtomService extends SystemService {
mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
mStatsSubscriptionsListener = new StatsSubscriptionsListener(mSubscriptionManager);
mStorageManager = (StorageManager) mContext.getSystemService(StorageManager.class);
- if (!ENABLE_NETWORK_STATS_MANAGER_INIT_ORDER_FIX) {
+ if (false) {
initNetworkStatsManager();
}
@@ -1050,7 +1043,7 @@ public class StatsPullAtomService extends SystemService {
*/
@NonNull
private NetworkStatsManager getNetworkStatsManager() {
- if (ENABLE_NETWORK_STATS_MANAGER_INIT_ORDER_FIX) {
+ if (true) {
if (mNetworkStatsManager == null) {
throw new IllegalStateException("NetworkStatsManager is not ready");
}
diff --git a/services/core/java/com/android/server/stats/stats_flags.aconfig b/services/core/java/com/android/server/stats/stats_flags.aconfig
index c479c6d11164..6faa2737ac30 100644
--- a/services/core/java/com/android/server/stats/stats_flags.aconfig
+++ b/services/core/java/com/android/server/stats/stats_flags.aconfig
@@ -8,11 +8,3 @@ flag {
bug: "309512867"
is_fixed_read_only: true
}
-
-flag {
- name: "stats_pull_network_stats_manager_init_order_fix"
- namespace: "statsd"
- description: "Fix the mNetworkStatsManager initialization order"
- bug: "331989853"
- is_fixed_read_only: true
-}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 21e4c967a995..2b32a30c31b4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3272,8 +3272,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mOccludesParent = occludesParent;
setMainWindowOpaque(occludesParent);
- if (changed && task != null && !occludesParent) {
- getRootTask().convertActivityToTranslucent(this);
+ if (changed && task != null) {
+ if (!occludesParent) {
+ getRootTask().convertActivityToTranslucent(this);
+ } else {
+ getRootTask().convertActivityFromTranslucent(this);
+ }
}
// Always ensure visibility if this activity doesn't occlude parent, so the
// {@link #returningOptions} of the activity under this one can be applied in
@@ -4266,6 +4270,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
getTaskFragment().cleanUpActivityReferences(this);
clearLastParentBeforePip();
+ // Abort and reset state if the scence transition is playing.
+ final Task rootTask = getRootTask();
+ if (rootTask != null) {
+ rootTask.abortTranslucentActivityWaiting(this);
+ }
+
// Clean up the splash screen if it was still displayed.
cleanUpSplashScreen();
@@ -11111,7 +11121,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* Otherwise, return the creation time of the top window.
*/
long getLastWindowCreateTime() {
- final WindowState window = getWindow(win -> true);
+ final WindowState window = getWindow(alwaysTruePredicate());
return window != null && window.mAttrs.type != TYPE_BASE_APPLICATION
? window.getCreateTime()
: createTime;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 330336760413..68d150e24f69 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1768,6 +1768,7 @@ class ActivityStarter {
if (!avoidMoveToFront() && (mService.mHomeProcess == null
|| mService.mHomeProcess.mUid != realCallingUid)
&& (prevTopTask != null && prevTopTask.isActivityTypeHomeOrRecents())
+ && !targetTask.isActivityTypeHomeOrRecents()
&& r.mTransitionController.isTransientHide(targetTask)) {
mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
}
@@ -2167,7 +2168,7 @@ class ActivityStarter {
// We don't need to start a new activity, and the client said not to do anything
// if that is the case, so this is it! And for paranoia, make sure we have
// correctly resumed the top activity.
- if (!mMovedToFront && mDoResume) {
+ if (!mMovedToFront && mDoResume && !avoidMoveToFront()) {
ProtoLog.d(WM_DEBUG_TASKS, "Bring to front target: %s from %s", mTargetRootTask,
targetTaskTop);
mTargetRootTask.moveToFront("intentActivityFound");
@@ -2196,7 +2197,7 @@ class ActivityStarter {
if (mMovedToFront) {
// We moved the task to front, use starting window to hide initial drawn delay.
targetTaskTop.showStartingWindow(true /* taskSwitch */);
- } else if (mDoResume) {
+ } else if (mDoResume && !avoidMoveToFront()) {
// Make sure the root task and its belonging display are moved to topmost.
mTargetRootTask.moveToFront("intentActivityFound");
}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index c9703d871431..0e4f0335118d 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -1732,7 +1732,10 @@ class BackNavigationController {
// The activity was detached from hierarchy.
return;
}
- activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
+
+ if (activity.mDisplayContent.isFixedRotationLaunchingApp(activity)) {
+ activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
+ }
// Restore the launch-behind state.
activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c9a5e71ef1fd..a5853c013c7b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2755,7 +2755,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@Nullable
Task getTopRootTask() {
- return getRootTask(t -> true);
+ return getRootTask(alwaysTruePredicate());
}
/**
diff --git a/services/core/java/com/android/server/wm/PerfettoTransitionTracer.java b/services/core/java/com/android/server/wm/PerfettoTransitionTracer.java
index 498182dab9c3..3606a34e23e0 100644
--- a/services/core/java/com/android/server/wm/PerfettoTransitionTracer.java
+++ b/services/core/java/com/android/server/wm/PerfettoTransitionTracer.java
@@ -41,8 +41,12 @@ class PerfettoTransitionTracer implements TransitionTracer {
PerfettoTransitionTracer() {
Producer.init(InitArguments.DEFAULTS);
- mDataSource.register(
- new DataSourceParams(PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT));
+ DataSourceParams params =
+ new DataSourceParams.Builder()
+ .setBufferExhaustedPolicy(
+ PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT)
+ .build();
+ mDataSource.register(params);
}
/**
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8defec3dbeab..a555388ab233 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -297,6 +297,10 @@ class Task extends TaskFragment {
ActivityRecord mTranslucentActivityWaiting = null;
ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<>();
+ // The topmost Activity that was converted to translucent for scene transition, which should
+ // be converted from translucent once the transition is completed, or the app died.
+ private ActivityRecord mPendingConvertFromTranslucentActivity = null;
+
/**
* Set when we know we are going to be calling updateConfiguration()
* soon, so want to skip intermediate config checks.
@@ -4988,6 +4992,27 @@ class Task extends TaskFragment {
}
}
+ void abortTranslucentActivityWaiting(@NonNull ActivityRecord r) {
+ if (r != mTranslucentActivityWaiting && r != mPendingConvertFromTranslucentActivity) {
+ return;
+ }
+
+ if (mTranslucentActivityWaiting != null) {
+ if (!mTranslucentActivityWaiting.finishing) {
+ mTranslucentActivityWaiting.setOccludesParent(true);
+ }
+ mTranslucentActivityWaiting = null;
+ }
+ if (mPendingConvertFromTranslucentActivity != null) {
+ if (!mPendingConvertFromTranslucentActivity.finishing) {
+ mPendingConvertFromTranslucentActivity.setOccludesParent(true);
+ }
+ mPendingConvertFromTranslucentActivity = null;
+ }
+ mUndrawnActivitiesBelowTopTranslucent.clear();
+ mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
+ }
+
void checkTranslucentActivityWaiting(ActivityRecord top) {
if (mTranslucentActivityWaiting != top) {
mUndrawnActivitiesBelowTopTranslucent.clear();
@@ -5002,10 +5027,19 @@ class Task extends TaskFragment {
void convertActivityToTranslucent(ActivityRecord r) {
mTranslucentActivityWaiting = r;
+ mPendingConvertFromTranslucentActivity = r;
mUndrawnActivitiesBelowTopTranslucent.clear();
mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
}
+ void convertActivityFromTranslucent(ActivityRecord r) {
+ if (r != mPendingConvertFromTranslucentActivity) {
+ Slog.e(TAG, "convertFromTranslucent expects " + mPendingConvertFromTranslucentActivity
+ + " but is " + r);
+ }
+ mPendingConvertFromTranslucentActivity = null;
+ }
+
/**
* Called as activities below the top translucent activity are redrawn. When the last one is
* redrawn notify the top activity by calling
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 2c27b98250c9..eff831552320 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -223,7 +223,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
@VisibleForTesting
Task getTopRootTask() {
- return getRootTask(t -> true);
+ return getRootTask(alwaysTruePredicate());
}
@Nullable
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index d70ca02cc23d..edbba9244738 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -116,6 +116,7 @@ import com.android.internal.util.ToBooleanFunction;
import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.android.server.wm.utils.AlwaysTruePredicate;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -2019,29 +2020,34 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
}
+ @SuppressWarnings("unchecked")
+ static <T> Predicate<T> alwaysTruePredicate() {
+ return (Predicate<T>) AlwaysTruePredicate.INSTANCE;
+ }
+
ActivityRecord getActivityAbove(ActivityRecord r) {
- return getActivity((above) -> true, r,
+ return getActivity(alwaysTruePredicate(), r /* boundary */,
false /*includeBoundary*/, false /*traverseTopToBottom*/);
}
ActivityRecord getActivityBelow(ActivityRecord r) {
- return getActivity((below) -> true, r,
+ return getActivity(alwaysTruePredicate(), r /* boundary */,
false /*includeBoundary*/, true /*traverseTopToBottom*/);
}
ActivityRecord getBottomMostActivity() {
- return getActivity((r) -> true, false /*traverseTopToBottom*/);
+ return getActivity(alwaysTruePredicate(), false /* traverseTopToBottom */);
}
ActivityRecord getTopMostActivity() {
- return getActivity((r) -> true, true /*traverseTopToBottom*/);
+ return getActivity(alwaysTruePredicate(), true /* traverseTopToBottom */);
}
ActivityRecord getTopActivity(boolean includeFinishing, boolean includeOverlays) {
// Break down into 4 calls to avoid object creation due to capturing input params.
if (includeFinishing) {
if (includeOverlays) {
- return getActivity((r) -> true);
+ return getActivity(alwaysTruePredicate());
}
return getActivity((r) -> !r.isTaskOverlay());
} else if (includeOverlays) {
@@ -2220,21 +2226,17 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
}
- Task getTaskAbove(Task t) {
- return getTask(
- (above) -> true, t, false /*includeBoundary*/, false /*traverseTopToBottom*/);
- }
-
Task getTaskBelow(Task t) {
- return getTask((below) -> true, t, false /*includeBoundary*/, true /*traverseTopToBottom*/);
+ return getTask(alwaysTruePredicate(), t /* boundary */,
+ false /* includeBoundary */, true /* traverseTopToBottom */);
}
Task getBottomMostTask() {
- return getTask((t) -> true, false /*traverseTopToBottom*/);
+ return getTask(alwaysTruePredicate(), false /* traverseTopToBottom */);
}
Task getTopMostTask() {
- return getTask((t) -> true, true /*traverseTopToBottom*/);
+ return getTask(alwaysTruePredicate(), true /* traverseTopToBottom */);
}
Task getTask(Predicate<Task> callback) {
diff --git a/services/core/java/com/android/server/wm/utils/AlwaysTruePredicate.java b/services/core/java/com/android/server/wm/utils/AlwaysTruePredicate.java
new file mode 100644
index 000000000000..49dcb6cab633
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/AlwaysTruePredicate.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.utils;
+
+import java.util.function.Predicate;
+
+/** A simple Predicate to avoid synthetic allocation of lambda expression "o -> true". */
+public class AlwaysTruePredicate implements Predicate<Object> {
+
+ public static final AlwaysTruePredicate INSTANCE = new AlwaysTruePredicate();
+
+ private AlwaysTruePredicate() {
+ }
+
+ @Override
+ public boolean test(Object o) {
+ return true;
+ }
+}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index a01c1231b373..74ca9ad687ea 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -423,7 +423,7 @@ private:
std::set<int32_t> disabledInputDevices{};
// Associated Pointer controller display.
- ui::LogicalDisplayId pointerDisplayId{ui::ADISPLAY_ID_DEFAULT};
+ ui::LogicalDisplayId pointerDisplayId{ui::LogicalDisplayId::DEFAULT};
// True if stylus button reporting through motion events is enabled.
bool stylusButtonMotionEventsEnabled{true};
@@ -1886,7 +1886,7 @@ static jobject nativeCreateInputMonitor(JNIEnv* env, jobject nativeImplObj, jint
jstring nameObj, jint pid) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- if (displayId == ui::ADISPLAY_ID_NONE.val()) {
+ if (ui::LogicalDisplayId{displayId} == ui::LogicalDisplayId::INVALID) {
std::string message = "InputChannel used as a monitor must be associated with a display";
jniThrowRuntimeException(env, message.c_str());
return nullptr;
@@ -2727,6 +2727,11 @@ static void nativeSetInputMethodConnectionIsActive(JNIEnv* env, jobject nativeIm
im->setInputMethodConnectionIsActive(isActive);
}
+static jint nativeGetLastUsedInputDeviceId(JNIEnv* env, jobject nativeImplObj) {
+ NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+ return static_cast<jint>(im->getInputManager()->getReader().getLastUsedInputDeviceId());
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gInputManagerMethods[] = {
@@ -2835,6 +2840,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"setAccessibilityStickyKeysEnabled", "(Z)V",
(void*)nativeSetAccessibilityStickyKeysEnabled},
{"setInputMethodConnectionIsActive", "(Z)V", (void*)nativeSetInputMethodConnectionIsActive},
+ {"getLastUsedInputDeviceId", "()I", (void*)nativeGetLastUsedInputDeviceId},
};
#define FIND_CLASS(var, className) \
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index ae6361bdd556..df9671235071 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -46,6 +46,7 @@ import com.android.server.display.brightness.strategy.AutomaticBrightnessStrateg
import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
+import com.android.server.display.brightness.strategy.FallbackBrightnessStrategy;
import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy;
import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy;
@@ -90,6 +91,8 @@ public final class DisplayBrightnessStrategySelectorTest {
@Mock
private AutoBrightnessFallbackStrategy mAutoBrightnessFallbackStrategy;
@Mock
+ private FallbackBrightnessStrategy mFallbackBrightnessStrategy;
+ @Mock
private Resources mResources;
@Mock
private DisplayManagerFlags mDisplayManagerFlags;
@@ -135,7 +138,7 @@ public final class DisplayBrightnessStrategySelectorTest {
@Override
AutomaticBrightnessStrategy getAutomaticBrightnessStrategy1(Context context,
- int displayId) {
+ int displayId, DisplayManagerFlags displayManagerFlags) {
return mAutomaticBrightnessStrategy;
}
@@ -155,6 +158,11 @@ public final class DisplayBrightnessStrategySelectorTest {
AutoBrightnessFallbackStrategy getAutoBrightnessFallbackStrategy() {
return mAutoBrightnessFallbackStrategy;
}
+
+ @Override
+ FallbackBrightnessStrategy getFallbackBrightnessStrategy() {
+ return mFallbackBrightnessStrategy;
+ }
};
@Rule
@@ -355,6 +363,25 @@ public final class DisplayBrightnessStrategySelectorTest {
}
@Test
+ public void selectStrategy_selectsFallbackStrategyAsAnUltimateFallback() {
+ when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
+ mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
+ mInjector, DISPLAY_ID, mDisplayManagerFlags);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+ DisplayManagerInternal.DisplayPowerRequest.class);
+ displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+ displayPowerRequest.screenBrightnessOverride = Float.NaN;
+ when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
+ when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
+ when(mAutomaticBrightnessStrategy.shouldUseAutoBrightness()).thenReturn(false);
+ when(mAutomaticBrightnessStrategy.isAutoBrightnessValid()).thenReturn(false);
+ assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
+ new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+ 0.1f, false)),
+ mFallbackBrightnessStrategy);
+ }
+
+ @Test
public void selectStrategyCallsPostProcessorForAllStrategies() {
when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index 3e78118cd5df..19bff56a4b29 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -18,8 +18,10 @@ package com.android.server.display.brightness.strategy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -45,6 +47,7 @@ import com.android.server.display.DisplayBrightnessState;
import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.brightness.StrategyExecutionRequest;
+import com.android.server.display.feature.DisplayManagerFlags;
import org.junit.After;
import org.junit.Before;
@@ -64,6 +67,9 @@ public class AutomaticBrightnessStrategyTest {
@Mock
private AutomaticBrightnessController mAutomaticBrightnessController;
+ @Mock
+ private DisplayManagerFlags mDisplayManagerFlags;
+
private BrightnessConfiguration mBrightnessConfiguration;
private float mDefaultScreenAutoBrightnessAdjustment;
private Context mContext;
@@ -80,7 +86,8 @@ public class AutomaticBrightnessStrategyTest {
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, Float.NaN);
Settings.System.putFloat(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.5f);
- mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, DISPLAY_ID);
+ mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, DISPLAY_ID,
+ mDisplayManagerFlags);
mBrightnessConfiguration = new BrightnessConfiguration.Builder(
new float[]{0f, 1f}, new float[]{0, PowerManager.BRIGHTNESS_ON}).build();
@@ -247,6 +254,46 @@ public class AutomaticBrightnessStrategyTest {
}
@Test
+ public void testAutoBrightnessState_modeSwitch() {
+ // Setup the test
+ when(mDisplayManagerFlags.areAutoBrightnessModesEnabled()).thenReturn(true);
+ mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+ boolean allowAutoBrightnessWhileDozing = false;
+ int brightnessReason = BrightnessReason.REASON_UNKNOWN;
+ float lastUserSetBrightness = 0.2f;
+ boolean userSetBrightnessChanged = true;
+ int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+ float pendingBrightnessAdjustment = 0.1f;
+ Settings.System.putFloat(mContext.getContentResolver(),
+ Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingBrightnessAdjustment);
+ mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments();
+
+ // Validate no interaction when automaticBrightnessController is in idle mode
+ when(mAutomaticBrightnessController.isInIdleMode()).thenReturn(true);
+ mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON,
+ allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+ userSetBrightnessChanged);
+ verify(mAutomaticBrightnessController, never()).switchMode(anyInt());
+
+ // Validate interaction when automaticBrightnessController is in non-idle mode, and display
+ // state is ON
+ when(mAutomaticBrightnessController.isInIdleMode()).thenReturn(false);
+ mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON,
+ allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+ userSetBrightnessChanged);
+ verify(mAutomaticBrightnessController).switchMode(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT);
+
+ // Validate interaction when automaticBrightnessController is in non-idle mode, and display
+ // state is DOZE
+ mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_DOZE,
+ allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+ userSetBrightnessChanged);
+ verify(mAutomaticBrightnessController).switchMode(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE);
+ }
+
+ @Test
public void accommodateUserBrightnessChangesWorksAsExpected() {
// Verify the state if automaticBrightnessController is configured.
assertFalse(mAutomaticBrightnessStrategy.isShortTermModelActive());
@@ -390,7 +437,8 @@ public class AutomaticBrightnessStrategyTest {
@Test
public void testVerifyNoAutoBrightnessAdjustmentsArePopulatedForNonDefaultDisplay() {
int newDisplayId = 1;
- mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, newDisplayId);
+ mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, newDisplayId,
+ mDisplayManagerFlags);
mAutomaticBrightnessStrategy.putAutoBrightnessAdjustmentSetting(0.3f);
assertEquals(0.5f, mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(),
0.0f);
@@ -429,8 +477,7 @@ public class AutomaticBrightnessStrategyTest {
updateBrightness_constructsDisplayBrightnessState_withAdjustmentAutoAdjustmentFlag() {
BrightnessEvent brightnessEvent = new BrightnessEvent(DISPLAY_ID);
mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(
- mContext, DISPLAY_ID, displayId -> brightnessEvent);
- new AutomaticBrightnessStrategy(mContext, DISPLAY_ID);
+ mContext, DISPLAY_ID, displayId -> brightnessEvent, mDisplayManagerFlags);
mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
mAutomaticBrightnessController);
float brightness = 0.4f;
@@ -461,8 +508,7 @@ public class AutomaticBrightnessStrategyTest {
updateBrightness_constructsDisplayBrightnessState_withAdjustmentTempAdjustmentFlag() {
BrightnessEvent brightnessEvent = new BrightnessEvent(DISPLAY_ID);
mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(
- mContext, DISPLAY_ID, displayId -> brightnessEvent);
- new AutomaticBrightnessStrategy(mContext, DISPLAY_ID);
+ mContext, DISPLAY_ID, displayId -> brightnessEvent, mDisplayManagerFlags);
mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
mAutomaticBrightnessController);
float brightness = 0.4f;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
new file mode 100644
index 000000000000..c4767ae5172b
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+
+import static org.junit.Assert.assertEquals;
+
+import android.hardware.display.DisplayManagerInternal;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.StrategyExecutionRequest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+
+public class FallbackBrightnessStrategyTest {
+ private FallbackBrightnessStrategy mFallbackBrightnessStrategy;
+
+ @Before
+ public void before() {
+ mFallbackBrightnessStrategy = new FallbackBrightnessStrategy();
+ }
+
+ @Test
+ public void updateBrightness_currentBrightnessIsSet() {
+ DisplayManagerInternal.DisplayPowerRequest
+ displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
+ float currentBrightness = 0.2f;
+ BrightnessReason brightnessReason = new BrightnessReason();
+ brightnessReason.setReason(BrightnessReason.REASON_MANUAL);
+ DisplayBrightnessState expectedDisplayBrightnessState =
+ new DisplayBrightnessState.Builder()
+ .setBrightness(currentBrightness)
+ .setBrightnessReason(brightnessReason)
+ .setSdrBrightness(currentBrightness)
+ .setDisplayBrightnessStrategyName(mFallbackBrightnessStrategy.getName())
+ .setShouldUpdateScreenBrightnessSetting(true)
+ .build();
+ DisplayBrightnessState updatedDisplayBrightnessState =
+ mFallbackBrightnessStrategy.updateBrightness(
+ new StrategyExecutionRequest(displayPowerRequest, currentBrightness));
+ assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
+ }
+}
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java
index 88ab871529ee..874e99173c63 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java
@@ -273,28 +273,36 @@ public class DreamControllerTest {
}
@Test
- public void setDreamHasFocus_true_dreamHasFocus() {
+ public void setDreamIsObscured_true_dreamIsNotFrontmost() {
mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
- mDreamController.setDreamHasFocus(true);
- assertTrue(mDreamController.dreamHasFocus());
+ mDreamController.setDreamIsObscured(true);
+ assertFalse(mDreamController.dreamIsFrontmost());
}
@Test
- public void setDreamHasFocus_false_dreamDoesNotHaveFocus() {
+ public void setDreamIsObscured_false_dreamIsFrontmost() {
mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
- mDreamController.setDreamHasFocus(false);
- assertFalse(mDreamController.dreamHasFocus());
+ mDreamController.setDreamIsObscured(false);
+ assertTrue(mDreamController.dreamIsFrontmost());
}
@Test
- public void setDreamHasFocus_notDreaming_dreamDoesNotHaveFocus() {
- mDreamController.setDreamHasFocus(true);
- // Dream still doesn't have focus because it was never started.
- assertFalse(mDreamController.dreamHasFocus());
+ public void setDreamIsObscured_notDreaming_dreamIsNotFrontmost() {
+ mDreamController.setDreamIsObscured(true);
+ // Dream still isn't frontmost because it was never started.
+ assertFalse(mDreamController.dreamIsFrontmost());
+ }
+
+ @Test
+ public void startDream_dreamIsFrontmost() {
+ mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
+ 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
+
+ assertTrue(mDreamController.dreamIsFrontmost());
}
private ServiceConnection captureServiceConnection() {
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 27c522d68119..b56af87ee020 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -25,6 +25,13 @@
value="/data/local/tmp/cts/content/broken_shortcut.xml" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" />
+ <option name="set-global-setting" key="verifier_engprod" value="1" />
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="restore-settings" value="true" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
index 07fb9fc2f509..570256bf43e6 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
@@ -19,9 +19,16 @@ package com.android.server.net;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_RULE_DEFAULT;
+import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.util.DebugUtils.valueToString;
import static org.junit.Assert.assertEquals;
@@ -51,7 +58,10 @@ import android.os.PermissionEnforcer;
import android.os.Process;
import android.os.RemoteException;
import android.os.test.FakePermissionEnforcer;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import androidx.test.filters.SmallTest;
@@ -62,6 +72,7 @@ import com.android.modules.utils.build.SdkLevel;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -84,6 +95,9 @@ public class NetworkManagementServiceTest {
@Mock private IBatteryStats.Stub mBatteryStatsService;
@Mock private INetd.Stub mNetdService;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
private static final int TEST_UID = 111;
@NonNull
@@ -254,6 +268,7 @@ public class NetworkManagementServiceTest {
}
@Test
+ @DisableFlags(Flags.FLAG_USE_METERED_FIREWALL_CHAINS)
public void testMeteredNetworkRestrictions() throws RemoteException {
// Make sure the mocked netd method returns true.
doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
@@ -295,6 +310,69 @@ public class NetworkManagementServiceTest {
}
@Test
+ @EnableFlags(Flags.FLAG_USE_METERED_FIREWALL_CHAINS)
+ public void testMeteredNetworkRestrictionsByAdminChain() {
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, TEST_UID,
+ FIREWALL_RULE_DENY);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, TEST_UID,
+ FIREWALL_RULE_DENY);
+ assertTrue("Should be true since mobile data usage is restricted by admin chain",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ assertFalse("Should be false since mobile data usage is no longer restricted by admin",
+ mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_USE_METERED_FIREWALL_CHAINS)
+ public void testMeteredNetworkRestrictionsByUserChain() {
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_USER, TEST_UID,
+ FIREWALL_RULE_DENY);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, TEST_UID,
+ FIREWALL_RULE_DENY);
+ assertTrue("Should be true since mobile data usage is restricted by user chain",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_USER, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ assertFalse("Should be false since mobile data usage is no longer restricted by user",
+ mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_USE_METERED_FIREWALL_CHAINS)
+ public void testDataSaverRestrictionsWithAllowChain() {
+ mNMService.setDataSaverModeEnabled(true);
+ verify(mCm).setDataSaverEnabled(true);
+
+ assertTrue("Should be true since data saver is on and the uid is not allowlisted",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_ALLOW, TEST_UID, FIREWALL_RULE_ALLOW);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, TEST_UID, FIREWALL_RULE_ALLOW);
+ assertFalse("Should be false since data saver is on and the uid is allowlisted",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ // remove uid from allowlist and turn datasaver off again
+
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_ALLOW, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ mNMService.setDataSaverModeEnabled(false);
+ verify(mCm).setDataSaverEnabled(false);
+
+ assertFalse("Network should not be restricted when data saver is off",
+ mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
public void testFirewallChains() {
final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
// Dozable chain
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
index da8368f3cedf..2b6ddcb43f18 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
@@ -32,6 +32,9 @@ import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
+/**
+ * To run this test: `atest FlickerTestsIme1:CloseImeOnDismissPopupDialogTest`
+ */
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
index 2f3ec6301215..0344197c1425 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
@@ -33,8 +33,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME window closing to home transitions. To run this test: `atest
- * FlickerTests:CloseImeWindowToHomeTest`
+ * Test IME window closing to home transitions.
+ * To run this test: `atest FlickerTestsIme1:CloseImeOnGoHomeTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
index 8821b69cdb3e..fde1373b032b 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
@@ -42,7 +42,7 @@ import org.junit.runners.Parameterized
*
* More details on b/190352379
*
- * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToHomeTest`
+ * To run this test: `atest FlickerTestsIme1:CloseImeShownOnAppStartOnGoHomeTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
index d75eba68c7cc..dc5013519dbf 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
@@ -42,7 +42,7 @@ import org.junit.runners.Parameterized
*
* More details on b/190352379
*
- * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToAppTest`
+ * To run this test: `atest FlickerTestsIme1:CloseImeShownOnAppStartToAppOnPressBackTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
index 41d9e30a17ee..dc2bd1bc9996 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
@@ -34,8 +34,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME window closing back to app window transitions. To run this test: `atest
- * FlickerTests:CloseImeWindowToAppTest`
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTestsIme1:CloseImeToAppOnPressBackTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
index 0e7fb7975df8..05771e88fc83 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
@@ -40,7 +40,7 @@ import org.junit.runners.Parameterized
* Unlike {@link OpenImeWindowTest} testing IME window opening transitions, this test also verify
* there is no flickering when back to the simple activity without requesting IME to show.
*
- * To run this test: `atest FlickerTests:OpenImeWindowAndCloseTest`
+ * To run this test: `atest FlickerTestsIme1:CloseImeToHomeOnFinishActivityTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
index 47a7e1b65b2d..336fe6f991ca 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -36,8 +36,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME window shown on the app with fixing portrait orientation. To run this test: `atest
- * FlickerTests:OpenImeWindowToFixedPortraitAppTest`
+ * Test IME window shown on the app with fixing portrait orientation.
+ * To run this test: `atest FlickerTestsIme2:OpenImeWindowToFixedPortraitAppTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
index 48ec4d1fed2c..b8f11dcf8970 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
@@ -38,8 +38,9 @@ import org.junit.runners.Parameterized
/**
* Test IME window layer will become visible when switching from the fixed orientation activity
- * (e.g. Launcher activity). To run this test: `atest
- * FlickerTests:ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest`
+ * (e.g. Launcher activity).
+ * To run this test:
+ * `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
index 03f3a68a573f..34a708578396 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
@@ -33,7 +33,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME window opening transitions. To run this test: `atest FlickerTests:ReOpenImeWindowTest`
+ * Test IME window opening transitions.
+ * To run this test: `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppFromOverviewTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
index 7b62c8967628..7c72c3187a7f 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
@@ -35,8 +35,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME windows switching with 2-Buttons or gestural navigation. To run this test: `atest
- * FlickerTests:SwitchImeWindowsFromGestureNavTest`
+ * Test IME windows switching with 2-Buttons or gestural navigation.
+ * To run this test: `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
index 53bfb4ecf66f..fe5320cd1a46 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
@@ -36,7 +36,7 @@ import org.junit.runners.Parameterized
/**
* Launch an app that automatically displays the IME
*
- * To run this test: `atest FlickerTests:LaunchAppShowImeOnStartTest`
+ * To run this test: `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppTest`
*
* Actions:
* ```
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
index d22bdcf25529..92b6b934874f 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
@@ -35,8 +35,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME window closing on lock and opening on screen unlock. To run this test: `atest
- * FlickerTests:CloseImeWindowToHomeTest`
+ * Test IME window closing on lock and opening on screen unlock.
+ * To run this test: `atest FlickerTestsIme2:ShowImeOnUnlockScreenTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
index 12290af8fd46..9eaf998ed63f 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
@@ -31,7 +31,10 @@ import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
-/** Test IME window opening transitions. To run this test: `atest FlickerTests:OpenImeWindowTest` */
+/**
+ * Test IME window opening transitions.
+ * To run this test: `atest FlickerTestsIme2:ShowImeWhenFocusingOnInputFieldTest`
+ */
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
index 0948351ac65b..7186a2c48c4c 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
@@ -41,7 +41,7 @@ import org.junit.runners.Parameterized
/**
* Test IME snapshot mechanism won't apply when transitioning from non-IME focused dialog activity.
- * To run this test: `atest FlickerTests:LaunchAppShowImeAndDialogThemeAppTest`
+ * To run this test: `atest FlickerTestsIme2:ShowImeWhileDismissingThemedPopupDialogTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
index 7aa525fcccef..c96c760e2d7b 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
@@ -37,8 +37,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME window layer will be associated with the app task when going to the overview screen. To
- * run this test: `atest FlickerTests:OpenImeWindowToOverViewTest`
+ * Test IME window layer will be associated with the app task when going to the overview screen.
+ * To run this test: `atest FlickerTestsIme2:ShowImeWhileEnteringOverviewTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
index ffaeeadb1042..8c9ab9aadb8e 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
@@ -40,7 +40,7 @@ import org.junit.runners.Parameterized
*
* This test assumes the device doesn't have AOD enabled
*
- * To run this test: `atest FlickerTests:OpenAppFromLockNotificationCold`
+ * To run this test: `atest FlickerTestsNotification:OpenAppFromLockscreenNotificationColdTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
index 6e67e193ed8c..e595100a2cbe 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
@@ -40,7 +40,7 @@ import org.junit.runners.Parameterized
*
* This test assumes the device doesn't have AOD enabled
*
- * To run this test: `atest FlickerTests:OpenAppFromLockNotificationWarm`
+ * To run this test: `atest FlickerTestsNotification:OpenAppFromLockscreenNotificationWarmTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
index f1df8a68fb63..fbe1d34272c9 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
@@ -40,7 +40,8 @@ import org.junit.runners.Parameterized
*
* This test assumes the device doesn't have AOD enabled
*
- * To run this test: `atest FlickerTests:OpenAppFromLockNotificationWithLockOverlayApp`
+ * To run this test:
+ * `atest FlickerTestsNotification:OpenAppFromLockscreenNotificationWithOverlayAppTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
index b6d09d0bf3bb..c8ca644dde90 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
@@ -36,7 +36,7 @@ import org.junit.runners.Parameterized
/**
* Test cold launching an app from a notification.
*
- * To run this test: `atest FlickerTests:OpenAppFromNotificationCold`
+ * To run this test: `atest FlickerTestsNotification:OpenAppFromNotificationColdTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
index 1e607bfb2f49..c29e71ce4c79 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
@@ -47,7 +47,7 @@ import org.junit.runners.Parameterized
/**
* Test cold launching an app from a notification.
*
- * To run this test: `atest FlickerTests:OpenAppFromNotificationWarm`
+ * To run this test: `atest FlickerTestsNotification:OpenAppFromNotificationWarmTest`
*/
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
index 16785d1d9598..6b360b79c327 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
@@ -25,6 +25,7 @@ class AndroidHeuristicsFilter(
val aidlPolicy: FilterPolicyWithReason?,
val featureFlagsPolicy: FilterPolicyWithReason?,
val syspropsPolicy: FilterPolicyWithReason?,
+ val rFilePolicy: FilterPolicyWithReason?,
fallback: OutputFilter
) : DelegatingFilter(fallback) {
override fun getPolicyForClass(className: String): FilterPolicyWithReason {
@@ -37,6 +38,9 @@ class AndroidHeuristicsFilter(
if (syspropsPolicy != null && classes.isSyspropsClass(className)) {
return syspropsPolicy
}
+ if (rFilePolicy != null && classes.isRClass(className)) {
+ return rFilePolicy
+ }
return super.getPolicyForClass(className)
}
}
@@ -74,3 +78,10 @@ private fun ClassNodes.isSyspropsClass(className: String): Boolean {
return className.startsWith("android/sysprop/")
&& className.endsWith("Properties")
}
+
+/**
+ * @return if a given class "seems like" an R class or its nested classes.
+ */
+private fun ClassNodes.isRClass(className: String): Boolean {
+ return className.endsWith("/R") || className.contains("/R$")
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index 75b5fc8f77ea..c5acd81f1cf2 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -17,6 +17,7 @@ package com.android.hoststubgen.filters
import com.android.hoststubgen.ParseException
import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.toHumanReadableClassName
import com.android.hoststubgen.log
import com.android.hoststubgen.normalizeTextLine
import com.android.hoststubgen.whitespaceRegex
@@ -31,13 +32,17 @@ import java.util.Objects
* Print a class node as a "keep" policy.
*/
fun printAsTextPolicy(pw: PrintWriter, cn: ClassNode) {
- pw.printf("class %s\t%s\n", cn.name, "keep")
+ pw.printf("class %s %s\n", cn.name.toHumanReadableClassName(), "keep")
- for (f in cn.fields ?: emptyList()) {
- pw.printf(" field %s\t%s\n", f.name, "keep")
+ cn.fields?.let {
+ for (f in it.sortedWith(compareBy({ it.name }))) {
+ pw.printf(" field %s %s\n", f.name, "keep")
+ }
}
- for (m in cn.methods ?: emptyList()) {
- pw.printf(" method %s\t%s\t%s\n", m.name, m.desc, "keep")
+ cn.methods?.let {
+ for (m in it.sortedWith(compareBy({ it.name }, { it.desc }))) {
+ pw.printf(" method %s %s %s\n", m.name, m.desc, "keep")
+ }
}
}
@@ -66,6 +71,7 @@ fun createFilterFromTextPolicyFile(
var aidlPolicy: FilterPolicyWithReason? = null
var featureFlagsPolicy: FilterPolicyWithReason? = null
var syspropsPolicy: FilterPolicyWithReason? = null
+ var rFilePolicy: FilterPolicyWithReason? = null
try {
BufferedReader(FileReader(filename)).use { reader ->
@@ -162,6 +168,14 @@ fun createFilterFromTextPolicyFile(
syspropsPolicy = policy.withReason(
"$FILTER_REASON (special-class sysprops)")
}
+ SpecialClass.RFile -> {
+ if (rFilePolicy != null) {
+ throw ParseException(
+ "Policy for R file already defined")
+ }
+ rFilePolicy = policy.withReason(
+ "$FILTER_REASON (special-class R file)")
+ }
}
}
}
@@ -225,13 +239,9 @@ fun createFilterFromTextPolicyFile(
throw e.withSourceInfo(filename, lineNo)
}
- var ret: OutputFilter = imf
- if (aidlPolicy != null || featureFlagsPolicy != null || syspropsPolicy != null) {
- log.d("AndroidHeuristicsFilter enabled")
- ret = AndroidHeuristicsFilter(
- classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, imf)
- }
- return ret
+ // Wrap the in-memory-filter with AHF.
+ return AndroidHeuristicsFilter(
+ classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, imf)
}
}
@@ -240,6 +250,7 @@ private enum class SpecialClass {
Aidl,
FeatureFlags,
Sysprops,
+ RFile,
}
private fun resolveSpecialClass(className: String): SpecialClass {
@@ -250,6 +261,7 @@ private fun resolveSpecialClass(className: String): SpecialClass {
":aidl" -> return SpecialClass.Aidl
":feature_flags" -> return SpecialClass.FeatureFlags
":sysprops" -> return SpecialClass.Sysprops
+ ":r" -> return SpecialClass.RFile
}
throw ParseException("Invalid special class name \"$className\"")
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index fa8fe6cd384f..931f0c5fa793 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -322,6 +322,78 @@ NestMembers:
InnerClasses:
public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 3
+ public static int[] ARRAY;
+ descriptor: [I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+
+ public com.android.hoststubgen.test.tinyframework.R$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_1
+ x: newarray int
+ x: dup
+ x: iconst_0
+ x: iconst_1
+ x: iastore
+ x: putstatic #x // Field ARRAY:[I
+ x: return
+ LineNumberTable:
+}
+SourceFile: "R.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.R();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R;
+}
+SourceFile: "R.java"
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/R$Nested
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index c605f767f527..906a81cf45e3 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -122,6 +122,100 @@ RuntimeVisibleAnnotations:
NestMembers:
com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public static int[] ARRAY;
+ descriptor: [I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.R$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.R();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/R$Nested
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index 11d5939b7917..10bc91da2544 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -348,6 +348,108 @@ RuntimeVisibleAnnotations:
NestMembers:
com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public static int[] ARRAY;
+ descriptor: [I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.R$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_1
+ x: newarray int
+ x: dup
+ x: iconst_0
+ x: iconst_1
+ x: iastore
+ x: putstatic #x // Field ARRAY:[I
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.R();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/R$Nested
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index c605f767f527..906a81cf45e3 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -122,6 +122,100 @@ RuntimeVisibleAnnotations:
NestMembers:
com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public static int[] ARRAY;
+ descriptor: [I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.R$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.R();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/R$Nested
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 088bc80e11c5..fcf9a8c663ad 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -481,6 +481,136 @@ RuntimeVisibleAnnotations:
NestMembers:
com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public static int[] ARRAY;
+ descriptor: [I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.R$Nested();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: iconst_1
+ x: newarray int
+ x: dup
+ x: iconst_0
+ x: iconst_1
+ x: iastore
+ x: putstatic #x // Field ARRAY:[I
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+ Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/R
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.R();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/R
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/R;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/R$Nested
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
index d30208452a40..696b6d009dc2 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
@@ -19,6 +19,9 @@ class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy ~com
# Heuristics rule: Stub all the AIDL classes.
class :aidl stubclass
+# Heuristics rule: Stub all the R classes.
+class :r stubclass
+
# Default is "remove", so let's put all the base classes / interfaces in the stub first.
class com.android.hoststubgen.test.tinyframework.subclasstest.C1 stub
class com.android.hoststubgen.test.tinyframework.subclasstest.C2 stub
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java
new file mode 100644
index 000000000000..b1bedf4b6853
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+public class R {
+ public static class Nested {
+ public static int[] ARRAY = new int[] {1};
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index 762180dcf74b..37925e82bdb6 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
+import com.android.hoststubgen.test.tinyframework.R.Nested;
import com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.SubClass;
import org.junit.Rule;
@@ -328,4 +329,9 @@ public class TinyFrameworkClassTest {
assertThat(IPretendingAidl.Stub.addOne(1)).isEqualTo(2);
assertThat(IPretendingAidl.Stub.Proxy.addTwo(1)).isEqualTo(3);
}
+
+ @Test
+ public void testRFileHeuristics() {
+ assertThat(Nested.ARRAY.length).isEqualTo(1);
+ }
}