summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java6
-rw-r--r--cmds/idmap2/include/idmap2/Idmap.h4
-rw-r--r--core/api/current.txt1
-rw-r--r--core/java/android/app/ContextImpl.java13
-rw-r--r--core/java/android/companion/virtual/flags/flags.aconfig8
-rw-r--r--core/java/android/content/pm/PackageManager.java4
-rw-r--r--core/java/android/content/pm/flags.aconfig9
-rw-r--r--core/java/android/content/res/AssetManager.java22
-rw-r--r--core/java/android/os/PerfettoTrackEventExtra.java21
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java1
-rw-r--r--core/java/android/text/Layout.java46
-rw-r--r--core/java/android/util/apk/ApkSignatureVerifier.java8
-rw-r--r--core/java/android/view/NotificationHeaderView.java10
-rw-r--r--core/java/android/view/View.java17
-rw-r--r--core/java/android/view/ViewRootImpl.java82
-rw-r--r--core/java/android/view/ViewRootRectTracker.java21
-rw-r--r--core/java/android/window/flags/lse_desktop_experience.aconfig10
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig11
-rw-r--r--core/java/com/android/internal/app/MediaRouteControllerContentManager.java48
-rw-r--r--core/java/com/android/internal/app/MediaRouteControllerDialog.java37
-rw-r--r--core/java/com/android/internal/os/LongArrayMultiStateCounter.java4
-rw-r--r--core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java12
-rw-r--r--core/java/com/android/internal/os/PowerStats.java40
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java4
-rw-r--r--core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java2
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogCommandHandler.java4
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogConfigurationService.java6
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java27
-rw-r--r--core/jni/android_os_PerfettoTrackEventExtra.cpp166
-rw-r--r--core/jni/android_util_AssetManager.cpp10
-rw-r--r--core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp8
-rw-r--r--core/proto/OWNERS1
-rw-r--r--core/res/res/drawable-w192dp/loader_horizontal_watch.xml97
-rw-r--r--core/res/res/drawable-w204dp/loader_horizontal_watch.xml104
-rw-r--r--core/res/res/drawable-w216dp/loader_horizontal_watch.xml105
-rw-r--r--core/res/res/drawable-w228dp/loader_horizontal_watch.xml103
-rw-r--r--core/res/res/drawable-w240dp/loader_horizontal_watch.xml104
-rw-r--r--core/res/res/drawable/loader_horizontal_watch.xml103
-rw-r--r--core/res/res/drawable/progress_ring_watch.xml24
-rw-r--r--core/res/res/values-w192dp/dimens_watch.xml28
-rw-r--r--core/res/res/values-w216dp/dimens_watch.xml21
-rw-r--r--core/res/res/values-w228dp/dimens_watch.xml21
-rw-r--r--core/res/res/values-w240dp/dimens_material.xml4
-rw-r--r--core/res/res/values-watch/styles_device_defaults.xml3
-rw-r--r--core/res/res/values/attrs.xml8
-rw-r--r--core/res/res/values/dimens_watch.xml6
-rw-r--r--core/tests/coretests/src/android/os/PerfettoTraceTest.java85
-rw-r--r--core/tests/coretests/src/android/view/ViewRootImplTest.java115
-rw-r--r--core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java70
-rw-r--r--graphics/java/android/framework_graphics.aconfig8
-rw-r--r--graphics/java/android/graphics/HardwareRenderer.java14
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java121
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt51
-rw-r--r--libs/androidfw/AssetManager2.cpp82
-rw-r--r--libs/androidfw/Idmap.cpp42
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h10
-rw-r--r--libs/androidfw/include/androidfw/Idmap.h43
-rw-r--r--libs/hwui/FrameInfo.cpp2
-rw-r--r--libs/hwui/FrameInfo.h2
-rw-r--r--libs/hwui/FrameMetricsReporter.h6
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp10
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp6
-rw-r--r--libs/hwui/renderthread/CanvasContext.h4
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp12
-rw-r--r--libs/hwui/renderthread/RenderProxy.h4
-rw-r--r--media/java/android/media/MediaRoute2Info.java6
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java19
-rw-r--r--packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt1
-rw-r--r--packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt8
-rw-r--r--packages/SettingsLib/AndroidManifest.xml7
-rw-r--r--packages/SettingsLib/IllustrationPreference/AndroidManifest.xml2
-rw-r--r--packages/SettingsLib/IllustrationPreference/res/values/strings.xml27
-rw-r--r--packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java93
-rw-r--r--packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt4
-rw-r--r--packages/SettingsLib/aconfig/settingslib.aconfig24
-rw-r--r--packages/SettingsLib/res/layout/activity_create_new_user.xml (renamed from core/res/res/values-w204dp-round-watch/dimens_watch.xml)15
-rw-r--r--packages/SettingsLib/res/values/styles.xml9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java34
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java50
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeSchedules.java45
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java145
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java37
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java117
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java114
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java6
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java89
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt8
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt6
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt87
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/animation/ViewTransitionRegistryTest.kt71
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java32
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt33
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt54
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt15
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt16
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt22
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt29
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java12
-rw-r--r--packages/SystemUI/res/values/strings.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/ailabs/OWNERS1
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java125
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModel.kt78
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModel.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt226
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt305
-rw-r--r--packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLogger.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java9
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt18
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModelKosmos.kt29
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModelKosmos.kt29
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapterKosmos.kt8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelKosmos.kt8
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java5
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java40
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java5
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java1
-rw-r--r--services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java16
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java18
-rw-r--r--services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java3
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java13
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig11
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java3
-rw-r--r--services/core/java/com/android/server/input/InputGestureManager.java5
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS1
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java22
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java56
-rw-r--r--services/core/java/com/android/server/power/stats/format/ScreenPowerStatsLayout.java13
-rw-r--r--services/core/java/com/android/server/power/stats/format/SensorPowerStatsLayout.java18
-rw-r--r--services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java6
-rw-r--r--services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java14
-rw-r--r--services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java33
-rw-r--r--services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java28
-rw-r--r--services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java20
-rw-r--r--services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java20
-rw-r--r--services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java27
-rw-r--r--services/core/java/com/android/server/power/stats/processor/MultiStateStats.java5
-rw-r--r--services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java33
-rw-r--r--services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java17
-rw-r--r--services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java18
-rw-r--r--services/core/java/com/android/server/power/stats/processor/SensorPowerStatsProcessor.java19
-rw-r--r--services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java27
-rw-r--r--services/core/java/com/android/server/vibrator/VendorVibrationSession.java33
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java200
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java12
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java48
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java1
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java213
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java12
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java107
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java2
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java13
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java13
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobServiceContextTest.java19
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java4
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java5
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/processor/CpuPowerStatsProcessorTest.java10
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java2
-rw-r--r--services/tests/servicestests/Android.bp3
-rw-r--r--services/tests/servicestests/AndroidManifest.xml4
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayConstraintsTests.java210
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java8
-rw-r--r--startop/OWNERS1
-rw-r--r--tests/Input/Android.bp3
-rw-r--r--tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt12
-rw-r--r--tests/SoundTriggerTestApp/OWNERS1
-rw-r--r--tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java13
-rw-r--r--tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java9
-rw-r--r--tests/testables/src/android/testing/TestableLooper.java2
235 files changed, 3957 insertions, 2497 deletions
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 ebfda527001d..010006edc995 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -809,7 +809,11 @@ public final class JobServiceContext implements ServiceConnection {
if (!verifyCallerLocked(cb)) {
return;
}
-
+ if (mVerb != VERB_EXECUTING) {
+ // Any state other than executing means the
+ // job is in transient or stopped state
+ return;
+ }
executing = getRunningJobLocked();
}
if (executing != null && jobId == executing.getJobId()) {
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 1f15daf1ba47..335dc97bf964 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -178,8 +178,8 @@ class IdmapHeader {
};
struct IdmapConstraint {
- // Constraint type can be TYPE_DISPLAY_ID or TYP_DEVICE_ID, please refer
- // to ConstraintType in OverlayConstraint.java
+ // Constraint type can be android::kOverlayConstraintTypeDisplayId or
+ // android::kOverlayConstraintTypeDeviceId
uint32_t constraint_type;
uint32_t constraint_value;
diff --git a/core/api/current.txt b/core/api/current.txt
index f5dcf2de4c51..9ebb5068bf19 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -18112,6 +18112,7 @@ package android.graphics.drawable {
method public void setThickness(@Px int);
method public void setThicknessRatio(@FloatRange(from=0.0f, fromInclusive=false) float);
method public void setUseLevel(boolean);
+ field @FlaggedApi("com.android.graphics.flags.gradient_drawable_shape_rounded_cap") public static final int ARC = 4; // 0x4
field public static final int LINE = 2; // 0x2
field public static final int LINEAR_GRADIENT = 0; // 0x0
field public static final int OVAL = 1; // 0x1
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 0519695ff7fe..1a6e9b07067f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2976,6 +2976,13 @@ class ContextImpl extends Context {
if (display != null) {
updateDeviceIdIfChanged(display.getDisplayId());
}
+ updateResourceOverlayConstraints();
+ }
+
+ private void updateResourceOverlayConstraints() {
+ if (mResources != null) {
+ mResources.getAssets().setOverlayConstraints(getDisplayId(), getDeviceId());
+ }
}
@Override
@@ -2988,9 +2995,11 @@ class ContextImpl extends Context {
}
}
- return new ContextImpl(this, mMainThread, mPackageInfo, mParams,
+ final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
mToken, mUser, mFlags, mClassLoader, null, deviceId, true);
+ context.updateResourceOverlayConstraints();
+ return context;
}
@NonNull
@@ -3285,6 +3294,7 @@ class ContextImpl extends Context {
mDeviceId = updatedDeviceId;
mAttributionSource = createAttributionSourceWithDeviceId(mAttributionSource, mDeviceId);
notifyOnDeviceChangedListeners(updatedDeviceId);
+ updateResourceOverlayConstraints();
}
}
@@ -3700,6 +3710,7 @@ class ContextImpl extends Context {
mResourcesManager.setLocaleConfig(lc);
}
}
+ updateResourceOverlayConstraints();
}
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index ba1473cf5ed7..67ade79e1b94 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -135,3 +135,11 @@ flag {
description: "Show virtual devices in Settings"
bug: "338974320"
}
+
+flag {
+ name: "migrate_viewconfiguration_constants_to_resources"
+ namespace: "virtual_devices"
+ description: "Use resources instead of constants in ViewConfiguration"
+ is_fixed_read_only: true
+ bug: "370928384"
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f91b2474fdac..9e91f5944504 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2038,7 +2038,7 @@ public abstract class PackageManager {
public static final int INSTALL_SCENARIO_DEFAULT = 0;
/**
- * Installation scenario providing the fastest “install button to launch" experience possible.
+ * Installation scenario providing the fastest "install button to launch" experience possible.
*/
public static final int INSTALL_SCENARIO_FAST = 1;
@@ -3585,7 +3585,7 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device is
- * compatible with Android’s security model.
+ * compatible with Android's security model.
*
* <p>See sections 2 and 9 in the
* <a href="https://source.android.com/compatibility/android-cdd">Android CDD</a> for more
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index e4b8c90d381d..255a08cf170f 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -391,3 +391,12 @@ flag {
bug: "319137634"
is_fixed_read_only: true
}
+
+flag {
+ name: "always_load_past_certs_v4"
+ is_exported: true
+ namespace: "package_manager_service"
+ description: "Always read the corresponding v3/3.1 signature block for the current v4 to get the past rotated certificates, even when not verifying integrity."
+ bug: "378539511"
+ is_fixed_read_only: true
+}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 7cd2d31ac974..bcb50881d327 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -148,8 +148,8 @@ public final class AssetManager implements AutoCloseable {
* @hide
*/
public static class Builder {
- private ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>();
- private ArrayList<ResourcesLoader> mLoaders = new ArrayList<>();
+ private final ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>();
+ private final ArrayList<ResourcesLoader> mLoaders = new ArrayList<>();
private boolean mNoInit = false;
@@ -1625,6 +1625,23 @@ public final class AssetManager implements AutoCloseable {
}
/**
+ * Passes the display id and device id to AssetManager, to filter out overlays based on
+ * any {@link android.content.om.OverlayConstraint}.
+ *
+ * @hide
+ */
+ public void setOverlayConstraints(int displayId, int deviceId) {
+ if (!Flags.rroConstraints()) {
+ return;
+ }
+
+ synchronized (this) {
+ ensureValidLocked();
+ nativeSetOverlayConstraints(mObject, displayId, deviceId);
+ }
+ }
+
+ /**
* @hide
*/
@UnsupportedAppUsage
@@ -1717,6 +1734,7 @@ public final class AssetManager implements AutoCloseable {
int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender,
int majorVersion, boolean forceRefresh);
+ private static native void nativeSetOverlayConstraints(long ptr, int displayId, int deviceId);
private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
long ptr, boolean includeOverlays, boolean includeLoaders);
diff --git a/core/java/android/os/PerfettoTrackEventExtra.java b/core/java/android/os/PerfettoTrackEventExtra.java
index adb98aa25f8f..68442293c3a3 100644
--- a/core/java/android/os/PerfettoTrackEventExtra.java
+++ b/core/java/android/os/PerfettoTrackEventExtra.java
@@ -23,6 +23,8 @@ import dalvik.annotation.optimization.FastNative;
import libcore.util.NativeAllocationRegistry;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
@@ -50,6 +52,7 @@ public final class PerfettoTrackEventExtra {
private static final Supplier<FieldString> sFieldStringSupplier = FieldString::new;
private static final Supplier<FieldNested> sFieldNestedSupplier = FieldNested::new;
+ private final List<PerfettoPointer> mPendingPointers = new ArrayList<>();
private CounterInt64 mCounterInt64;
private CounterDouble mCounterDouble;
private Proto mProto;
@@ -592,7 +595,7 @@ public final class PerfettoTrackEventExtra {
checkContainer();
FieldInt64 field = mFieldInt64Cache.get(sFieldInt64Supplier);
field.setValue(id, val);
- mCurrentContainer.addField(field);
+ mExtra.addPerfettoPointer(mCurrentContainer, field);
return this;
}
@@ -601,7 +604,7 @@ public final class PerfettoTrackEventExtra {
checkContainer();
FieldDouble field = mFieldDoubleCache.get(sFieldDoubleSupplier);
field.setValue(id, val);
- mCurrentContainer.addField(field);
+ mExtra.addPerfettoPointer(mCurrentContainer, field);
return this;
}
@@ -610,7 +613,7 @@ public final class PerfettoTrackEventExtra {
checkContainer();
FieldString field = mFieldStringCache.get(sFieldStringSupplier);
field.setValue(id, val);
- mCurrentContainer.addField(field);
+ mExtra.addPerfettoPointer(mCurrentContainer, field);
return this;
}
@@ -635,7 +638,7 @@ public final class PerfettoTrackEventExtra {
checkContainer();
FieldNested field = mFieldNestedCache.get(sFieldNestedSupplier);
field.setId(id);
- mCurrentContainer.addField(field);
+ mExtra.addPerfettoPointer(mCurrentContainer, field);
return mBuilderCache.get(sBuilderSupplier).initInternal(this, field);
}
@@ -735,6 +738,15 @@ public final class PerfettoTrackEventExtra {
*/
public void addPerfettoPointer(PerfettoPointer extra) {
native_add_arg(mPtr, extra.getPtr());
+ mPendingPointers.add(extra);
+ }
+
+ /**
+ * Adds a pointer representing a track event parameter to the {@code container}.
+ */
+ public void addPerfettoPointer(FieldContainer container, PerfettoPointer extra) {
+ container.addField(extra);
+ mPendingPointers.add(extra);
}
/**
@@ -742,6 +754,7 @@ public final class PerfettoTrackEventExtra {
*/
public void reset() {
native_clear_args(mPtr);
+ mPendingPointers.clear();
}
private CounterInt64 getCounterInt64() {
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 6f94c1b2d274..4cbd5beb3a8c 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -3131,6 +3131,7 @@ public class ZenModeConfig implements Parcelable {
* @return null if DND is off or describeForeverCondition is false and
* DND is on forever (until turned off)
*/
+ // TODO: b/368247671 - Delete when inlining MODES_UI
public static String getDescription(Context context, boolean zenOn, ZenModeConfig config,
boolean describeForeverCondition) {
if (!zenOn || config == null) {
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 2fa56137a8a0..b273a7f7c271 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1071,13 +1071,27 @@ public abstract class Layout {
var newBackground = determineContrastingBackgroundColor(index);
var hasBgColorChanged = newBackground != bgPaint.getColor();
- if (lineNum != mLastLineNum || hasBgColorChanged) {
- // Skip processing if the character is a space or a tap to avoid
- // rendering an abrupt, empty rectangle.
- if (Character.isWhitespace(mText.charAt(index))) {
- return;
- }
+ // Skip processing if the character is a space or a tap to avoid
+ // rendering an abrupt, empty rectangle.
+ if (TextLine.isLineEndSpace(mText.charAt(index))) {
+ return;
+ }
+ // To avoid highlighting emoji sequences, we use Extended_Pictgraphs as a
+ // heuristic. Highlighting is skipped based on code points, not glyph type
+ // (text vs. color), so emojis with default text presentation are
+ // intentionally not highlighted (numeric representation with emoji
+ // presentation are manually excluded). Although we process ZWJ and
+ // variation selectors within emoji sequences, they should not affect
+ // highlighting due to their zero-width nature.
+ var codePoint = Character.codePointAt(mText, index);
+ var isEmoji = Character.isEmojiComponent(codePoint)
+ || Character.isExtendedPictographic(codePoint);
+ if (isEmoji && !isStandardNumber(index)) {
+ return;
+ }
+
+ if (lineNum != mLastLineNum || hasBgColorChanged) {
// Draw what we have so far, then reset the rect and update its color
drawRect();
mLineBackground.set(left, top, right, bottom);
@@ -1096,6 +1110,16 @@ public abstract class Layout {
drawRect();
}
+ private boolean isStandardNumber(int index) {
+ var codePoint = Character.codePointAt(mText, index);
+ var isNumberSignOrAsterisk = (codePoint >= '0' && codePoint <= '9')
+ || codePoint == '#' || codePoint == '*';
+ var isColoredGlyph = index + 1 < mText.length()
+ && Character.codePointAt(mText, index + 1) == 0xFE0F;
+
+ return isNumberSignOrAsterisk && !isColoredGlyph;
+ }
+
private void drawRect() {
if (!mLineBackground.isEmpty()) {
mLineBackground.inset(-padding, -padding);
@@ -4626,6 +4650,16 @@ public abstract class Layout {
* Callback for {@link #forEachCharacterBounds(int, int, int, int, CharacterBoundsListener)}
*/
private interface CharacterBoundsListener {
+ /**
+ * Called for each character with its bounds.
+ *
+ * @param index the index of the character
+ * @param lineNum the line number of the character
+ * @param left the left edge of the character
+ * @param top the top edge of the character
+ * @param right the right edge of the character
+ * @param bottom the bottom edge of the character
+ */
void onCharacterBounds(int index, int lineNum, float left, float top, float right,
float bottom);
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index a4c3ed96f2ce..5910434dc692 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -260,9 +260,11 @@ public class ApkSignatureVerifier {
Certificate[][] nonstreamingCerts = null;
int v3BlockId = APK_SIGNATURE_SCHEME_DEFAULT;
- // If V4 contains additional signing blocks then we need to always run v2/v3 verifier
- // to figure out which block they use.
- if (verifyFull || signingInfos.signingInfoBlocks.length > 0) {
+ // We need to always run v2/v3 verifier to figure out which block they use so we can
+ // return the past signers as well as the current one - the rotation chain is important
+ // for many callers who verify the signature origin as well as the apk integrity.
+ if (android.content.pm.Flags.alwaysLoadPastCertsV4()
+ || verifyFull || signingInfos.signingInfoBlocks.length > 0) {
try {
// v4 is an add-on and requires v2 or v3 signature to validate against its
// certificate and digest
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index df680c054f56..fe868e1c43be 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -223,8 +223,14 @@ public class NotificationHeaderView extends RelativeLayout {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (notificationsRedesignTemplates()) {
- mTopLineTranslation = measureCenterTranslation(mTopLineView);
- mExpandButtonTranslation = measureCenterTranslation(mExpandButton);
+ // TODO: b/378660052 - These should never be null in practice, consider using
+ // requireViewById() in the onFinishInflate.
+ if (mTopLineView != null) {
+ mTopLineTranslation = measureCenterTranslation(mTopLineView);
+ }
+ if (mExpandButton != null) {
+ mExpandButtonTranslation = measureCenterTranslation(mExpandButton);
+ }
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0866e0d832b1..c048d7987515 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -66,6 +66,7 @@ import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFI
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION;
import static com.android.window.flags.Flags.FLAG_DELEGATE_UNHANDLED_DRAGS;
import static com.android.window.flags.Flags.FLAG_SUPPORTS_DRAG_ASSISTANT_TO_MULTIWINDOW;
+import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs;
import static java.lang.Math.max;
@@ -247,6 +248,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
@@ -12888,15 +12890,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (rects.isEmpty() && mListenerInfo == null) return;
final ListenerInfo info = getListenerInfo();
+ final boolean rectsChanged = !reduceChangedExclusionRectsMsgs()
+ || !Objects.equals(info.mSystemGestureExclusionRects, rects);
if (info.mSystemGestureExclusionRects != null) {
- info.mSystemGestureExclusionRects.clear();
- info.mSystemGestureExclusionRects.addAll(rects);
+ if (rectsChanged) {
+ info.mSystemGestureExclusionRects.clear();
+ info.mSystemGestureExclusionRects.addAll(rects);
+ }
} else {
info.mSystemGestureExclusionRects = new ArrayList<>(rects);
}
-
- updatePositionUpdateListener();
- postUpdate(this::updateSystemGestureExclusionRects);
+ if (rectsChanged) {
+ updatePositionUpdateListener();
+ postUpdate(this::updateSystemGestureExclusionRects);
+ }
}
private void updatePositionUpdateListener() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cfdcc10a20f4..9498407fb33b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -136,6 +136,7 @@ import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
import static com.android.window.flags.Flags.enableWindowContextResourcesUpdateOnConfigChange;
import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi;
+import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import android.Manifest;
@@ -152,8 +153,6 @@ import android.annotation.UiContext;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ResourcesManager;
-import android.app.UiModeManager;
-import android.app.UiModeManager.ForceInvertStateChangeListener;
import android.app.WindowConfiguration;
import android.app.compat.CompatChanges;
import android.app.servertransaction.WindowStateTransactionItem;
@@ -169,6 +168,7 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.database.ContentObserver;
import android.graphics.BLASTBufferQueue;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -214,6 +214,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.Vibrator;
+import android.provider.Settings;
import android.sysprop.DisplayProperties;
import android.sysprop.ViewProperties;
import android.text.TextUtils;
@@ -469,8 +470,10 @@ public final class ViewRootImpl implements ViewParent,
private CompatOnBackInvokedCallback mCompatOnBackInvokedCallback;
@Nullable
- private ForceInvertStateChangeListener mForceInvertStateChangeListener;
+ private ContentObserver mForceInvertObserver;
+ private static final int INVALID_VALUE = Integer.MIN_VALUE;
+ private int mForceInvertEnabled = INVALID_VALUE;
/**
* Callback for notifying about global configuration changes.
*/
@@ -552,8 +555,6 @@ public final class ViewRootImpl implements ViewParent,
@UiContext
public final Context mContext;
- private UiModeManager mUiModeManager;
-
@UnsupportedAppUsage
final IWindowSession mWindowSession;
@NonNull Display mDisplay;
@@ -1255,7 +1256,6 @@ public final class ViewRootImpl implements ViewParent,
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
WindowLayout windowLayout) {
mContext = context;
- mUiModeManager = context.getSystemService(UiModeManager.class);
mWindowSession = session;
mWindowLayout = windowLayout;
mDisplay = display;
@@ -1804,6 +1804,23 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ private boolean isForceInvertEnabled() {
+ if (mForceInvertEnabled == INVALID_VALUE) {
+ reloadForceInvertEnabled();
+ }
+ return mForceInvertEnabled == 1;
+ }
+
+ private void reloadForceInvertEnabled() {
+ if (forceInvertColor()) {
+ mForceInvertEnabled = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
+ /* def= */ 0,
+ UserHandle.myUserId());
+ }
+ }
+
/**
* Register any kind of listeners if setView was success.
*/
@@ -1835,11 +1852,21 @@ public final class ViewRootImpl implements ViewParent,
mBasePackageName);
if (forceInvertColor()) {
- if (mForceInvertStateChangeListener == null) {
- mForceInvertStateChangeListener =
- forceInvertState -> updateForceDarkMode();
- mUiModeManager.addForceInvertStateChangeListener(mExecutor,
- mForceInvertStateChangeListener);
+ if (mForceInvertObserver == null) {
+ mForceInvertObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ reloadForceInvertEnabled();
+ updateForceDarkMode();
+ }
+ };
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED
+ ),
+ false,
+ mForceInvertObserver,
+ UserHandle.myUserId());
}
}
}
@@ -1857,10 +1884,9 @@ public final class ViewRootImpl implements ViewParent,
.unregisterDisplayListener(mDisplayListener);
if (forceInvertColor()) {
- if (mForceInvertStateChangeListener != null) {
- mUiModeManager.removeForceInvertStateChangeListener(
- mForceInvertStateChangeListener);
- mForceInvertStateChangeListener = null;
+ if (mForceInvertObserver != null) {
+ mContext.getContentResolver().unregisterContentObserver(mForceInvertObserver);
+ mForceInvertObserver = null;
}
}
@@ -2047,25 +2073,21 @@ public final class ViewRootImpl implements ViewParent,
return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
}
- /**
- * Determines the type of force dark to apply, considering force inversion, system night mode,
- * and app-specific settings (including developer opt-outs).
- *
- * @return A {@link ForceDarkType.ForceDarkTypeDef} constant indicating the force dark type.
- */
+ /** Returns true if force dark should be enabled according to various settings */
@VisibleForTesting
public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() {
if (forceInvertColor()) {
// Force invert ignores all developer opt-outs.
// We also ignore dark theme, since the app developer can override the user's preference
- // for dark mode in configuration.uiMode. Instead, we assume that both force invert and
- // the system's dark theme are enabled.
- if (mUiModeManager.getForceInvertState() == UiModeManager.FORCE_INVERT_TYPE_DARK) {
+ // for dark mode in configuration.uiMode. Instead, we assume that the force invert
+ // setting will be enabled at the same time dark theme is in the Settings app.
+ if (isForceInvertEnabled()) {
return ForceDarkType.FORCE_INVERT_COLOR_DARK;
}
}
boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
+
if (useAutoDark) {
boolean forceDarkAllowedDefault =
SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
@@ -6053,8 +6075,12 @@ public final class ViewRootImpl implements ViewParent,
}
void updateSystemGestureExclusionRectsForView(View view) {
+ boolean msgInQueue = reduceChangedExclusionRectsMsgs()
+ && mGestureExclusionTracker.isWaitingForComputeChanges();
mGestureExclusionTracker.updateRectsForView(view);
- mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
+ if (!msgInQueue) {
+ mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
+ }
}
void systemGestureExclusionChanged() {
@@ -6098,8 +6124,12 @@ public final class ViewRootImpl implements ViewParent,
* the root's view hierarchy.
*/
public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) {
+ boolean msgInQueue = reduceChangedExclusionRectsMsgs()
+ && mGestureExclusionTracker.isWaitingForComputeChanges();
mGestureExclusionTracker.setRootRects(rects);
- mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
+ if (!msgInQueue) {
+ mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
+ }
}
/**
diff --git a/core/java/android/view/ViewRootRectTracker.java b/core/java/android/view/ViewRootRectTracker.java
index 152729b8d1d8..0bef3255f1dc 100644
--- a/core/java/android/view/ViewRootRectTracker.java
+++ b/core/java/android/view/ViewRootRectTracker.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.ref.WeakReference;
@@ -32,8 +33,10 @@ import java.util.function.Function;
/**
* Abstract class to track a collection of rects reported by the views under the same
* {@link ViewRootImpl}.
+ * @hide
*/
-class ViewRootRectTracker {
+@VisibleForTesting
+public class ViewRootRectTracker {
private final Function<View, List<Rect>> mRectCollector;
private boolean mViewsChanged = false;
private boolean mRootRectsChanged = false;
@@ -41,11 +44,18 @@ class ViewRootRectTracker {
private List<ViewInfo> mViewInfos = new ArrayList<>();
private List<Rect> mRects = Collections.emptyList();
+ // Keeps track of whether updateRectsForView has been called but there was no subsequent call
+ // on computeChanges yet. Since updateRectsForView is called when sending a message and
+ // computeChanges when it is received, this tracks whether such message is in the queue already
+ private boolean mWaitingForComputeChanges = false;
+
/**
* @param rectCollector given a view returns a list of the rects of interest for this
* ViewRootRectTracker
+ * @hide
*/
- ViewRootRectTracker(Function<View, List<Rect>> rectCollector) {
+ @VisibleForTesting
+ public ViewRootRectTracker(Function<View, List<Rect>> rectCollector) {
mRectCollector = rectCollector;
}
@@ -70,6 +80,7 @@ class ViewRootRectTracker {
mViewInfos.add(new ViewInfo(view));
mViewsChanged = true;
}
+ mWaitingForComputeChanges = true;
}
/**
@@ -92,6 +103,7 @@ class ViewRootRectTracker {
* @return {@code true} if there were changes, {@code false} otherwise.
*/
public boolean computeChanges() {
+ mWaitingForComputeChanges = false;
boolean changed = mRootRectsChanged;
final Iterator<ViewInfo> i = mViewInfos.iterator();
final List<Rect> rects = new ArrayList<>(mRootRects);
@@ -121,6 +133,10 @@ class ViewRootRectTracker {
return false;
}
+ public boolean isWaitingForComputeChanges() {
+ return mWaitingForComputeChanges;
+ }
+
/**
* Returns a List of all Rects from all visible Views in the global (root) coordinate system.
* This list is only updated when calling {@link #computeChanges()} or
@@ -140,6 +156,7 @@ class ViewRootRectTracker {
Preconditions.checkNotNull(rects, "rects must not be null");
mRootRects = rects;
mRootRectsChanged = true;
+ mWaitingForComputeChanges = true;
}
@NonNull
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 891c5e382a58..3e3b8e100d6d 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -196,6 +196,16 @@ flag {
}
flag {
+ name: "enable_camera_compat_for_desktop_windowing_opt_out"
+ namespace: "lse_desktop_experience"
+ description: "Whether to allow developers to opt-out of Camera Compat treatment to fixed-orientation apps in desktop windowing mode"
+ bug: "328616176"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_task_stack_observer_in_shell"
namespace: "lse_desktop_experience"
description: "Introduces a new observer in shell to track the task stack."
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 60f2c811dd1f..a4d128fa3caf 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -428,6 +428,17 @@ flag {
}
flag {
+ name: "reduce_changed_exclusion_rects_msgs"
+ namespace: "windowing_frontend"
+ description: "Don't send MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED when there is no change"
+ bug: "388231176"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "keep_app_window_hide_while_locked"
namespace: "windowing_frontend"
description: "Do not let app window visible while device is locked"
diff --git a/core/java/com/android/internal/app/MediaRouteControllerContentManager.java b/core/java/com/android/internal/app/MediaRouteControllerContentManager.java
index 83ae7edd796b..dc4caa3d35d7 100644
--- a/core/java/com/android/internal/app/MediaRouteControllerContentManager.java
+++ b/core/java/com/android/internal/app/MediaRouteControllerContentManager.java
@@ -28,19 +28,40 @@ import com.android.internal.R;
* This class manages the content display within the media route controller UI.
*/
public class MediaRouteControllerContentManager {
+ /**
+ * A delegate interface that a MediaRouteController UI should implement. It allows the content
+ * manager to inform the UI of any UI changes that need to be made in response to content
+ * updates.
+ */
+ public interface Delegate {
+ /**
+ * Updates the title of the cast device
+ */
+ void setCastDeviceTitle(CharSequence title);
+
+ /**
+ * Dismiss the UI to transition to a different workflow.
+ */
+ void dismissView();
+ }
+
+ private final Delegate mDelegate;
+
// Time to wait before updating the volume when the user lets go of the seek bar
// to allow the route provider time to propagate the change and publish a new
// route descriptor.
private static final int VOLUME_UPDATE_DELAY_MILLIS = 250;
+ private final MediaRouter mRouter;
private final MediaRouter.RouteInfo mRoute;
private LinearLayout mVolumeLayout;
private SeekBar mVolumeSlider;
private boolean mVolumeSliderTouched;
- public MediaRouteControllerContentManager(Context context) {
- MediaRouter mRouter = context.getSystemService(MediaRouter.class);
+ public MediaRouteControllerContentManager(Context context, Delegate delegate) {
+ mDelegate = delegate;
+ mRouter = context.getSystemService(MediaRouter.class);
mRoute = mRouter.getSelectedRoute();
}
@@ -49,6 +70,7 @@ public class MediaRouteControllerContentManager {
* given container view.
*/
public void bindViews(View containerView) {
+ mDelegate.setCastDeviceTitle(mRoute.getName());
mVolumeLayout = containerView.findViewById(R.id.media_route_volume_layout);
mVolumeSlider = containerView.findViewById(R.id.media_route_volume_slider);
mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@@ -89,6 +111,14 @@ public class MediaRouteControllerContentManager {
}
/**
+ * Updates all the views to reflect new states.
+ */
+ public void update() {
+ mDelegate.setCastDeviceTitle(mRoute.getName());
+ updateVolume();
+ }
+
+ /**
* Updates the volume layout and slider.
*/
public void updateVolume() {
@@ -103,6 +133,20 @@ public class MediaRouteControllerContentManager {
}
}
+ /**
+ * Callback function to triggered after the disconnect button is clicked.
+ */
+ public void onDisconnectButtonClick() {
+ if (mRoute.isSelected()) {
+ if (mRoute.isBluetooth()) {
+ mRouter.getDefaultRoute().select();
+ } else {
+ mRouter.getFallbackRoute().select();
+ }
+ }
+ mDelegate.dismissView();
+ }
+
private boolean isVolumeControlAvailable() {
return mRoute.getVolumeHandling() == MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
}
diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialog.java b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
index c79f3c7bf76f..45a4a13667a4 100644
--- a/core/java/com/android/internal/app/MediaRouteControllerDialog.java
+++ b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
@@ -46,7 +46,10 @@ import com.android.internal.R;
*
* TODO: Move this back into the API, as in the support library media router.
*/
-public class MediaRouteControllerDialog extends AlertDialog {
+public class MediaRouteControllerDialog extends AlertDialog implements
+ MediaRouteControllerContentManager.Delegate {
+ // TODO(b/360050020): Eventually these 3 variables should be in the content manager instead of
+ // here. So these should be removed when the migration is completed.
private final MediaRouter mRouter;
private final MediaRouterCallback mCallback;
private final MediaRouter.RouteInfo mRoute;
@@ -63,7 +66,7 @@ public class MediaRouteControllerDialog extends AlertDialog {
public MediaRouteControllerDialog(Context context, int theme) {
super(context, theme);
- mContentManager = new MediaRouteControllerContentManager(context);
+ mContentManager = new MediaRouteControllerContentManager(context, this);
mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mCallback = new MediaRouterCallback();
mRoute = mRouter.getSelectedRoute();
@@ -71,24 +74,13 @@ public class MediaRouteControllerDialog extends AlertDialog {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTitle(mRoute.getName());
Resources res = getContext().getResources();
setButton(BUTTON_NEGATIVE, res.getString(R.string.media_route_controller_disconnect),
- (dialogInterface, id) -> {
- if (mRoute.isSelected()) {
- if (mRoute.isBluetooth()) {
- mRouter.getDefaultRoute().select();
- } else {
- mRouter.getFallbackRoute().select();
- }
- }
- dismiss();
- });
+ (dialogInterface, id) -> mContentManager.onDisconnectButtonClick());
View customView = getLayoutInflater().inflate(R.layout.media_route_controller_dialog, null);
setView(customView, 0, 0, 0, 0);
- super.onCreate(savedInstanceState);
-
mContentManager.bindViews(customView);
+ super.onCreate(savedInstanceState);
View customPanelView = getWindow().findViewById(R.id.customPanel);
if (customPanelView != null) {
@@ -135,13 +127,22 @@ public class MediaRouteControllerDialog extends AlertDialog {
return super.onKeyUp(keyCode, event);
}
+ @Override
+ public void setCastDeviceTitle(CharSequence title) {
+ setTitle(title);
+ }
+
+ @Override
+ public void dismissView() {
+ dismiss();
+ }
+
private void update() {
if (!mRoute.isSelected() || mRoute.isDefault()) {
- dismiss();
+ dismissView();
}
- setTitle(mRoute.getName());
- mContentManager.updateVolume();
+ mContentManager.update();
Drawable icon = getIconDrawable();
if (icon != mCurrentIconDrawable) {
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index 2931bd2c83dd..fe616e085488 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
@@ -155,8 +156,9 @@ public final class LongArrayMultiStateCounter implements Parcelable {
/**
* Adds the supplied values to the current accumulated values in the counter.
+ * Null `values` parameter is interpreted as an array of zeros.
*/
- public void incrementValues(long[] values, long timestampMs) {
+ public void incrementValues(@Nullable long[] values, long timestampMs) {
native_incrementValues(mNativeObject, values, timestampMs);
}
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java
index 7030d8e84b70..4f5f37d0640e 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
+import android.annotation.Nullable;
import android.os.BadParcelableException;
import android.os.Parcel;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
@@ -147,10 +148,12 @@ class LongArrayMultiStateCounter_ravenwood {
mLastUpdateTimestampMs = timestampMs;
}
- public void incrementValues(long[] delta, long timestampMs) {
+ public void incrementValues(@Nullable long[] delta, long timestampMs) {
long[] values = Arrays.copyOf(mValues, mValues.length);
- for (int i = 0; i < mArrayLength; i++) {
- values[i] += delta[i];
+ if (delta != null) {
+ for (int i = 0; i < mArrayLength; i++) {
+ values[i] += delta[i];
+ }
}
updateValue(values, timestampMs);
}
@@ -304,7 +307,8 @@ class LongArrayMultiStateCounter_ravenwood {
getInstance(targetInstanceId).copyStatesFrom(getInstance(sourceInstanceId));
}
- public static void native_incrementValues(long instanceId, long[] delta, long timestampMs) {
+ public static void native_incrementValues(long instanceId, @Nullable long[] delta,
+ long timestampMs) {
getInstance(instanceId).incrementValues(delta, timestampMs);
}
diff --git a/core/java/com/android/internal/os/PowerStats.java b/core/java/com/android/internal/os/PowerStats.java
index aafef6c8b5fd..6c69e2c623ad 100644
--- a/core/java/com/android/internal/os/PowerStats.java
+++ b/core/java/com/android/internal/os/PowerStats.java
@@ -128,6 +128,7 @@ public final class PowerStats {
* Extra parameters specific to the power component, e.g. the availability of power
* monitors.
*/
+ @NonNull
public final PersistableBundle extras;
private PowerStatsFormatter mDeviceStatsFormatter;
@@ -269,20 +270,41 @@ public final class PowerStats {
stateStatsArrayLength, uidStatsArrayLength, extras);
}
+ @SuppressWarnings("deprecation")
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Descriptor)) return false;
Descriptor that = (Descriptor) o;
- return powerComponentId == that.powerComponentId
- && statsArrayLength == that.statsArrayLength
- && stateLabels.contentEquals(that.stateLabels)
- && stateStatsArrayLength == that.stateStatsArrayLength
- && uidStatsArrayLength == that.uidStatsArrayLength
- && Objects.equals(name, that.name)
- && extras.size() == that.extras.size() // Unparcel the Parcel if not yet
- && Bundle.kindofEquals(extras,
- that.extras); // Since the Parcel is now unparceled, do a deep comparison
+ if (powerComponentId != that.powerComponentId
+ || statsArrayLength != that.statsArrayLength
+ || !stateLabels.contentEquals(that.stateLabels)
+ || stateStatsArrayLength != that.stateStatsArrayLength
+ || uidStatsArrayLength != that.uidStatsArrayLength
+ || !Objects.equals(name, that.name)) {
+ return false;
+ }
+
+ // Getting the size has the side-effect of unparceling the Bundle if not yet
+ if (extras.size() != that.extras.size()) {
+ return false;
+ }
+
+ if (Bundle.kindofEquals(extras, that.extras)) {
+ return true;
+ }
+
+ // Since `kindofEquals` does not deep-compare arrays, we do that separately, albeit at
+ // the expense of creating an iterator and using a deprecated API, `bundle.get`.
+ // There is no performance concern, because the situation where PowerStatsDescriptors
+ // are changed in an incompatible way are exceedingly rare, occurring at most
+ // once per power component after a system upgrade.
+ for (String key : extras.keySet()) {
+ if (!Objects.deepEquals(extras.get(key), that.extras.get(key))) {
+ return false;
+ }
+ }
+ return true;
}
/**
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
index 7ee22f30ace0..69c04807c604 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
@@ -157,7 +157,7 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(this.name);
+ sForInternedString.parcel(this.name, dest, flags);
dest.writeInt(this.getIcon());
dest.writeInt(this.getLabelRes());
dest.writeCharSequence(this.getNonLocalizedLabel());
@@ -175,7 +175,7 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable
// We use the boot classloader for all classes that we load.
final ClassLoader boot = Object.class.getClassLoader();
//noinspection ConstantConditions
- this.name = in.readString();
+ this.name = sForInternedString.unparcel(in);
this.icon = in.readInt();
this.labelRes = in.readInt();
this.nonLocalizedLabel = in.readCharSequence();
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index 93be3b02a12a..2d989943800e 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -322,7 +322,7 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
PrintWriter pw = shell.getOutPrintWriter();
if (android.tracing.Flags.clientSideProtoLogging()) {
- pw.println("Command deprecated. Please use 'cmd protolog' instead.");
+ pw.println("Command deprecated. Please use 'cmd protolog_configuration' instead.");
return -1;
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java b/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java
index 82d8d3431a9d..6d4a40899a65 100644
--- a/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java
+++ b/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java
@@ -145,11 +145,11 @@ public class ProtoLogCommandHandler extends ShellCommand {
switch (cmd) {
case "enable" -> {
- mProtoLogConfigurationService.enableProtoLogToLogcat(processGroups());
+ mProtoLogConfigurationService.enableProtoLogToLogcat(pw, processGroups());
return 0;
}
case "disable" -> {
- mProtoLogConfigurationService.disableProtoLogToLogcat(processGroups());
+ mProtoLogConfigurationService.disableProtoLogToLogcat(pw, processGroups());
return 0;
}
default -> {
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
index d65aaae7deaa..a19690bbd0e4 100644
--- a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
@@ -18,6 +18,8 @@ package com.android.internal.protolog;
import android.annotation.NonNull;
+import java.io.PrintWriter;
+
public interface ProtoLogConfigurationService extends IProtoLogConfigurationService {
/**
* Get the list of groups clients have registered to the protolog service.
@@ -37,11 +39,11 @@ public interface ProtoLogConfigurationService extends IProtoLogConfigurationServ
* Enable logging target groups to logcat.
* @param groups we want to enable logging them to logcat for.
*/
- void enableProtoLogToLogcat(@NonNull String... groups);
+ void enableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups);
/**
* Disable logging target groups to logcat.
* @param groups we want to disable from being logged to logcat.
*/
- void disableProtoLogToLogcat(@NonNull String... groups);
+ void disableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups);
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
index f83359dddfcc..ac1022ff1e0f 100644
--- a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
@@ -44,6 +44,7 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -183,8 +184,8 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
* @param groups we want to enable logging them to logcat for.
*/
@Override
- public void enableProtoLogToLogcat(@NonNull String... groups) {
- toggleProtoLogToLogcat(true, groups);
+ public void enableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups) {
+ toggleProtoLogToLogcat(pw, true, groups);
}
/**
@@ -192,8 +193,8 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
* @param groups we want to disable from being logged to logcat.
*/
@Override
- public void disableProtoLogToLogcat(@NonNull String... groups) {
- toggleProtoLogToLogcat(false, groups);
+ public void disableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups) {
+ toggleProtoLogToLogcat(pw, false, groups);
}
/**
@@ -249,7 +250,9 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
}
}
- private void toggleProtoLogToLogcat(boolean enabled, @NonNull String[] groups) {
+ private void toggleProtoLogToLogcat(
+ @NonNull PrintWriter pw, boolean enabled, @NonNull String[] groups
+ ) {
final var clientToGroups = new HashMap<IProtoLogClient, Set<String>>();
for (String group : groups) {
@@ -257,8 +260,10 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
if (clients == null) {
// No clients associated to this group
- Log.w(LOG_TAG, "Attempting to toggle log to logcat for group " + group
- + " with no registered clients.");
+ var warning = "Attempting to toggle log to logcat for group " + group
+ + " with no registered clients. This is a no-op.";
+ Log.w(LOG_TAG, warning);
+ pw.println("WARNING: " + warning);
continue;
}
@@ -270,8 +275,14 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
for (IProtoLogClient client : clientToGroups.keySet()) {
try {
- client.toggleLogcat(enabled, clientToGroups.get(client).toArray(new String[0]));
+ final var clientGroups = clientToGroups.get(client).toArray(new String[0]);
+ pw.println("Toggling logcat logging for client " + client.toString()
+ + " to " + enabled + " for groups: ["
+ + String.join(", ", clientGroups) + "]");
+ client.toggleLogcat(enabled, clientGroups);
+ pw.println("- Done");
} catch (RemoteException e) {
+ pw.println("- Failed");
throw new RuntimeException(
"Failed to toggle logcat status for groups on client", e);
}
diff --git a/core/jni/android_os_PerfettoTrackEventExtra.cpp b/core/jni/android_os_PerfettoTrackEventExtra.cpp
index b8bdc8c29199..18f05cabd12d 100644
--- a/core/jni/android_os_PerfettoTrackEventExtra.cpp
+++ b/core/jni/android_os_PerfettoTrackEventExtra.cpp
@@ -23,7 +23,8 @@
#include <nativehelper/utils.h>
#include <tracing_sdk.h>
-static constexpr ssize_t kMaxStrLen = 4096;
+#include <list>
+
namespace android {
template <typename T>
inline static T* toPointer(jlong ptr) {
@@ -35,24 +36,145 @@ inline static jlong toJLong(T* ptr) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr));
}
+/**
+ * @brief A thread-safe utility class for converting Java UTF-16 strings to ASCII in JNI
+ * environment.
+ *
+ * StringBuffer provides efficient conversion of Java strings to ASCII with optimized memory
+ * handling.
+ * It uses a two-tiered buffering strategy:
+ * 1. A fast path using pre-allocated thread-local buffers for strings up to 128 characters
+ * 2. A fallback path using dynamic allocation for longer strings
+ *
+ * Non-ASCII characters (>255) are replaced with '?' during conversion. The class maintains
+ * thread safety through thread-local storage and provides zero-copy string views for optimal
+ * performance.
+ *
+ * Memory Management:
+ * - Uses fixed-size thread-local buffers for both UTF-16 and ASCII characters
+ * - Overflow strings are stored in a thread-local list to maintain valid string views
+ * - Avoids unnecessary allocations in the common case of small strings
+ *
+ * Usage example:
+ * @code
+ * JNIEnv* env = ...;
+ * jstring java_string = ...;
+ * std::string_view ascii = StringBuffer::utf16_to_ascii(env, java_string);
+ * // Use the ASCII string...
+ * StringBuffer::reset(); // Clean up when done
+ * @endcode
+ *
+ * Thread Safety: All methods are thread-safe due to thread-local storage.
+ */
+class StringBuffer {
+private:
+ static constexpr size_t BASE_SIZE = 128;
+ // Temporarily stores the UTF-16 characters retrieved from the Java
+ // string before they are converted to ASCII.
+ static thread_local inline char char_buffer[BASE_SIZE];
+ // For fast-path conversions when the resulting ASCII string fits within
+ // the pre-allocated space. All ascii strings in a trace event will be stored
+ // here until emitted.
+ static thread_local inline jchar jchar_buffer[BASE_SIZE];
+ // When the fast-path conversion is not possible (because char_buffer
+ // doesn't have enough space), the converted ASCII string is stored
+ // in this list. We use list here to avoid moving the strings on resize
+ // with vector. This way, we can give out string_views from the stored strings.
+ // The additional overhead from list node allocations is fine cos we are already
+ // in an extremely unlikely path here and there are other bigger problems if here.
+ static thread_local inline std::list<std::string> overflow_strings;
+ // current offset into the char_buffer.
+ static thread_local inline size_t current_offset{0};
+ // This allows us avoid touching the overflow_strings directly in the fast path.
+ // Touching it causes some thread local init routine to run which shows up in profiles.
+ static thread_local inline bool is_overflow_strings_empty = true;
+
+ static void copy_utf16_to_ascii(const jchar* src, size_t len, char* dst, JNIEnv* env,
+ jstring str) {
+ std::transform(src, src + len, dst,
+ [](jchar c) { return (c <= 0xFF) ? static_cast<char>(c) : '?'; });
+
+ if (src != jchar_buffer) {
+ // We hit the slow path to populate src, so we have to release.
+ env->ReleaseStringCritical(str, src);
+ }
+ }
+
+public:
+ static void reset() {
+ if (!is_overflow_strings_empty) {
+ overflow_strings.clear();
+ is_overflow_strings_empty = true;
+ }
+ current_offset = 0;
+ }
+
+ // Converts a Java string (jstring) to an ASCII string_view. Characters
+ // outside the ASCII range (0-255) are replaced with '?'.
+ //
+ // @param env The JNI environment.
+ // @param val The Java string to convert.
+ // @return A string_view representing the ASCII version of the string.
+ // Returns an empty string_view if the input is null or empty.
+ static std::string_view utf16_to_ascii(JNIEnv* env, jstring val) {
+ if (!val) return "";
+
+ const jsize len = env->GetStringLength(val);
+ if (len == 0) return "";
+
+ const jchar* temp_buffer;
+
+ // Fast path: Enough space in jchar_buffer
+ if (static_cast<size_t>(len) <= BASE_SIZE) {
+ env->GetStringRegion(val, 0, len, jchar_buffer);
+ temp_buffer = jchar_buffer;
+ } else {
+ // Slow path: Fallback to asking ART for the string which will likely
+ // allocate and return a copy.
+ temp_buffer = env->GetStringCritical(val, nullptr);
+ }
+
+ const size_t next_offset = current_offset + len + 1;
+ // Fast path: Enough space in char_buffer
+ if (BASE_SIZE > next_offset) {
+ const size_t start_offset = current_offset;
+
+ copy_utf16_to_ascii(temp_buffer, len, char_buffer + current_offset, env, val);
+ char_buffer[current_offset + len] = '\0';
+
+ auto res = std::string_view(char_buffer + current_offset, len);
+ current_offset = next_offset;
+ return res;
+ } else {
+ // Slow path: Not enough space in char_buffer. Use overflow_strings.
+ // This will cause a string alloc but should be very unlikely to hit.
+ std::string& str = overflow_strings.emplace_back(len + 1, '\0');
+
+ copy_utf16_to_ascii(temp_buffer, len, str.data(), env, val);
+ is_overflow_strings_empty = false;
+ return std::string_view(str);
+ }
+ }
+};
+
static jlong android_os_PerfettoTrackEventExtraArgInt64_init(JNIEnv* env, jclass, jstring name) {
- ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name);
- return toJLong(new tracing_perfetto::DebugArg<int64_t>(name_chars.c_str()));
+ return toJLong(new tracing_perfetto::DebugArg<int64_t>(
+ StringBuffer::utf16_to_ascii(env, name).data()));
}
static jlong android_os_PerfettoTrackEventExtraArgBool_init(JNIEnv* env, jclass, jstring name) {
- ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name);
- return toJLong(new tracing_perfetto::DebugArg<bool>(name_chars.c_str()));
+ return toJLong(
+ new tracing_perfetto::DebugArg<bool>(StringBuffer::utf16_to_ascii(env, name).data()));
}
static jlong android_os_PerfettoTrackEventExtraArgDouble_init(JNIEnv* env, jclass, jstring name) {
- ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name);
- return toJLong(new tracing_perfetto::DebugArg<double>(name_chars.c_str()));
+ return toJLong(
+ new tracing_perfetto::DebugArg<double>(StringBuffer::utf16_to_ascii(env, name).data()));
}
static jlong android_os_PerfettoTrackEventExtraArgString_init(JNIEnv* env, jclass, jstring name) {
- ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name);
- return toJLong(new tracing_perfetto::DebugArg<const char*>(name_chars.c_str()));
+ return toJLong(new tracing_perfetto::DebugArg<const char*>(
+ StringBuffer::utf16_to_ascii(env, name).data()));
}
static jlong android_os_PerfettoTrackEventExtraArgInt64_delete() {
@@ -109,11 +231,9 @@ static void android_os_PerfettoTrackEventExtraArgDouble_set_value(jlong ptr, jdo
static void android_os_PerfettoTrackEventExtraArgString_set_value(JNIEnv* env, jclass, jlong ptr,
jstring val) {
- ScopedUtfChars val_chars = GET_UTF_OR_RETURN_VOID(env, val);
-
tracing_perfetto::DebugArg<const char*>* arg =
toPointer<tracing_perfetto::DebugArg<const char*>>(ptr);
- arg->set_value(strdup(val_chars.c_str()));
+ arg->set_value(StringBuffer::utf16_to_ascii(env, val).data());
}
static jlong android_os_PerfettoTrackEventExtraFieldInt64_init() {
@@ -186,11 +306,9 @@ static void android_os_PerfettoTrackEventExtraFieldDouble_set_value(jlong ptr, j
static void android_os_PerfettoTrackEventExtraFieldString_set_value(JNIEnv* env, jclass, jlong ptr,
jlong id, jstring val) {
- ScopedUtfChars val_chars = GET_UTF_OR_RETURN_VOID(env, val);
-
tracing_perfetto::ProtoField<const char*>* field =
toPointer<tracing_perfetto::ProtoField<const char*>>(ptr);
- field->set_value(id, strdup(val_chars.c_str()));
+ field->set_value(id, StringBuffer::utf16_to_ascii(env, val).data());
}
static void android_os_PerfettoTrackEventExtraFieldNested_add_field(jlong field_ptr,
@@ -231,8 +349,9 @@ static jlong android_os_PerfettoTrackEventExtraFlow_get_extra_ptr(jlong ptr) {
static jlong android_os_PerfettoTrackEventExtraNamedTrack_init(JNIEnv* env, jclass, jlong id,
jstring name, jlong parent_uuid) {
- ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name);
- return toJLong(new tracing_perfetto::NamedTrack(id, parent_uuid, name_chars.c_str()));
+ return toJLong(
+ new tracing_perfetto::NamedTrack(id, parent_uuid,
+ StringBuffer::utf16_to_ascii(env, name).data()));
}
static jlong android_os_PerfettoTrackEventExtraNamedTrack_delete() {
@@ -246,9 +365,10 @@ static jlong android_os_PerfettoTrackEventExtraNamedTrack_get_extra_ptr(jlong pt
static jlong android_os_PerfettoTrackEventExtraCounterTrack_init(JNIEnv* env, jclass, jstring name,
jlong parent_uuid) {
- ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name);
-
- return toJLong(new tracing_perfetto::RegisteredTrack(1, parent_uuid, name_chars.c_str(), true));
+ return toJLong(
+ new tracing_perfetto::RegisteredTrack(1, parent_uuid,
+ StringBuffer::utf16_to_ascii(env, name).data(),
+ true));
}
static jlong android_os_PerfettoTrackEventExtraCounterTrack_delete() {
@@ -318,11 +438,11 @@ static void android_os_PerfettoTrackEventExtra_clear_args(jlong ptr) {
static void android_os_PerfettoTrackEventExtra_emit(JNIEnv* env, jclass, jint type, jlong cat_ptr,
jstring name, jlong extra_ptr) {
- ScopedUtfChars name_chars = GET_UTF_OR_RETURN_VOID(env, name);
-
tracing_perfetto::Category* category = toPointer<tracing_perfetto::Category>(cat_ptr);
- tracing_perfetto::trace_event(type, category->get(), name_chars.c_str(),
+ tracing_perfetto::trace_event(type, category->get(),
+ StringBuffer::utf16_to_ascii(env, name).data(),
toPointer<tracing_perfetto::Extra>(extra_ptr));
+ StringBuffer::reset();
}
static jlong android_os_PerfettoTrackEventExtraProto_init() {
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index b2649a471b8a..a73ff421acf7 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -424,6 +424,15 @@ static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
assetmanager->SetDefaultLocale(default_locale_int);
}
+static void NativeSetOverlayConstraints(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr,
+ jint displayId, jint deviceId) {
+ ATRACE_NAME("AssetManager::SetDisplayIdAndDeviceId");
+
+ auto assetmanager = LockAndStartAssetManager(ptr);
+ assetmanager->SetOverlayConstraints(static_cast<int32_t>(displayId),
+ static_cast<int32_t>(deviceId));
+}
+
static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jboolean includeOverlays,
jboolean includeLoaders) {
@@ -1554,6 +1563,7 @@ static const JNINativeMethod gAssetManagerMethods[] = {
{"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;ZZ)V", (void*)NativeSetApkAssets},
{"nativeSetConfiguration", "(JIILjava/lang/String;[Ljava/lang/String;IIIIIIIIIIIIIIIIZ)V",
(void*)NativeSetConfiguration},
+ {"nativeSetOverlayConstraints", "(JII)V", (void*)NativeSetOverlayConstraints},
{"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
(void*)NativeGetAssignedPackageIdentifiers},
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
index 7ffe0ed7c6cd..8f36ecb8b01a 100644
--- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -97,7 +97,13 @@ static void native_updateValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray
static void native_incrementValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray values,
jlong timestamp) {
auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
- counter->incrementValue(JavaUint64Array(env, values), timestamp);
+ if (values != nullptr) {
+ counter->incrementValue(JavaUint64Array(env, values), timestamp);
+ } else {
+ // Pass an empty Uint64Array, which is equivalent to an array of zeros.
+ // This is done to ensure that the timestamp is still updated in the counter.
+ counter->incrementValue(Uint64Array(), timestamp);
+ }
}
static void native_addCounts(JNIEnv *env, jclass, jlong nativePtr, jlongArray values) {
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index b51f72dee260..aa8f8419ac46 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -5,7 +5,6 @@ joeo@google.com
singhtejinder@google.com
yanmin@google.com
yaochen@google.com
-yro@google.com
zhouwenjie@google.com
# Frameworks
diff --git a/core/res/res/drawable-w192dp/loader_horizontal_watch.xml b/core/res/res/drawable-w192dp/loader_horizontal_watch.xml
deleted file mode 100644
index 18cea6e0d87d..000000000000
--- a/core/res/res/drawable-w192dp/loader_horizontal_watch.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<!--
- ~ Copyright (C) 2025 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.
- -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
- <aapt:attr name="android:drawable">
- <vector android:height="15dp" android:width="67dp" android:viewportHeight="15" android:viewportWidth="67">
- <group android:name="_R_G">
- <group android:name="_R_G_L_1_G" android:translateX="33.5" android:translateY="7.5">
- <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M33.5 -7.5 C33.5,-7.5 33.5,7.5 33.5,7.5 C33.5,7.5 -33.5,7.5 -33.5,7.5 C-33.5,7.5 -33.5,-7.5 -33.5,-7.5 C-33.5,-7.5 33.5,-7.5 33.5,-7.5c "/>
- </group>
- <group android:name="_R_G_L_0_G" android:translateX="-296.5" android:translateY="-62.5" android:pivotX="330" android:pivotY="70" android:scaleX="0.1" android:scaleY="0.1">
- <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-224.84700000000004" android:translateY="-321.948" android:pivotX="555.09" android:pivotY="-329" android:rotation="28.9" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M194.88 359 C190,359 185.05,357.81 180.48,355.3 C59.86,289.14 -41.55,191.9 -112.79,74.11 C-186.14,-47.16 -224.91,-186.55 -224.91,-329 C-224.91,-345.57 -211.48,-359 -194.91,-359 C-178.34,-359 -164.91,-345.57 -164.91,-329 C-164.91,-197.5 -129.13,-68.84 -61.45,43.06 C4.33,151.82 97.97,241.6 209.33,302.69 C223.86,310.66 229.18,328.9 221.21,343.42 C215.75,353.37 205.48,359 194.88,359c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_5_G" android:translateX="744.323" android:translateY="-277.96299999999997" android:pivotX="-414.08" android:pivotY="-372.985" android:rotation="28.9">
- <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-335.95 402.99 C-351.13,402.99 -364.16,391.5 -365.76,376.07 C-367.46,359.59 -355.49,344.85 -339.01,343.14 C-162.93,324.91 -0.15,242.33 119.34,110.62 C239.66,-22.01 305.92,-193.76 305.92,-372.98 C305.92,-389.55 319.35,-402.98 335.92,-402.98 C352.49,-402.98 365.92,-389.55 365.92,-372.98 C365.92,-178.82 294.13,7.24 163.78,150.93 C34.34,293.61 -142.03,383.07 -332.83,402.82 C-333.88,402.93 -334.92,402.99 -335.95,402.99c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_2_G" android:translateX="185.385" android:translateY="70.09100000000001" android:pivotX="144.858" android:pivotY="-721.039" android:rotation="28.9" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M144.62 58.96 C144.61,58.96 144.61,58.96 144.6,58.96 C40.39,58.93 -60.82,38.66 -156.19,-1.28 C-171.48,-7.68 -178.68,-25.26 -172.28,-40.54 C-165.88,-55.82 -148.3,-63.02 -133.02,-56.62 C-45.02,-19.77 48.4,-1.07 144.63,-1.04 C161.19,-1.03 174.62,12.4 174.62,28.97 C174.61,45.53 161.18,58.96 144.62,58.96c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_0_G" android:translateX="330" android:translateY="70">
- <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-660 -313 C-660,-313 -660,313 -660,313 C-660,313 660,313 660,313 C660,313 660,-313 660,-313 C660,-313 -660,-313 -660,-313c M300.74 -1.16 C205.46,38.62 103.22,59.09 -0.03,59.05 C-103.28,59.01 -205.51,38.48 -300.76,-1.37 C-316.05,-7.76 -323.26,-25.34 -316.86,-40.62 C-310.47,-55.91 -292.9,-63.12 -277.61,-56.72 C-189.68,-19.94 -95.32,-0.98 -0.01,-0.95 C95.3,-0.92 189.67,-19.81 277.63,-56.53 C292.92,-62.91 310.49,-55.69 316.87,-40.4 C323.25,-25.11 316.03,-7.54 300.74,-1.16c "/>
- </group>
- </group>
- </group>
- <group android:name="time_group"/>
- </vector>
- </aapt:attr>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.9" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.135 0.202,0.848 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.9" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.135 0.202,0.848 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.9" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.135 0.202,0.848 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="time_group">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
-</animated-vector>
-
diff --git a/core/res/res/drawable-w204dp/loader_horizontal_watch.xml b/core/res/res/drawable-w204dp/loader_horizontal_watch.xml
deleted file mode 100644
index fbc6eab320eb..000000000000
--- a/core/res/res/drawable-w204dp/loader_horizontal_watch.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<!--
- ~ Copyright (C) 2025 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.
- -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
- <aapt:attr name="android:drawable">
- <vector android:height="15dp" android:width="70dp" android:viewportHeight="15" android:viewportWidth="70">
- <group android:name="_R_G">
- <group android:name="_R_G_L_1_G" android:translateX="35" android:translateY="7.5">
- <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M35 -7.5 C35,-7.5 35,7.5 35,7.5 C35,7.5 -35,7.5 -35,7.5 C-35,7.5 -35,-7.5 -35,-7.5 C-35,-7.5 35,-7.5 35,-7.5c "/>
- </group>
- <group android:name="_R_G_L_0_G" android:translateX="-310" android:translateY="-64" android:pivotX="345" android:pivotY="71.5" android:scaleX="0.1" android:scaleY="0.1">
- <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-239.44799999999998" android:translateY="-341.45" android:pivotX="584.448" android:pivotY="-346.55" android:rotation="28.8" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M205.28 376.55 C200.4,376.55 195.46,375.36 190.88,372.85 C64.08,303.29 -42.54,201.07 -117.44,77.24 C-194.55,-50.25 -235.31,-196.79 -235.31,-346.55 C-235.31,-363.12 -221.88,-376.55 -205.31,-376.55 C-188.74,-376.55 -175.31,-363.12 -175.31,-346.55 C-175.31,-207.74 -137.54,-71.93 -66.1,46.19 C3.34,160.99 102.18,255.76 219.73,320.24 C234.26,328.21 239.58,346.45 231.61,360.97 C226.15,370.92 215.88,376.55 205.28,376.55c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_5_G" android:translateX="781.413" android:translateY="-295.124" android:pivotX="-436.413" android:pivotY="-392.876" android:rotation="28.8">
- <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-353.86 422.88 C-369.04,422.88 -382.07,411.4 -383.67,395.97 C-385.37,379.49 -373.4,364.74 -356.92,363.03 C-171.06,343.79 0.76,256.62 126.89,117.59 C253.89,-22.41 323.83,-203.7 323.83,-392.88 C323.83,-409.44 337.26,-422.88 353.83,-422.88 C370.4,-422.88 383.83,-409.44 383.83,-392.88 C383.83,-188.76 308.36,6.84 171.32,157.9 C35.25,307.89 -150.15,401.94 -350.74,422.72 C-351.79,422.82 -352.83,422.88 -353.86,422.88c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_2_G" android:translateX="192.671" android:translateY="71.49599999999998" android:pivotX="152.329" android:pivotY="-759.496" android:rotation="28.8" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M152.33 60.5 C152.33,60.5 152.32,60.5 152.32,60.5 C42.76,60.47 -63.64,39.16 -163.91,-2.82 C-179.19,-9.22 -186.39,-26.8 -179.99,-42.08 C-173.59,-57.36 -156.02,-64.57 -140.73,-58.16 C-47.84,-19.27 50.77,0.47 152.34,0.5 C168.91,0.51 182.33,13.94 182.33,30.51 C182.32,47.08 168.89,60.5 152.33,60.5c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_0_G" android:translateX="345" android:translateY="71.5">
- <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-579 -259.5 C-579,-259.5 -579,259.5 -579,259.5 C-579,259.5 579,259.5 579,259.5 C579,259.5 579,-259.5 579,-259.5 C579,-259.5 -579,-259.5 -579,-259.5c M316.17 -2.8 C216,39.02 108.52,60.54 -0.03,60.5 C-108.58,60.46 -216.04,38.87 -316.18,-3.02 C-331.47,-9.41 -338.68,-26.99 -332.28,-42.27 C-325.89,-57.56 -308.32,-64.76 -293.03,-58.37 C-200.22,-19.55 -100.61,0.46 -0.01,0.5 C100.6,0.54 200.22,-19.41 293.06,-58.17 C308.35,-64.55 325.92,-57.33 332.3,-42.04 C338.68,-26.75 331.46,-9.18 316.17,-2.8c "/>
- </group>
- </group>
- </group>
- <group android:name="time_group"/>
- </vector>
- </aapt:attr>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="time_group">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
-</animated-vector>
-
diff --git a/core/res/res/drawable-w216dp/loader_horizontal_watch.xml b/core/res/res/drawable-w216dp/loader_horizontal_watch.xml
deleted file mode 100644
index ed4b7ea0ff02..000000000000
--- a/core/res/res/drawable-w216dp/loader_horizontal_watch.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<!--
- ~ Copyright (C) 2025 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.
- -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
- <aapt:attr name="android:drawable">
- <vector android:height="16dp" android:width="74dp" android:viewportHeight="16" android:viewportWidth="74">
- <group android:name="_R_G">
- <group android:name="_R_G_L_1_G" android:translateX="37" android:translateY="8">
- <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M37 -8 C37,-8 37,8 37,8 C37,8 -37,8 -37,8 C-37,8 -37,-8 -37,-8 C-37,-8 37,-8 37,-8c "/>
- </group>
- <group android:name="_R_G_L_0_G" android:translateX="-328" android:translateY="-65.5" android:pivotX="365" android:pivotY="73.5" android:scaleX="0.1" android:scaleY="0.1">
- <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-256.447" android:translateY="-365.014" android:pivotX="621.447" android:pivotY="-368.486" android:rotation="28.8" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M218.28 398.49 C213.4,398.49 208.46,397.3 203.88,394.78 C69.34,320.99 -43.78,212.53 -123.25,81.15 C-205.06,-54.11 -248.31,-209.59 -248.31,-368.49 C-248.31,-385.05 -234.88,-398.49 -218.31,-398.49 C-201.74,-398.49 -188.31,-385.05 -188.31,-368.49 C-188.31,-220.54 -148.06,-75.8 -71.91,50.09 C2.1,172.45 107.45,273.45 232.73,342.18 C247.26,350.15 252.58,368.38 244.61,382.91 C239.15,392.86 228.88,398.49 218.28,398.49c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_5_G" android:translateX="829.0260000000001" android:translateY="-315.759" android:pivotX="-464.026" android:pivotY="-417.741" android:rotation="28.8">
- <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-376.25 447.74 C-391.43,447.74 -404.46,436.26 -406.05,420.83 C-407.76,404.35 -395.78,389.61 -379.3,387.9 C-181.22,367.38 1.9,274.48 136.32,126.3 C271.67,-22.9 346.22,-216.12 346.22,-417.74 C346.22,-434.31 359.65,-447.74 376.22,-447.74 C392.79,-447.74 406.22,-434.31 406.22,-417.74 C406.22,-201.18 326.15,6.35 180.76,166.61 C36.39,325.75 -160.31,425.54 -373.12,447.58 C-374.17,447.69 -375.22,447.74 -376.25,447.74c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_2_G" android:translateX="203.029" android:translateY="74.06899999999996" android:pivotX="161.971" android:pivotY="-807.569" android:rotation="28.8" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M161.97 62.43 C161.97,62.43 161.96,62.43 161.96,62.43 C45.71,62.4 -67.17,39.79 -173.55,-4.75 C-188.83,-11.15 -196.03,-28.72 -189.63,-44.01 C-183.24,-59.29 -165.66,-66.49 -150.38,-60.09 C-51.37,-18.64 53.72,2.4 161.98,2.43 C178.55,2.44 191.98,15.87 191.97,32.44 C191.97,49 178.54,62.43 161.97,62.43c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_0_G" android:translateX="365" android:translateY="73.5">
- <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-609 -244.5 C-609,-244.5 -609,244.5 -609,244.5 C-609,244.5 609,244.5 609,244.5 C609,244.5 609,-244.5 609,-244.5 C609,-244.5 -609,-244.5 -609,-244.5c M335.44 -4.16 C229.17,40.21 115.13,63.04 -0.04,63 C-115.21,62.96 -229.22,40.05 -335.47,-4.39 C-350.76,-10.79 -357.95,-28.36 -351.56,-43.65 C-345.17,-58.93 -327.59,-66.14 -312.31,-59.74 C-213.39,-18.36 -107.24,2.96 -0.02,3 C107.21,3.04 213.38,-18.22 312.33,-59.53 C327.62,-65.91 345.19,-58.69 351.57,-43.4 C357.95,-28.11 350.73,-10.54 335.44,-4.16c "/>
- </group>
- </group>
- </group>
- <group android:name="time_group"/>
- </vector>
- </aapt:attr>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.3" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.3" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.3" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="time_group">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
-</animated-vector>
-
-
diff --git a/core/res/res/drawable-w228dp/loader_horizontal_watch.xml b/core/res/res/drawable-w228dp/loader_horizontal_watch.xml
deleted file mode 100644
index 6b86c634d554..000000000000
--- a/core/res/res/drawable-w228dp/loader_horizontal_watch.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<!--
- ~ Copyright (C) 2025 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.
- -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
- <aapt:attr name="android:drawable">
- <vector android:height="14dp" android:width="76dp" android:viewportHeight="14" android:viewportWidth="76">
- <group android:name="_R_G">
- <group android:name="_R_G_L_1_G" android:translateX="39" android:translateY="8">
- <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M39 -8 C39,-8 39,8 39,8 C39,8 -39,8 -39,8 C-39,8 -39,-8 -39,-8 C-39,-8 39,-8 39,-8c "/>
- </group>
- <group android:name="_R_G_L_0_G" android:translateX="-345" android:translateY="-67" android:pivotX="384" android:pivotY="75" android:scaleX="0.1" android:scaleY="0.1">
- <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-274.19" android:translateY="-390.077" android:pivotX="658.448" android:pivotY="-390.423" android:rotation="28.7" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M231.28 420.42 C226.4,420.42 221.45,419.23 216.88,416.72 C74.61,338.68 -45.02,224 -129.06,85.06 C-171.54,14.82 -204.38,-60.73 -226.66,-139.5 C-249.65,-220.76 -261.31,-305.18 -261.31,-390.42 C-261.31,-406.99 -247.88,-420.42 -231.31,-420.42 C-214.74,-420.42 -201.31,-406.99 -201.31,-390.42 C-201.31,-310.71 -190.42,-231.78 -168.93,-155.83 C-148.11,-82.23 -117.42,-11.63 -77.72,54 C0.86,183.92 112.71,291.15 245.73,364.12 C260.26,372.08 265.58,390.32 257.61,404.85 C252.15,414.79 241.88,420.42 231.28,420.42c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_5_G" android:translateX="875.8979999999999" android:translateY="-337.894" android:pivotX="-491.64" android:pivotY="-442.606" android:rotation="28.7">
- <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-398.64 472.61 C-413.82,472.61 -426.84,461.13 -428.44,445.7 C-430.15,429.22 -418.17,414.47 -401.69,412.77 C-191.38,390.98 3.04,292.33 145.75,135.01 C289.46,-23.4 368.6,-228.54 368.6,-442.61 C368.6,-459.17 382.04,-472.61 398.6,-472.61 C415.17,-472.61 428.6,-459.17 428.6,-442.61 C428.6,-213.6 343.93,5.85 190.19,175.33 C37.53,343.61 -170.48,449.13 -395.51,472.44 C-396.56,472.55 -397.6,472.61 -398.64,472.61c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_2_G" android:translateX="212.64499999999998" android:translateY="75.14200000000005" android:pivotX="171.613" android:pivotY="-855.642" android:rotation="28.7" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M171.61 64.36 C171.61,64.36 171.61,64.36 171.61,64.36 C48.68,64.32 -70.7,40.42 -183.19,-6.68 C-198.47,-13.07 -205.68,-30.65 -199.28,-45.93 C-192.88,-61.22 -175.3,-68.42 -160.02,-62.02 C-54.9,-18.01 56.68,4.33 171.62,4.36 C188.19,4.36 201.62,17.8 201.61,34.36 C201.61,50.93 188.18,64.36 171.61,64.36c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_0_G" android:translateX="384" android:translateY="75">
- <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-611 -259 C-611,-259 -611,259 -611,259 C-611,259 611,259 611,259 C611,259 611,-259 611,-259 C611,-259 -611,-259 -611,-259c M354.66 -6.52 C242.36,40.4 121.76,64.54 -0.04,64.5 C-121.84,64.46 -242.44,40.23 -354.74,-6.76 C-370.04,-13.16 -377.24,-30.73 -370.84,-46.02 C-364.44,-61.3 -346.94,-68.51 -331.64,-62.12 C-226.54,-18.18 -113.84,4.46 -0.04,4.5 C113.76,4.54 226.56,-18.02 331.56,-61.89 C346.86,-68.27 364.46,-61.05 370.86,-45.76 C377.26,-30.47 369.96,-12.9 354.66,-6.52c "/>
- </group>
- </group>
- </group>
- <group android:name="time_group"/>
- </vector>
- </aapt:attr>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="time_group">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
-</animated-vector>
diff --git a/core/res/res/drawable-w240dp/loader_horizontal_watch.xml b/core/res/res/drawable-w240dp/loader_horizontal_watch.xml
deleted file mode 100644
index ad60bbdc420c..000000000000
--- a/core/res/res/drawable-w240dp/loader_horizontal_watch.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<!--
- ~ Copyright (C) 2025 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.
- -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
- <aapt:attr name="android:drawable">
- <vector android:height="17dp" android:width="82dp" android:viewportHeight="17" android:viewportWidth="82">
- <group android:name="_R_G">
- <group android:name="_R_G_L_1_G" android:translateX="41" android:translateY="8.5">
- <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M41 -8.5 C41,-8.5 41,8.5 41,8.5 C41,8.5 -41,8.5 -41,8.5 C-41,8.5 -41,-8.5 -41,-8.5 C-41,-8.5 41,-8.5 41,-8.5c "/>
- </group>
- <group android:name="_R_G_L_0_G" android:translateX="-362.5" android:translateY="-69" android:pivotX="403.5" android:pivotY="77.5" android:scaleX="0.1" android:scaleY="0.1">
- <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-291.64799999999997" android:translateY="-414.141" android:pivotX="695.448" android:pivotY="-412.359" android:rotation="28.7" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M244.28 442.36 C239.4,442.36 234.45,441.17 229.88,438.66 C79.87,356.38 -46.26,235.46 -134.87,88.96 C-179.66,14.91 -214.28,-64.74 -237.78,-147.79 C-262.02,-233.47 -274.31,-322.49 -274.31,-412.36 C-274.31,-428.93 -260.88,-442.36 -244.31,-442.36 C-227.74,-442.36 -214.31,-428.93 -214.31,-412.36 C-214.31,-328.01 -202.78,-244.49 -180.05,-164.12 C-158.01,-86.24 -125.54,-11.54 -83.53,57.91 C-0.38,195.38 117.97,308.85 258.73,386.05 C273.26,394.02 278.58,412.26 270.61,426.78 C265.15,436.73 254.88,442.36 244.28,442.36c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_5_G" android:translateX="923.0530000000001" android:translateY="-359.029" android:pivotX="-519.253" android:pivotY="-467.471" android:rotation="28.7">
- <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-421.02 497.47 C-436.2,497.47 -449.23,485.99 -450.83,470.56 C-452.53,454.08 -440.56,439.34 -424.08,437.63 C-201.54,414.57 4.18,310.19 155.19,143.73 C229.54,61.77 287.7,-31.75 328.04,-134.22 C369.81,-240.3 390.99,-352.42 390.99,-467.47 C390.99,-484.04 404.42,-497.47 420.99,-497.47 C437.56,-497.47 450.99,-484.04 450.99,-467.47 C450.99,-226.02 361.72,5.35 199.63,184.04 C38.67,361.47 -180.63,472.73 -417.89,497.31 C-418.94,497.42 -419.99,497.47 -421.02,497.47c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_2_G" android:translateX="222.54600000000002" android:translateY="77.21400000000006" android:pivotX="181.254" android:pivotY="-903.714" android:rotation="28.7" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M181.26 66.28 C181.25,66.28 181.25,66.28 181.25,66.28 C51.64,66.25 -74.22,41.06 -192.83,-8.6 C-208.12,-15 -215.32,-32.58 -208.92,-47.86 C-202.52,-63.15 -184.94,-70.35 -169.66,-63.95 C-58.42,-17.38 59.64,6.25 181.26,6.28 C197.83,6.29 211.26,19.72 211.26,36.29 C211.25,52.86 197.82,66.28 181.26,66.28c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_0_G" android:translateX="403.5" android:translateY="77.5">
- <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-630.5 -255.5 C-630.5,-255.5 -630.5,255.5 -630.5,255.5 C-630.5,255.5 630.5,255.5 630.5,255.5 C630.5,255.5 630.5,-255.5 630.5,-255.5 C630.5,-255.5 -630.5,-255.5 -630.5,-255.5c M374 -8.88 C255.5,40.59 128.4,66.04 0,66 C-128.4,65.95 -255.6,40.42 -374,-9.14 C-389.3,-15.53 -396.5,-33.11 -390.1,-48.39 C-383.7,-63.68 -366.2,-70.88 -350.9,-64.49 C-239.7,-18 -120.5,5.96 0,6 C120.4,6.04 239.7,-17.84 350.9,-64.25 C366.2,-70.63 383.7,-63.41 390.1,-48.12 C396.5,-32.83 389.3,-15.26 374,-8.88c "/>
- </group>
- </group>
- </group>
- <group android:name="time_group"/>
- </vector>
- </aapt:attr>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="time_group">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
-</animated-vector>
-
diff --git a/core/res/res/drawable/loader_horizontal_watch.xml b/core/res/res/drawable/loader_horizontal_watch.xml
deleted file mode 100644
index 6b86c634d554..000000000000
--- a/core/res/res/drawable/loader_horizontal_watch.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<!--
- ~ Copyright (C) 2025 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.
- -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
- <aapt:attr name="android:drawable">
- <vector android:height="14dp" android:width="76dp" android:viewportHeight="14" android:viewportWidth="76">
- <group android:name="_R_G">
- <group android:name="_R_G_L_1_G" android:translateX="39" android:translateY="8">
- <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M39 -8 C39,-8 39,8 39,8 C39,8 -39,8 -39,8 C-39,8 -39,-8 -39,-8 C-39,-8 39,-8 39,-8c "/>
- </group>
- <group android:name="_R_G_L_0_G" android:translateX="-345" android:translateY="-67" android:pivotX="384" android:pivotY="75" android:scaleX="0.1" android:scaleY="0.1">
- <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-274.19" android:translateY="-390.077" android:pivotX="658.448" android:pivotY="-390.423" android:rotation="28.7" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M231.28 420.42 C226.4,420.42 221.45,419.23 216.88,416.72 C74.61,338.68 -45.02,224 -129.06,85.06 C-171.54,14.82 -204.38,-60.73 -226.66,-139.5 C-249.65,-220.76 -261.31,-305.18 -261.31,-390.42 C-261.31,-406.99 -247.88,-420.42 -231.31,-420.42 C-214.74,-420.42 -201.31,-406.99 -201.31,-390.42 C-201.31,-310.71 -190.42,-231.78 -168.93,-155.83 C-148.11,-82.23 -117.42,-11.63 -77.72,54 C0.86,183.92 112.71,291.15 245.73,364.12 C260.26,372.08 265.58,390.32 257.61,404.85 C252.15,414.79 241.88,420.42 231.28,420.42c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_5_G" android:translateX="875.8979999999999" android:translateY="-337.894" android:pivotX="-491.64" android:pivotY="-442.606" android:rotation="28.7">
- <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-398.64 472.61 C-413.82,472.61 -426.84,461.13 -428.44,445.7 C-430.15,429.22 -418.17,414.47 -401.69,412.77 C-191.38,390.98 3.04,292.33 145.75,135.01 C289.46,-23.4 368.6,-228.54 368.6,-442.61 C368.6,-459.17 382.04,-472.61 398.6,-472.61 C415.17,-472.61 428.6,-459.17 428.6,-442.61 C428.6,-213.6 343.93,5.85 190.19,175.33 C37.53,343.61 -170.48,449.13 -395.51,472.44 C-396.56,472.55 -397.6,472.61 -398.64,472.61c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_2_G" android:translateX="212.64499999999998" android:translateY="75.14200000000005" android:pivotX="171.613" android:pivotY="-855.642" android:rotation="28.7" android:scaleY="0">
- <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M171.61 64.36 C171.61,64.36 171.61,64.36 171.61,64.36 C48.68,64.32 -70.7,40.42 -183.19,-6.68 C-198.47,-13.07 -205.68,-30.65 -199.28,-45.93 C-192.88,-61.22 -175.3,-68.42 -160.02,-62.02 C-54.9,-18.01 56.68,4.33 171.62,4.36 C188.19,4.36 201.62,17.8 201.61,34.36 C201.61,50.93 188.18,64.36 171.61,64.36c "/>
- </group>
- <group android:name="_R_G_L_0_G_L_0_G" android:translateX="384" android:translateY="75">
- <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-611 -259 C-611,-259 -611,259 -611,259 C-611,259 611,259 611,259 C611,259 611,-259 611,-259 C611,-259 -611,-259 -611,-259c M354.66 -6.52 C242.36,40.4 121.76,64.54 -0.04,64.5 C-121.84,64.46 -242.44,40.23 -354.74,-6.76 C-370.04,-13.16 -377.24,-30.73 -370.84,-46.02 C-364.44,-61.3 -346.94,-68.51 -331.64,-62.12 C-226.54,-18.18 -113.84,4.46 -0.04,4.5 C113.76,4.54 226.56,-18.02 331.56,-61.89 C346.86,-68.27 364.46,-61.05 370.86,-45.76 C377.26,-30.47 369.96,-12.9 354.66,-6.52c "/>
- </group>
- </group>
- </group>
- <group android:name="time_group"/>
- </vector>
- </aapt:attr>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_6_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_5_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
- <target android:name="time_group">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
- </set>
- </aapt:attr>
- </target>
-</animated-vector>
diff --git a/core/res/res/drawable/progress_ring_watch.xml b/core/res/res/drawable/progress_ring_watch.xml
index 8250ee600a8f..2e65ff13b3de 100644
--- a/core/res/res/drawable/progress_ring_watch.xml
+++ b/core/res/res/drawable/progress_ring_watch.xml
@@ -16,27 +16,27 @@
-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
- android:fromDegrees = "270"
- android:toDegrees="270"
- android:pivotX="50%"
- android:pivotY="50%" >
+ android:fromDegrees="270"
+ android:toDegrees="270">
<layer-list>
<item>
<shape
- android:shape="ring"
- android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+ android:shape="arc"
+ android:useLevel="false"
android:thickness="@dimen/progressbar_thickness"
- android:useLevel="false">
- <solid android:color="@color/materialColorSurfaceContainer"/>
+ android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+ android:strokeCap="round">
+ <solid android:color="@*android:color/materialColorSurfaceContainer"/>
</shape>
</item>
<item>
<shape
- android:shape="ring"
- android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+ android:shape="arc"
+ android:useLevel="true"
android:thickness="@dimen/progressbar_thickness"
- android:useLevel="true">
- <solid android:color="@color/materialColorPrimary"/>
+ android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+ android:strokeCap="round">
+ <solid android:color="@*android:color/materialColorPrimary"/>
</shape>
</item>
</layer-list>
diff --git a/core/res/res/values-w192dp/dimens_watch.xml b/core/res/res/values-w192dp/dimens_watch.xml
deleted file mode 100644
index c6bf767ab6b8..000000000000
--- a/core/res/res/values-w192dp/dimens_watch.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2025 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<resources>
- <!-- 16.7% of display size -->
- <dimen name="base_error_dialog_top_padding">32dp</dimen>
- <!-- 5.2% of display size -->
- <dimen name="base_error_dialog_padding">10dp</dimen>
- <!-- 20.83% of display size -->
- <dimen name="base_error_dialog_bottom_padding">40dp</dimen>
-
- <!-- watch's indeterminate progress bar dimens based on the current screen size -->
- <dimen name="loader_horizontal_min_width_watch">67dp</dimen>
- <dimen name="loader_horizontal_min_height_watch">15dp</dimen>
-</resources>
diff --git a/core/res/res/values-w216dp/dimens_watch.xml b/core/res/res/values-w216dp/dimens_watch.xml
deleted file mode 100644
index e14ce5e98f55..000000000000
--- a/core/res/res/values-w216dp/dimens_watch.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
- ~ Copyright (C) 2025 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources>
- <!-- watch's indeterminate progress bar dimens based on the current screen size -->
- <dimen name="loader_horizontal_min_width_watch">72dp</dimen>
- <dimen name="loader_horizontal_min_height_watch">16dp</dimen>
-</resources> \ No newline at end of file
diff --git a/core/res/res/values-w228dp/dimens_watch.xml b/core/res/res/values-w228dp/dimens_watch.xml
deleted file mode 100644
index 3c6265690c3c..000000000000
--- a/core/res/res/values-w228dp/dimens_watch.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2025 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<resources>
- <!-- watch's indeterminate progress bar dimens based on the current screen size -->
- <dimen name="loader_horizontal_min_width">76dp</dimen>
- <dimen name="loader_horizontal_min_height">14dp</dimen>
-</resources>
diff --git a/core/res/res/values-w240dp/dimens_material.xml b/core/res/res/values-w240dp/dimens_material.xml
index e30aea46aec7..bd26c8bf84df 100644
--- a/core/res/res/values-w240dp/dimens_material.xml
+++ b/core/res/res/values-w240dp/dimens_material.xml
@@ -21,8 +21,4 @@
<dimen name="screen_percentage_12">28.8dp</dimen>
<dimen name="screen_percentage_15">36dp</dimen>
<dimen name="screen_percentage_3646">87.5dp</dimen>
-
- <!-- watch's indeterminate progress bar dimens based on the current screen size -->
- <dimen name="progress_indeterminate_horizontal_min_width_watch">80dp</dimen>
- <dimen name="progress_indeterminate_horizontal_min_height_watch">17dp</dimen>
</resources>
diff --git a/core/res/res/values-watch/styles_device_defaults.xml b/core/res/res/values-watch/styles_device_defaults.xml
index eeb66e7cf6a8..fb7dbb0660c5 100644
--- a/core/res/res/values-watch/styles_device_defaults.xml
+++ b/core/res/res/values-watch/styles_device_defaults.xml
@@ -42,8 +42,5 @@
<item name="indeterminateOnly">false</item>
<!-- Use Wear Material3 ring shape as default determinate drawable -->
<item name="progressDrawable">@drawable/progress_ring_watch</item>
- <item name="indeterminateDrawable">@drawable/loader_horizontal_watch</item>
- <item name="android:minWidth">@dimen/loader_horizontal_min_width_watch</item>
- <item name="android:minHeight">@dimen/loader_horizontal_min_height_watch</item>
</style>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 66111785af4f..d2c993aecb0d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6934,6 +6934,8 @@
<enum name="line" value="2" />
<!-- Ring shape. -->
<enum name="ring" value="3" />
+ <!-- ARC shape. -->
+ <enum name="arc" value="4"/>
</attr>
<!-- Inner radius of the ring expressed as a ratio of the ring's width. For instance,
if innerRadiusRatio=9, then the inner radius equals the ring's width divided by 9.
@@ -6966,6 +6968,12 @@
<attr name="opticalInsetRight" />
<!-- Bottom optical inset. -->
<attr name="opticalInsetBottom" />
+ <!-- Attributes that customize the stroke line cap. @hide -->
+ <attr name="strokeCap" format="enum">
+ <enum name="butt" value="0"/>
+ <enum name="round" value="1"/>
+ <enum name="square" value="2"/>
+ </attr>
</declare-styleable>
<!-- Used to specify the size of the shape for GradientDrawable. -->
diff --git a/core/res/res/values/dimens_watch.xml b/core/res/res/values/dimens_watch.xml
index 19845916984b..7462b733b0ae 100644
--- a/core/res/res/values/dimens_watch.xml
+++ b/core/res/res/values/dimens_watch.xml
@@ -52,7 +52,7 @@
<dimen name="primary_content_alpha_device_default">0.38</dimen>
<!-- values for wear material3 progress bar(progress indicator) -->
- <item name="progressbar_inner_radius_ratio" format="float" type="dimen">2.12</item>
+ <item name="progressbar_inner_radius_ratio" format="float" type="dimen">2</item>
<dimen name="progressbar_thickness">8dp</dimen>
<dimen name="progressbar_elevation">0.1dp</dimen>
@@ -61,8 +61,4 @@
<dimen name="disabled_alpha_wear_material3">0.12</dimen>
<!-- Alpha transparency applied to elements which are considered primary (e.g. primary text) -->
<dimen name="primary_content_alpha_wear_material3">0.38</dimen>
-
- <!-- watch's indeterminate progress bar dimens -->
- <dimen name="loader_horizontal_min_width">68dp</dimen>
- <dimen name="loader_horizontal_min_height">13dp</dimen>
</resources>
diff --git a/core/tests/coretests/src/android/os/PerfettoTraceTest.java b/core/tests/coretests/src/android/os/PerfettoTraceTest.java
index c5c2554c2a67..fb743d2b42ad 100644
--- a/core/tests/coretests/src/android/os/PerfettoTraceTest.java
+++ b/core/tests/coretests/src/android/os/PerfettoTraceTest.java
@@ -77,6 +77,8 @@ public class PerfettoTraceTest {
private static final String TAG = "PerfettoTraceTest";
private static final String FOO = "foo";
private static final String BAR = "bar";
+ private static final String TEXT_ABOVE_4K_SIZE =
+ new String(new char[8192]).replace('\0', 'a');
private static final Category FOO_CATEGORY = new Category(FOO);
private static final int MESSAGE = 1234567;
@@ -155,41 +157,6 @@ public class PerfettoTraceTest {
@Test
@RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
- public void testDebugAnnotationsWithLambda() throws Exception {
- TraceConfig traceConfig = getTraceConfig(FOO);
-
- PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
-
- PerfettoTrace.instant(FOO_CATEGORY, "event").addArg("long_val", 123L).emit();
-
- byte[] traceBytes = session.close();
-
- Trace trace = Trace.parseFrom(traceBytes);
-
- boolean hasTrackEvent = false;
- boolean hasDebugAnnotations = false;
- for (TracePacket packet: trace.getPacketList()) {
- TrackEvent event;
- if (packet.hasTrackEvent()) {
- hasTrackEvent = true;
- event = packet.getTrackEvent();
-
- if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType())
- && event.getDebugAnnotationsCount() == 1) {
- hasDebugAnnotations = true;
-
- List<DebugAnnotation> annotations = event.getDebugAnnotationsList();
- assertThat(annotations.get(0).getIntValue()).isEqualTo(123L);
- }
- }
- }
-
- assertThat(hasTrackEvent).isTrue();
- assertThat(hasDebugAnnotations).isTrue();
- }
-
- @Test
- @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
public void testNamedTrack() throws Exception {
TraceConfig traceConfig = getTraceConfig(FOO);
@@ -440,7 +407,6 @@ public class PerfettoTraceTest {
boolean hasTrackEvent = false;
boolean hasSourceLocation = false;
-
for (TracePacket packet: trace.getPacketList()) {
TrackEvent event;
if (packet.hasTrackEvent()) {
@@ -467,6 +433,53 @@ public class PerfettoTraceTest {
@Test
@RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
+ public void testProtoWithSlowPath() throws Exception {
+ TraceConfig traceConfig = getTraceConfig(FOO);
+
+ PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
+
+ PerfettoTrace.instant(FOO_CATEGORY, "event_proto")
+ .beginProto()
+ .beginNested(33L)
+ .addField(4L, 2L)
+ .addField(3, TEXT_ABOVE_4K_SIZE)
+ .endNested()
+ .addField(2001, "AIDL::IActivityManager")
+ .endProto()
+ .emit();
+
+ byte[] traceBytes = session.close();
+
+ Trace trace = Trace.parseFrom(traceBytes);
+
+ boolean hasTrackEvent = false;
+ boolean hasSourceLocation = false;
+ for (TracePacket packet: trace.getPacketList()) {
+ TrackEvent event;
+ if (packet.hasTrackEvent()) {
+ hasTrackEvent = true;
+ event = packet.getTrackEvent();
+
+ if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType())
+ && event.hasSourceLocation()) {
+ SourceLocation loc = event.getSourceLocation();
+ if (TEXT_ABOVE_4K_SIZE.equals(loc.getFunctionName())
+ && loc.getLineNumber() == 2) {
+ hasSourceLocation = true;
+ }
+ }
+ }
+
+ collectInternedData(packet);
+ }
+
+ assertThat(hasTrackEvent).isTrue();
+ assertThat(hasSourceLocation).isTrue();
+ assertThat(mCategoryNames).contains(FOO);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
public void testProtoNested() throws Exception {
TraceConfig traceConfig = getTraceConfig(FOO);
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index a289df0441e5..c40137f1bd34 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -16,8 +16,6 @@
package android.view;
-import static android.app.UiModeManager.MODE_NIGHT_NO;
-import static android.app.UiModeManager.MODE_NIGHT_YES;
import static android.util.SequenceUtils.getInitSeq;
import static android.view.HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING;
import static android.view.InputDevice.SOURCE_ROTARY_ENCODER;
@@ -69,10 +67,8 @@ import static org.junit.Assume.assumeTrue;
import android.annotation.NonNull;
import android.app.Instrumentation;
import android.app.UiModeManager;
-import android.app.UiModeManager.ForceInvertType;
import android.content.Context;
import android.graphics.ForceDarkType;
-import android.graphics.ForceDarkType.ForceDarkTypeDef;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
@@ -97,12 +93,9 @@ import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.ShellIdentityUtils;
-import com.android.compatibility.common.util.TestUtils;
import com.android.cts.input.BlockingQueueEventVerifier;
import com.android.window.flags.Flags;
-import com.google.common.truth.Expect;
-
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.AfterClass;
@@ -131,8 +124,6 @@ public class ViewRootImplTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
- @Rule
- public final Expect mExpect = Expect.create();
private ViewRootImpl mViewRootImpl;
private View mView;
@@ -1516,34 +1507,49 @@ public class ViewRootImplTest {
}
@Test
- @RequiresFlagsEnabled(FLAG_FORCE_INVERT_COLOR)
- public void updateConfiguration_returnsExpectedForceDarkMode() {
- waitForSystemNightModeActivated(true);
-
- verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ true,
- UiModeManager.FORCE_INVERT_TYPE_DARK, ForceDarkType.FORCE_INVERT_COLOR_DARK);
- verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ false,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
- verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ true,
- UiModeManager.FORCE_INVERT_TYPE_DARK, ForceDarkType.FORCE_INVERT_COLOR_DARK);
- verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ false,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
-
- waitForSystemNightModeActivated(false);
-
- verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ true,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
- verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ false,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
- verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ true,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
- verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ false,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
+ public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() {
+ mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
+ ShellIdentityUtils.invokeWithShellPermissions(() -> {
+ Settings.Secure.putInt(
+ sContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
+ /* value= */ 0
+ );
+ var uiModeManager = sContext.getSystemService(UiModeManager.class);
+ uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
+ });
+
+ sInstrumentation.runOnMainSync(() ->
+ mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
+ );
+
+ assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.NONE);
+ }
+
+ @Test
+ public void forceInvertOnDarkThemeOff_forceDarkModeEnabled() {
+ mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
+ ShellIdentityUtils.invokeWithShellPermissions(() -> {
+ Settings.Secure.putInt(
+ sContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
+ /* value= */ 1
+ );
+ var uiModeManager = sContext.getSystemService(UiModeManager.class);
+ uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
+ });
+
+ sInstrumentation.runOnMainSync(() ->
+ mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
+ );
+
+ assertThat(mViewRootImpl.determineForceDarkType())
+ .isEqualTo(ForceDarkType.FORCE_INVERT_COLOR_DARK);
}
@Test
- @EnableFlags(FLAG_FORCE_INVERT_COLOR)
public void forceInvertOffForceDarkOff_forceDarkModeDisabled() {
+ mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
ShellIdentityUtils.invokeWithShellPermissions(() -> {
Settings.Secure.putInt(
sContext.getContentResolver(),
@@ -1556,14 +1562,15 @@ public class ViewRootImplTest {
});
sInstrumentation.runOnMainSync(() ->
- mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()));
+ mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
+ );
assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.NONE);
}
@Test
- @EnableFlags(FLAG_FORCE_INVERT_COLOR)
public void forceInvertOffForceDarkOn_forceDarkModeEnabled() {
+ mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
ShellIdentityUtils.invokeWithShellPermissions(() -> {
Settings.Secure.putInt(
sContext.getContentResolver(),
@@ -1575,7 +1582,8 @@ public class ViewRootImplTest {
});
sInstrumentation.runOnMainSync(() ->
- mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()));
+ mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
+ );
assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.FORCE_DARK);
}
@@ -1782,39 +1790,4 @@ public class ViewRootImplTest {
() -> view.getViewTreeObserver().removeOnDrawListener(listener));
}
}
-
- private void waitForSystemNightModeActivated(boolean active) {
- ShellIdentityUtils.invokeWithShellPermissions(() ->
- sInstrumentation.runOnMainSync(() -> {
- var uiModeManager = sContext.getSystemService(UiModeManager.class);
- uiModeManager.setNightModeActivated(active);
- }));
- sInstrumentation.waitForIdleSync();
- }
-
- private void verifyForceDarkType(boolean isAppInNightMode, boolean isForceInvertEnabled,
- @ForceInvertType int expectedForceInvertType,
- @ForceDarkTypeDef int expectedForceDarkType) {
- var uiModeManager = sContext.getSystemService(UiModeManager.class);
- ShellIdentityUtils.invokeWithShellPermissions(() -> {
- uiModeManager.setApplicationNightMode(
- isAppInNightMode ? MODE_NIGHT_YES : MODE_NIGHT_NO);
- Settings.Secure.putInt(
- sContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
- isForceInvertEnabled ? 1 : 0);
- });
-
- sInstrumentation.runOnMainSync(() ->
- mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()));
- try {
- TestUtils.waitUntil("Waiting for force invert state changed",
- () -> (uiModeManager.getForceInvertState() == expectedForceInvertType));
- } catch (Exception e) {
- Log.e(TAG, "Unexpected error trying to apply force invert state. " + e);
- e.printStackTrace();
- }
-
- mExpect.that(mViewRootImpl.determineForceDarkType()).isEqualTo(expectedForceDarkType);
- }
}
diff --git a/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java b/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java
new file mode 100644
index 000000000000..c66e10079bc8
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2025 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.view;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.testng.AssertJUnit.assertEquals;
+
+import android.graphics.Rect;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewRootRectTrackerTest {
+ private ViewRootRectTracker mTracker;
+ private final List<Rect> mRects = Lists.newArrayList(new Rect(0, 0, 5, 5),
+ new Rect(5, 5, 10, 10));
+
+ @Before
+ public void setUp() {
+ mTracker = new ViewRootRectTracker(v -> Collections.emptyList());
+ }
+
+ @Test
+ public void setRootRectsAndComputeTest() {
+ mTracker.setRootRects(mRects);
+ mTracker.computeChanges();
+ assertEquals(mRects, mTracker.getLastComputedRects());
+ }
+
+ @Test
+ public void waitingForComputeChangesTest() {
+ mTracker.setRootRects(mRects);
+ assertTrue(mTracker.isWaitingForComputeChanges());
+ mTracker.computeChangedRects();
+ assertFalse(mTracker.isWaitingForComputeChanges());
+
+ View mockView = mock(View.class);
+ mTracker.updateRectsForView(mockView);
+ assertTrue(mTracker.isWaitingForComputeChanges());
+ mTracker.computeChangedRects();
+ assertFalse(mTracker.isWaitingForComputeChanges());
+ }
+}
diff --git a/graphics/java/android/framework_graphics.aconfig b/graphics/java/android/framework_graphics.aconfig
index a63cbee4d707..fdbee3ccbebe 100644
--- a/graphics/java/android/framework_graphics.aconfig
+++ b/graphics/java/android/framework_graphics.aconfig
@@ -42,3 +42,11 @@ flag {
description: "Add DISPLAY_BT2020 ColorSpace support"
bug: "344038816"
}
+
+flag {
+ name: "gradient_drawable_shape_rounded_cap"
+ is_fixed_read_only: true
+ namespace: "core_graphics"
+ description: "Make GradientDrawable support drawing ring with rounded stroke cap."
+ bug: "380000245"
+}
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 65854dd51a91..ef6b72871415 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -658,6 +658,13 @@ public class HardwareRenderer {
}
/**
+ * @hide
+ */
+ public void addObserver(long nativeObserver) {
+ nAddObserver(mNativeProxy, nativeObserver);
+ }
+
+ /**
* TODO: Public API this?
*
* @hide
@@ -667,6 +674,13 @@ public class HardwareRenderer {
}
/**
+ * @hide
+ */
+ public void removeObserver(long nativeObserver) {
+ nRemoveObserver(mNativeProxy, nativeObserver);
+ }
+
+ /**
* Sets the desired color mode on this renderer. Whether or not the actual rendering
* will use the requested colorMode depends on the hardware support for such rendering.
*
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 29d033e64aea..ff1dc93d787b 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -16,7 +16,11 @@
package android.graphics.drawable;
+import static com.android.graphics.flags.Flags.FLAG_GRADIENT_DRAWABLE_SHAPE_ROUNDED_CAP;
+import static com.android.graphics.flags.Flags.gradientDrawableShapeRoundedCap;
+
import android.annotation.ColorInt;
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -125,8 +129,14 @@ public class GradientDrawable extends Drawable {
*/
public static final int RING = 3;
+ /**
+ * Shape is an arc.
+ */
+ @FlaggedApi(FLAG_GRADIENT_DRAWABLE_SHAPE_ROUNDED_CAP)
+ public static final int ARC = 4;
+
/** @hide */
- @IntDef({RECTANGLE, OVAL, LINE, RING})
+ @IntDef({RECTANGLE, OVAL, LINE, RING, ARC})
@Retention(RetentionPolicy.SOURCE)
public @interface Shape {}
@@ -167,6 +177,17 @@ public class GradientDrawable extends Drawable {
@Retention(RetentionPolicy.SOURCE)
public @interface RadiusType {}
+ private static final int BUTT = 0;
+
+ private static final int ROUND = 1;
+
+ private static final int SQUARE = 2;
+
+ /** @hide */
+ @IntDef({BUTT, ROUND, SQUARE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StrokeCap {}
+
private static final float DEFAULT_INNER_RADIUS_RATIO = 3.0f;
private static final float DEFAULT_THICKNESS_RATIO = 9.0f;
@@ -191,6 +212,8 @@ public class GradientDrawable extends Drawable {
private boolean mMutated;
private Path mRingPath;
private boolean mPathIsDirty = true;
+ private Path mArcPath;
+ private Path mArcOutlinePath;
/** Current gradient radius, valid when {@link #mGradientIsDirty} is false. */
private float mGradientRadius;
@@ -850,6 +873,55 @@ public class GradientDrawable extends Drawable {
}
break;
}
+ case ARC:
+ if (gradientDrawableShapeRoundedCap()) {
+ // TODO(b/394988176): Consider applying ARC drawing logic to RING shape.
+ float centerX = mRect.centerX();
+ float centerY = mRect.centerY();
+ float thickness =
+ st.mThickness != -1 ? st.mThickness
+ : mRect.width() / st.mThicknessRatio;
+ float radius = st.mInnerRadius != -1 ? st.mInnerRadius
+ : mRect.width() / st.mInnerRadiusRatio;
+ radius -= thickness;
+ float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
+ mRect.set(centerX - radius, centerY - radius, centerX + radius,
+ centerY + radius);
+
+ // Prepare paint. Set style to STROKE for purpose of drawing line ARC.
+ mFillPaint.setStyle(Paint.Style.STROKE);
+ mFillPaint.setStrokeWidth(thickness);
+ mFillPaint.setStrokeCap(getStrokeLineCapForPaint(st.mStrokeCap));
+ canvas.drawArc(mRect, 0.0f, sweep, /* useCenter= */ false, mFillPaint);
+
+ if (haveStroke) {
+ if (mArcPath == null) {
+ mArcPath = new Path();
+ } else {
+ mArcPath.reset();
+ }
+ if (mArcOutlinePath == null) {
+ mArcOutlinePath = new Path();
+ } else {
+ mArcOutlinePath.reset();
+ }
+ if (sweep == 360f) {
+ mArcPath.addOval(mRect, Path.Direction.CW);
+ } else {
+ mArcPath.arcTo(mRect, 0.0f, sweep, /* forceMoveTo= */ false);
+ }
+
+ // The arc path doesn't have width. So, to get the outline of the result arc
+ // shape, we need to apply the paint effect to the path; then use the
+ // output as the result outline.
+ mFillPaint.getFillPath(mArcPath, mArcOutlinePath);
+ canvas.drawPath(mArcOutlinePath, mStrokePaint);
+ }
+
+ // Restore to FILL
+ mFillPaint.setStyle(Paint.Style.FILL);
+ break;
+ }
case RING:
Path path = buildRing(st);
canvas.drawPath(path, mFillPaint);
@@ -993,6 +1065,36 @@ public class GradientDrawable extends Drawable {
}
/**
+ * Return current drawable's stroke line cap. Note that this is only respected when drawable is
+ * {@link Shape#ARC}.
+ *
+ * @return the {@link StrokeCap} of current drawable.
+ * @attr ref android.R.styleable#GradientDrawable_strokeCap
+ * @see #setStrokeCap(int)
+ *
+ * @hide
+ */
+ @StrokeCap
+ public int getStrokeCap() {
+ return mGradientState.mStrokeCap;
+ }
+
+ /**
+ * Configure the stroke line cap type that drawable will use while drawing. Note that this is
+ * only respected when drawable is {@link Shape#ARC}.
+ *
+ * @param strokeCapType the stroke line cap type that the drawable will use while drawing.
+ * @attr ref android.R.styleable#GradientDrawable_strokeCap
+ * @see #getStrokeCap
+ *
+ * @hide
+ */
+ public void setStrokeCap(@StrokeCap int strokeCapType) {
+ mGradientState.mStrokeCap = strokeCapType;
+ invalidateSelf();
+ }
+
+ /**
* Configure the padding of the gradient shape
* @param left Left padding of the gradient shape
* @param top Top padding of the gradient shape
@@ -1066,6 +1168,15 @@ public class GradientDrawable extends Drawable {
return ringPath;
}
+ private Paint.Cap getStrokeLineCapForPaint(@StrokeCap int strokeLineCap) {
+ return switch (strokeLineCap) {
+ case BUTT -> Paint.Cap.BUTT;
+ case ROUND -> Paint.Cap.ROUND;
+ case SQUARE -> Paint.Cap.SQUARE;
+ default -> Paint.Cap.SQUARE;
+ };
+ }
+
/**
* Changes this drawable to use a single color instead of a gradient.
* <p>
@@ -1484,7 +1595,7 @@ public class GradientDrawable extends Drawable {
state.mShape = a.getInt(R.styleable.GradientDrawable_shape, state.mShape);
state.mDither = a.getBoolean(R.styleable.GradientDrawable_dither, state.mDither);
- if (state.mShape == RING) {
+ if (state.mShape == RING || state.mShape == ARC) {
state.mInnerRadius = a.getDimensionPixelSize(
R.styleable.GradientDrawable_innerRadius, state.mInnerRadius);
@@ -1503,6 +1614,9 @@ public class GradientDrawable extends Drawable {
state.mUseLevelForShape = a.getBoolean(
R.styleable.GradientDrawable_useLevel, state.mUseLevelForShape);
+
+ state.mStrokeCap = a.getInt(
+ R.styleable.GradientDrawable_strokeCap, state.mStrokeCap);
}
final int tintMode = a.getInt(R.styleable.GradientDrawable_tintMode, -1);
@@ -2045,6 +2159,9 @@ public class GradientDrawable extends Drawable {
public int mInnerRadius = -1;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050218)
public int mThickness = -1;
+ @UnsupportedAppUsage(trackingBug = 380000245)
+ @StrokeCap public int mStrokeCap = ROUND;
+
public boolean mDither = false;
public Insets mOpticalInsets = Insets.NONE;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index f6a2c8d9695e..305fcdd5fb7d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -912,7 +912,7 @@ public class BubbleController implements ConfigurationChangeListener,
// TODO(b/393172431) : Utilise DragZoneFactory once it is ready
final int bubbleBarDropZoneSideSize = getContext().getResources().getDimensionPixelSize(
R.dimen.bubble_bar_drop_zone_side_size);
- int top = t - bubbleBarDropZoneSideSize;
+ int top = b - bubbleBarDropZoneSideSize;
result.put(BubbleBarLocation.LEFT,
new Rect(l, top, l + bubbleBarDropZoneSideSize, b));
result.put(BubbleBarLocation.RIGHT,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index e3b0872df593..29837dc04423 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -135,6 +135,7 @@ public class BubbleBarLayerView extends FrameLayout
/** Shows the expanded view drop target at the requested {@link BubbleBarLocation location} */
public void showBubbleBarExtendedViewDropTarget(@NonNull BubbleBarLocation bubbleBarLocation) {
+ setVisibility(VISIBLE);
mBubbleExpandedViewPinController.showDropTarget(bubbleBarLocation);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index b46051c51fcc..cb231800bd63 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -43,7 +43,7 @@ import com.android.wm.shell.bubbles.BubbleTransitions
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP
-import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.shared.TransitionUtil
import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
@@ -120,10 +120,7 @@ sealed class DragToDesktopTransitionHandler(
dragToDesktopAnimator: MoveToDesktopAnimator,
) {
if (inProgress) {
- ProtoLog.v(
- ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
- "DragToDesktop: Drag to desktop transition already in progress.",
- )
+ logV("Drag to desktop transition already in progress.")
return
}
@@ -537,12 +534,14 @@ sealed class DragToDesktopTransitionHandler(
state.cancelState == CancelState.CANCEL_SPLIT_LEFT ||
state.cancelState == CancelState.CANCEL_SPLIT_RIGHT
) {
+ logV("mergeAnimation: cancel through split")
clearState()
return
}
// In case of bubble animation, finish the initial desktop drag animation, but keep the
// current animation running and have bubbles take over
if (info.type == TRANSIT_CONVERT_TO_BUBBLE) {
+ logV("mergeAnimation: convert-to-bubble")
state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null)
clearState()
return
@@ -562,6 +561,7 @@ sealed class DragToDesktopTransitionHandler(
state.startTransitionFinishCb
?: error("Start transition expected to be waiting for merge but wasn't")
if (isEndTransition) {
+ logV("mergeAnimation: end-transition, target=$mergeTarget")
setupEndDragToDesktop(
info,
startTransaction = startT,
@@ -572,7 +572,10 @@ sealed class DragToDesktopTransitionHandler(
LatencyTracker.getInstance(context)
.onActionEnd(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG)
animateEndDragToDesktop(startTransaction = startT, startTransitionFinishCb)
- } else if (isCancelTransition) {
+ return
+ }
+ if (isCancelTransition) {
+ logV("mergeAnimation: cancel-transition, target=$mergeTarget")
LatencyTracker.getInstance(context)
.onActionCancel(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG)
info.changes.forEach { change ->
@@ -583,7 +586,9 @@ sealed class DragToDesktopTransitionHandler(
finishCallback.onTransitionFinished(/* wct= */ null)
startTransitionFinishCb.onTransitionFinished(/* wct= */ null)
clearState()
+ return
}
+ logW("unhandled merge transition: transitionInfo=$info")
}
protected open fun setupEndDragToDesktop(
@@ -724,10 +729,7 @@ sealed class DragToDesktopTransitionHandler(
return
}
if (state.startTransitionToken == transition) {
- ProtoLog.v(
- ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
- "DragToDesktop: onTransitionConsumed() start transition aborted",
- )
+ logV("onTransitionConsumed() start transition aborted")
state.startAborted = true
// The start-transition (DRAG_HOLD) is aborted, cancel its jank interaction.
interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
@@ -950,7 +952,16 @@ sealed class DragToDesktopTransitionHandler(
CANCEL_BUBBLE_RIGHT,
}
+ private fun logV(msg: String, vararg arguments: Any?) {
+ ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
+
+ private fun logW(msg: String, vararg arguments: Any?) {
+ ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
+
companion object {
+ private const val TAG = "DragToDesktopTransitionHandler"
/** The duration of the animation to commit or cancel the drag-to-desktop gesture. */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
const val DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS = 336L
@@ -1052,10 +1063,7 @@ constructor(
val state = requireTransitionState()
val homeLeash = state.homeChange?.leash
if (homeLeash == null) {
- ProtoLog.e(
- ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
- "DragToDesktop: home leash is null",
- )
+ logE("home leash is null")
} else {
// Hide home on finish to prevent flickering when wallpaper activity flag is enabled
finishTransaction.hide(homeLeash)
@@ -1096,6 +1104,12 @@ constructor(
val startBoundsWithOffset =
Rect(startBounds).apply { offset(startPosition.x.toInt(), startPosition.y.toInt()) }
+ logV(
+ "animateEndDragToDesktop: startBounds=$startBounds, endBounds=$endBounds, " +
+ "startScale=$startScale, startPosition=$startPosition, " +
+ "startBoundsWithOffset=$startBoundsWithOffset"
+ )
+
dragToDesktopStateListener?.onCommitToDesktopAnimationStart()
// Accept the merge by applying the merging transaction (applied by #showResizeVeil)
// and finish callback. Show the veil and position the task at the first frame before
@@ -1177,7 +1191,16 @@ constructor(
.start()
}
+ private fun logV(msg: String, vararg arguments: Any?) {
+ ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
+
+ private fun logE(msg: String, vararg arguments: Any?) {
+ ProtoLog.e(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
+
companion object {
+ private const val TAG = "SpringDragToDesktopTransitionHandler"
/** The freeform tasks initial scale when committing the drag-to-desktop gesture. */
private val FREEFORM_TASKS_INITIAL_SCALE =
propertyValue("freeform_tasks_initial_scale", scale = 100f, default = 0.9f)
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index f5e10d94452f..7a51c20f7672 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -44,6 +44,9 @@ namespace android {
namespace {
+constexpr int32_t kDefaultDisplayId = 0;
+constexpr int32_t kDefaultDeviceId = 0;
+
using EntryValue = std::variant<Res_value, incfs::verified_map_ptr<ResTable_map_entry>>;
/* NOTE: table_entry has been verified in LoadedPackage::GetEntryFromOffset(),
@@ -61,7 +64,7 @@ base::expected<EntryValue, IOError> GetEntryValue(
return table_entry->value();
}
-} // namespace
+} // namespace
struct FindEntryResult {
// The cookie representing the ApkAssets in which the value resides.
@@ -99,14 +102,15 @@ struct Theme::Entry {
Res_value value;
};
-AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration) {
+AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration)
+ : display_id_(kDefaultDisplayId), device_id_(kDefaultDeviceId) {
configurations_.push_back(configuration);
// Don't invalidate caches here as there's nothing cached yet.
SetApkAssets(apk_assets, false);
}
-AssetManager2::AssetManager2() {
+AssetManager2::AssetManager2() : display_id_(kDefaultDisplayId), device_id_(kDefaultDeviceId) {
configurations_.emplace_back();
}
@@ -172,8 +176,7 @@ void AssetManager2::BuildDynamicRefTable(ApkAssetsList apk_assets) {
// to take effect.
auto iter = target_assets_package_ids.find(loaded_idmap->TargetApkPath());
if (iter == target_assets_package_ids.end()) {
- LOG(INFO) << "failed to find target package for overlay "
- << loaded_idmap->OverlayApkPath();
+ LOG(INFO) << "failed to find target package for overlay " << loaded_idmap->OverlayApkPath();
} else {
uint8_t target_package_id = iter->second;
@@ -189,10 +192,11 @@ void AssetManager2::BuildDynamicRefTable(ApkAssetsList apk_assets) {
<< " assigned package group";
PackageGroup& target_package_group = package_groups_[target_idx];
- target_package_group.overlays_.push_back(
- ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id,
- overlay_ref_table.get()),
- apk_assets_cookies[apk_assets]});
+ target_package_group.overlays_.push_back(ConfiguredOverlay{
+ loaded_idmap->GetTargetResourcesMap(target_package_id, overlay_ref_table.get()),
+ apk_assets_cookies[apk_assets],
+ IsAnyOverlayConstraintSatisfied(loaded_idmap->GetConstraints())
+ });
}
}
@@ -291,7 +295,7 @@ void AssetManager2::DumpToLog() const {
}
LOG(INFO) << "Package ID map: " << list;
- for (const auto& package_group: package_groups_) {
+ for (const auto& package_group : package_groups_) {
list = "";
for (const auto& package : package_group.packages_) {
const LoadedPackage* loaded_package = package.loaded_package_;
@@ -347,7 +351,6 @@ std::shared_ptr<const DynamicRefTable> AssetManager2::GetDynamicRefTableForCooki
const std::unordered_map<std::string, std::string>*
AssetManager2::GetOverlayableMapForPackage(uint32_t package_id) const {
-
if (package_id >= package_ids_.size()) {
return nullptr;
}
@@ -462,6 +465,28 @@ void AssetManager2::SetConfigurations(std::span<const ResTable_config> configura
}
}
+void AssetManager2::SetOverlayConstraints(int32_t display_id, int32_t device_id) {
+ bool changed = false;
+ if (display_id_ != display_id) {
+ display_id_ = display_id;
+ changed = true;
+ }
+ if (device_id_ != device_id) {
+ device_id_ = device_id;
+ changed = true;
+ }
+ if (changed) {
+ // Enable/disable overlays based on current constraints
+ for (PackageGroup& group : package_groups_) {
+ for (auto &overlay: group.overlays_) {
+ overlay.enabled = IsAnyOverlayConstraintSatisfied(
+ overlay.overlay_res_maps_.GetConstraints());
+ }
+ }
+ InvalidateCaches(static_cast<uint32_t>(-1));
+ }
+}
+
std::set<AssetManager2::ApkAssetsPtr> AssetManager2::GetNonSystemOverlays() const {
std::set<ApkAssetsPtr> non_system_overlays;
for (const PackageGroup& package_group : package_groups_) {
@@ -475,6 +500,8 @@ std::set<AssetManager2::ApkAssetsPtr> AssetManager2::GetNonSystemOverlays() cons
if (!found_system_package) {
auto op = StartOperation();
+ // Return all overlays, including the disabled ones as this is used for static info
+ // collection only.
for (const ConfiguredOverlay& overlay : package_group.overlays_) {
if (const auto& asset = GetApkAssets(overlay.cookie)) {
non_system_overlays.insert(std::move(asset));
@@ -651,7 +678,6 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
auto op = StartOperation();
-
// Retrieve the package group from the package id of the resource id.
if (UNLIKELY(!is_valid_resid(resid))) {
LOG(ERROR) << base::StringPrintf("Invalid resource ID 0x%08x.", resid);
@@ -672,7 +698,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
std::optional<FindEntryResult> final_result;
bool final_has_locale = false;
bool final_overlaid = false;
- for (auto & config : configurations_) {
+ for (auto& config : configurations_) {
// Might use this if density_override != 0.
ResTable_config density_override_config;
@@ -698,7 +724,8 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
}
if (!assets->IsLoader()) {
for (const auto& id_map : package_group.overlays_) {
- auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
+ auto overlay_entry = id_map.enabled ?
+ id_map.overlay_res_maps_.Lookup(resid) : IdmapResMap::Result();
if (!overlay_entry) {
// No id map entry exists for this target resource.
continue;
@@ -708,7 +735,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
ConfigDescription best_frro_config;
Res_value best_frro_value;
bool frro_found = false;
- for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
+ for (const auto& [config, value] : overlay_entry.GetInlineValue()) {
if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
&& config.match(*desired_config)) {
frro_found = true;
@@ -1011,7 +1038,7 @@ std::string AssetManager2::GetLastResourceResolution() const {
resid, resource_name_string.c_str(), conf.toString().c_str());
char str[40];
str[0] = '\0';
- for(auto iter = configurations_.begin(); iter < configurations_.end(); iter++) {
+ for (auto iter = configurations_.begin(); iter < configurations_.end(); iter++) {
iter->getBcp47Locale(str);
log_stream << base::StringPrintf(" %s%s", str, iter < configurations_.end() ? "," : "");
}
@@ -1504,7 +1531,7 @@ void AssetManager2::RebuildFilterList() {
package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
FilteredConfigGroup* group = nullptr;
for (const auto& type_entry : type_spec.type_entries) {
- for (auto & config : configurations_) {
+ for (auto& config : configurations_) {
if (type_entry.config.match(config)) {
if (!group) {
group = &package.filtered_configs_.editItemAt(type_id - 1);
@@ -1521,6 +1548,27 @@ void AssetManager2::RebuildFilterList() {
}
}
+bool AssetManager2::IsAnyOverlayConstraintSatisfied(const Idmap_constraints& constraints) const {
+ if (constraints.constraint_count == 0) {
+ // There are no constraints, return true.
+ return true;
+ }
+
+ for (uint32_t i = 0; i < constraints.constraint_count; i++) {
+ auto constraint = constraints.constraint_entries[i];
+ if (constraint.constraint_type == kOverlayConstraintTypeDisplayId &&
+ constraint.constraint_value == display_id_) {
+ return true;
+ }
+ if (constraint.constraint_type == kOverlayConstraintTypeDeviceId &&
+ constraint.constraint_value == device_id_) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void AssetManager2::InvalidateCaches(uint32_t diff) {
cached_resolved_values_.clear();
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index f0ef97e5bdcc..8d1de1af56d2 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -56,13 +56,6 @@ struct Idmap_header {
// without having to read/store each header entry separately.
};
-struct Idmap_constraint {
- // Constraint type can be TYPE_DISPLAY_ID or TYP_DEVICE_ID, please refer
- // to ConstraintType in OverlayConstraint.java
- uint32_t constraint_type;
- uint32_t constraint_value;
-};
-
struct Idmap_data_header {
uint32_t target_entry_count;
uint32_t target_inline_entry_count;
@@ -148,12 +141,13 @@ status_t OverlayDynamicRefTable::lookupResourceIdNoRewrite(uint32_t* resId) cons
return DynamicRefTable::lookupResourceId(resId);
}
-IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries,
- Idmap_target_inline_entries inline_entries,
+IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, const Idmap_constraints& constraints,
+ Idmap_target_entries entries, Idmap_target_inline_entries inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values,
const ConfigDescription* configs, uint8_t target_assigned_package_id,
const OverlayDynamicRefTable* overlay_ref_table)
: data_header_(data_header),
+ constraints_(constraints),
entries_(entries),
inline_entries_(inline_entries),
inline_entry_values_(inline_entry_values),
@@ -254,7 +248,7 @@ std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size
}
return std::string_view(data, *len);
}
-} // namespace
+} // namespace
// O_PATH is a lightweight way of creating an FD, only exists on Linux
#ifndef O_PATH
@@ -262,9 +256,7 @@ std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size
#endif
LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
- const Idmap_constraint* constraints,
- uint32_t constraints_count,
- const Idmap_data_header* data_header,
+ const Idmap_data_header* data_header, const Idmap_constraints& constraints,
Idmap_target_entries target_entries,
Idmap_target_inline_entries target_inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values,
@@ -272,9 +264,8 @@ LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* head
std::unique_ptr<ResStringPool>&& string_pool,
std::string_view overlay_apk_path, std::string_view target_apk_path)
: header_(header),
- constraints_(constraints),
- constraints_count_(constraints_count),
data_header_(data_header),
+ constraints_(constraints),
target_entries_(target_entries),
target_inline_entries_(target_inline_entries),
inline_entry_values_(inline_entry_values),
@@ -328,16 +319,20 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie
return {};
}
- auto constraints_count = ReadType<uint32_t>(&data_ptr, &data_size, "constraints count");
- if (!constraints_count) {
+ auto constraint_count = ReadType<uint32_t>(&data_ptr, &data_size, "constraint count");
+ if (!constraint_count) {
+ LOG(ERROR) << "idmap doesn't have constraint count";
return {};
}
- auto constraints = *constraints_count > 0 ?
- ReadType<Idmap_constraint>(&data_ptr, &data_size, "constraints", *constraints_count)
+ auto constraint_entries = *constraint_count > 0 ?
+ ReadType<Idmap_constraint>(&data_ptr, &data_size, "constraints", dtohl(*constraint_count))
: nullptr;
- if (*constraints_count > 0 && !constraints) {
+ if (*constraint_count > 0 && !constraint_entries) {
+ LOG(ERROR) << "no constraint entries in idmap with non-zero constraints";
return {};
}
+ Idmap_constraints constraints{.constraint_count = *constraint_count,
+ .constraint_entries = constraint_entries};
// Parse the idmap data blocks. Currently idmap2 can only generate one data block.
auto data_header = ReadType<Idmap_data_header>(&data_ptr, &data_size, "data header");
@@ -405,10 +400,9 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie
// Can't use make_unique because LoadedIdmap constructor is private.
return std::unique_ptr<LoadedIdmap>(
- new LoadedIdmap(std::string(idmap_path), header, constraints, *constraints_count,
- data_header, target_entries, target_inline_entries,
- target_inline_entry_values,configurations, overlay_entries,
- std::move(idmap_string_pool),*overlay_path, *target_path));
+ new LoadedIdmap(std::string(idmap_path), header, data_header, constraints, target_entries,
+ target_inline_entries, target_inline_entry_values, configurations,
+ overlay_entries, std::move(idmap_string_pool), *overlay_path, *target_path));
}
UpToDate LoadedIdmap::IsUpToDate() const {
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 0fdeefa09e26..a47fe6a7f50d 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -171,6 +171,8 @@ class AssetManager2 {
default_locale_ = default_locale;
}
+ void SetOverlayConstraints(int32_t display_id, int32_t device_id);
+
// Returns all configurations for which there are resources defined, or an I/O error if reading
// resource data failed.
//
@@ -389,6 +391,9 @@ class AssetManager2 {
// The cookie of the overlay assets.
ApkAssetsCookie cookie;
+
+ // Enable/disable status of the overlay based on current constraints of AssetManager.
+ bool enabled;
};
// Represents a logical package, which can be made up of many individual packages. Each package
@@ -457,6 +462,8 @@ class AssetManager2 {
// promoted apk assets when the last operation ends.
void FinishOperation() const;
+ bool IsAnyOverlayConstraintSatisfied(const Idmap_constraints& constraints) const;
+
// The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
// have a longer lifetime.
// The second pair element is the promoted version of the assets, that is held for the duration
@@ -480,6 +487,9 @@ class AssetManager2 {
// may need to be purged.
ftl::SmallVector<ResTable_config, 1> configurations_;
+ int32_t display_id_;
+ int32_t device_id_;
+
// Cached set of bags. These are cached because they can inherit keys from parent bags,
// which involves some calculation.
mutable std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index 0c0856315d8f..939b62462560 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -59,13 +59,25 @@ inline UpToDate fromBool(bool value) {
class LoadedIdmap;
class IdmapResMap;
struct Idmap_header;
-struct Idmap_constraint;
+struct Idmap_constraints;
struct Idmap_data_header;
-struct Idmap_target_entry;
struct Idmap_target_entry_inline;
struct Idmap_target_entry_inline_value;
-struct Idmap_overlay_entry;
+// LINT.IfChange
+constexpr int32_t kOverlayConstraintTypeDisplayId = 0;
+constexpr int32_t kOverlayConstraintTypeDeviceId = 1;
+// LINT.ThenChange(../../../../core/java/android/content/om/OverlayConstraint.java)
+
+struct Idmap_constraint {
+ // Constraint type can be kOverlayConstraintTypeDisplayId or kOverlayConstraintTypeDeviceId
+ const uint32_t constraint_type;
+ const uint32_t constraint_value;
+};
+struct Idmap_constraints {
+ const uint32_t constraint_count = 0;
+ const Idmap_constraint* constraint_entries = nullptr;
+};
struct Idmap_target_entries {
const uint32_t* target_id = nullptr;
const uint32_t* overlay_id = nullptr;
@@ -169,14 +181,19 @@ class IdmapResMap {
return overlay_ref_table_;
}
+ inline Idmap_constraints GetConstraints() const {
+ return constraints_;
+ }
+
private:
- explicit IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries,
- Idmap_target_inline_entries inline_entries,
+ explicit IdmapResMap(const Idmap_data_header* data_header, const Idmap_constraints& constraints,
+ Idmap_target_entries entries, Idmap_target_inline_entries inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values,
const ConfigDescription* configs, uint8_t target_assigned_package_id,
const OverlayDynamicRefTable* overlay_ref_table);
const Idmap_data_header* data_header_;
+ Idmap_constraints constraints_;
Idmap_target_entries entries_;
Idmap_target_inline_entries inline_entries_;
const Idmap_target_entry_inline_value* inline_entry_values_;
@@ -210,8 +227,9 @@ class LoadedIdmap {
// Returns a mapping from target resource ids to overlay values.
IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id,
const OverlayDynamicRefTable* overlay_ref_table) const {
- return IdmapResMap(data_header_, target_entries_, target_inline_entries_, inline_entry_values_,
- configurations_, target_assigned_package_id, overlay_ref_table);
+ return IdmapResMap(data_header_, constraints_, target_entries_, target_inline_entries_,
+ inline_entry_values_, configurations_, target_assigned_package_id,
+ overlay_ref_table);
}
// Returns a dynamic reference table for a loaded overlay package.
@@ -223,14 +241,17 @@ class LoadedIdmap {
// LoadedIdmap.
UpToDate IsUpToDate() const;
+ inline const Idmap_constraints GetConstraints() const {
+ return constraints_;
+ }
+
protected:
// Exposed as protected so that tests can subclass and mock this class out.
LoadedIdmap() = default;
const Idmap_header* header_;
- const Idmap_constraint* constraints_;
- uint32_t constraints_count_;
const Idmap_data_header* data_header_;
+ Idmap_constraints constraints_;
Idmap_target_entries target_entries_;
Idmap_target_inline_entries target_inline_entries_;
const Idmap_target_entry_inline_value* inline_entry_values_;
@@ -247,9 +268,7 @@ class LoadedIdmap {
DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
explicit LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
- const Idmap_constraint* constraints,
- uint32_t constraints_count,
- const Idmap_data_header* data_header,
+ const Idmap_data_header* data_header, const Idmap_constraints& constraints,
Idmap_target_entries target_entries,
Idmap_target_inline_entries target_inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values_,
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index fa09296f647c..0e52f4e177c5 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -52,7 +52,7 @@ const std::array FrameInfoNames{"Flags",
static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 24,
"Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
-void FrameInfo::importUiThreadInfo(int64_t* info) {
+void FrameInfo::importUiThreadInfo(const int64_t* info) {
memcpy(mFrameInfo.data(), info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
mSkippedFrameReason.reset();
}
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 8b486cd49e24..b1f479faadff 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -134,7 +134,7 @@ private:
class FrameInfo {
public:
- void importUiThreadInfo(int64_t* info);
+ void importUiThreadInfo(const int64_t* info);
void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(SYSTEM_TIME_MONOTONIC); }
diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h
index 0b0895aa3f3d..71b3f52fe12e 100644
--- a/libs/hwui/FrameMetricsReporter.h
+++ b/libs/hwui/FrameMetricsReporter.h
@@ -35,12 +35,12 @@ class FrameMetricsReporter {
public:
FrameMetricsReporter() {}
- void addObserver(FrameMetricsObserver* observer) {
+ void addObserver(sp<FrameMetricsObserver>&& observer) {
std::lock_guard lock(mObserversLock);
- mObservers.push_back(observer);
+ mObservers.push_back(std::move(observer));
}
- bool removeObserver(FrameMetricsObserver* observer) {
+ bool removeObserver(const sp<FrameMetricsObserver>& observer) {
std::lock_guard lock(mObserversLock);
for (size_t i = 0; i < mObservers.size(); i++) {
if (mObservers[i].get() == observer) {
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 99e7740d66d2..cfec24b17cd4 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -915,20 +915,22 @@ static jboolean android_view_ThreadedRenderer_isDrawingEnabled(JNIEnv*, jclass)
static void android_view_ThreadedRenderer_addObserver(JNIEnv* env, jclass clazz,
jlong proxyPtr, jlong observerPtr) {
- HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
+ FrameMetricsObserver* rawObserver = reinterpret_cast<FrameMetricsObserver*>(observerPtr);
+ sp<FrameMetricsObserver> observer = sp<FrameMetricsObserver>::fromExisting(rawObserver);
renderthread::RenderProxy* renderProxy =
reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
- renderProxy->addFrameMetricsObserver(observer);
+ renderProxy->addFrameMetricsObserver(std::move(observer));
}
static void android_view_ThreadedRenderer_removeObserver(JNIEnv* env, jclass clazz,
jlong proxyPtr, jlong observerPtr) {
- HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
+ FrameMetricsObserver* rawObserver = reinterpret_cast<FrameMetricsObserver*>(observerPtr);
+ sp<FrameMetricsObserver> observer = sp<FrameMetricsObserver>::fromExisting(rawObserver);
renderthread::RenderProxy* renderProxy =
reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
- renderProxy->removeFrameMetricsObserver(observer);
+ renderProxy->removeFrameMetricsObserver(std::move(observer));
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e3e393c4fdfb..b248c4bc9ade 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -859,7 +859,7 @@ void CanvasContext::reportMetricsWithPresentTime() {
} // release lock
}
-void CanvasContext::addFrameMetricsObserver(FrameMetricsObserver* observer) {
+void CanvasContext::addFrameMetricsObserver(sp<FrameMetricsObserver>&& observer) {
std::scoped_lock lock(mFrameInfoMutex);
if (mFrameMetricsReporter.get() == nullptr) {
mFrameMetricsReporter.reset(new FrameMetricsReporter());
@@ -870,10 +870,10 @@ void CanvasContext::addFrameMetricsObserver(FrameMetricsObserver* observer) {
// their frame metrics.
uint64_t nextFrameNumber = getFrameNumber();
observer->reportMetricsFrom(nextFrameNumber, mSurfaceControlGenerationId);
- mFrameMetricsReporter->addObserver(observer);
+ mFrameMetricsReporter->addObserver(std::move(observer));
}
-void CanvasContext::removeFrameMetricsObserver(FrameMetricsObserver* observer) {
+void CanvasContext::removeFrameMetricsObserver(const sp<FrameMetricsObserver>& observer) {
std::scoped_lock lock(mFrameInfoMutex);
if (mFrameMetricsReporter.get() != nullptr) {
mFrameMetricsReporter->removeObserver(observer);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index cb3753822035..f119102dc2a2 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -176,8 +176,8 @@ public:
void setContentDrawBounds(const Rect& bounds) { mContentDrawBounds = bounds; }
- void addFrameMetricsObserver(FrameMetricsObserver* observer);
- void removeFrameMetricsObserver(FrameMetricsObserver* observer);
+ void addFrameMetricsObserver(sp<FrameMetricsObserver>&& observer);
+ void removeFrameMetricsObserver(const sp<FrameMetricsObserver>& observer);
// Used to queue up work that needs to be completed before this frame completes
void enqueueFrameWork(std::function<void()>&& func);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 77879cf992b7..ebfd8fde91f6 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -420,15 +420,15 @@ void RenderProxy::setFrameCompleteCallback(std::function<void()>&& callback) {
mDrawFrameTask.setFrameCompleteCallback(std::move(callback));
}
-void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
- mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
- mContext->addFrameMetricsObserver(observer.get());
+void RenderProxy::addFrameMetricsObserver(sp<FrameMetricsObserver>&& observer) {
+ mRenderThread.queue().post([this, observer = std::move(observer)]() mutable {
+ mContext->addFrameMetricsObserver(std::move(observer));
});
}
-void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
- mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
- mContext->removeFrameMetricsObserver(observer.get());
+void RenderProxy::removeFrameMetricsObserver(sp<FrameMetricsObserver>&& observer) {
+ mRenderThread.queue().post([this, observer = std::move(observer)]() {
+ mContext->removeFrameMetricsObserver(observer);
});
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index f2d8e94c7bd2..ad6d54bfcf91 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -141,8 +141,8 @@ public:
void setFrameCommitCallback(std::function<void(bool)>&& callback);
void setFrameCompleteCallback(std::function<void()>&& callback);
- void addFrameMetricsObserver(FrameMetricsObserver* observer);
- void removeFrameMetricsObserver(FrameMetricsObserver* observer);
+ void addFrameMetricsObserver(sp<FrameMetricsObserver>&& observer);
+ void removeFrameMetricsObserver(sp<FrameMetricsObserver>&& observer);
void setForceDark(ForceDarkType type);
static void copySurfaceInto(ANativeWindow* window, std::shared_ptr<CopyRequest>&& request);
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 88981eac9bb5..1cb540b09fb3 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -481,9 +481,9 @@ public final class MediaRoute2Info implements Parcelable {
/**
* Indicates that a route supports routing playback to remote routes through control commands.
*
- * <p>This type of routing does not affect affect this system's audio or video, but instead
- * relies on the device that corresponds to this route to fetch and play the media. It also
- * requires the media app to take care of initializing and controlling playback.
+ * <p>This type of routing does not affect this system's audio or video, but instead relies on
+ * the device that corresponds to this route to fetch and play the media. It also requires the
+ * media app to take care of initializing and controlling playback.
*/
@FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
public static final int FLAG_ROUTING_TYPE_REMOTE = 1 << 2;
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index e94fb7d9e52b..4ae8daa63e1d 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -348,18 +348,21 @@ public abstract class MediaRoute2ProviderService extends Service {
* <p>This method must only be called as the result of a prior call to {@link
* #onCreateSystemRoutingSession}.
*
+ * <p>This method returns a {@link MediaStreams} instance that holds the media streams to route
+ * as part of the newly created routing session. May be null if system media capture failed, in
+ * which case you can ignore the return value, as you will receive a call to {@link
+ * #onReleaseSession} where you can clean up this session. {@link AudioRecord#startRecording()}
+ * must be called immediately on {@link MediaStreams#getAudioRecord()} after calling this
+ * method, in order to start streaming audio to the receiver.
+ *
* @param requestId the ID of the {@link #onCreateSystemRoutingSession} request which this call
* is in response to.
* @param sessionInfo a {@link RoutingSessionInfo} that describes the newly created routing
* session.
* @param formats the {@link MediaStreamsFormats} that describes the format for the {@link
* MediaStreams} to return.
- * @return a {@link MediaStreams} instance that holds the media streams to route as part of the
- * newly created routing session. May be null if system media capture failed, in which case
- * you can ignore the return value, as you will receive a call to {@link #onReleaseSession}
- * where you can clean up this session. {@link AudioRecord#startRecording()} must be called
- * immediately on {@link MediaStreams#getAudioRecord()} after calling this method, in order
- * to start streaming audio to the receiver.
+ * @return The {@link MediaStreams} to route as part of the new session, or null if system media
+ * capture failed and the result can be ignored.
* @throws IllegalStateException If the provided {@code requestId} doesn't correspond to a
* previous call to {@link #onCreateSystemRoutingSession}.
*/
@@ -1191,8 +1194,8 @@ public abstract class MediaRoute2ProviderService extends Service {
*
* <p>The default value is an empty {@link Bundle}.
*
- * <p>Note that this bundle is not copied, so avoiding mutating the given {@link Bundle}
- * after passing it to this method.
+ * <p>Do not mutate the given {@link Bundle} after passing it to this method. You can
+ * use {@link Bundle#deepCopy()} to keep a mutable copy.
*/
@NonNull
public Builder setExtras(@NonNull Bundle extras) {
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
index d6e19a6193fd..a75aeaff0c48 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
@@ -104,6 +104,7 @@ fun WearApp(
scrollable(Screen.MultipleCredentialsScreenFlatten.route) {
MultiCredentialsFlattenScreen(
credentialSelectorUiState = (remember { uiState } as MultipleEntry),
+ columnState = it.columnState,
flowEngine = flowEngine,
)
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt
index 932b3456bfb8..96cadab3916a 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt
@@ -36,7 +36,7 @@ import com.android.credentialmanager.model.get.CredentialEntryInfo
import com.android.credentialmanager.ui.components.CredentialsScreenChipSpacer
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.compose.layout.ScalingLazyColumn
-import com.google.android.horologist.compose.layout.rememberColumnState
+import com.google.android.horologist.compose.layout.ScalingLazyColumnState
import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults
import androidx.compose.ui.text.style.TextAlign
import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme
@@ -45,6 +45,7 @@ import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme
* Screen that shows multiple credentials to select from, grouped by accounts
*
* @param credentialSelectorUiState The app bar view model.
+ * @param columnState ScalingLazyColumn configuration to be be applied
* @param modifier styling for composable
* @param flowEngine [FlowEngine] that updates ui state for this screen
*/
@@ -52,15 +53,14 @@ import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme
@Composable
fun MultiCredentialsFlattenScreen(
credentialSelectorUiState: MultipleEntry,
+ columnState: ScalingLazyColumnState,
flowEngine: FlowEngine,
) {
val selectEntry = flowEngine.getEntrySelector()
Row {
Spacer(Modifier.weight(0.052f)) // 5.2% side margin
ScalingLazyColumn(
- columnState = rememberColumnState(
- ScalingLazyColumnDefaults.belowTimeText(horizontalAlignment = Alignment.Start),
- ),
+ columnState = columnState,
modifier = Modifier.weight(0.896f).fillMaxSize(), // 5.2% side margin
) {
diff --git a/packages/SettingsLib/AndroidManifest.xml b/packages/SettingsLib/AndroidManifest.xml
index 412ff29aec32..473b7eb07666 100644
--- a/packages/SettingsLib/AndroidManifest.xml
+++ b/packages/SettingsLib/AndroidManifest.xml
@@ -21,6 +21,13 @@
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<application>
+ <activity
+ android:name=".users.CreateUserActivity"
+ android:excludeFromRecents="true"
+ android:exported="false"
+ android:finishOnCloseSystemDialogs="true"
+ android:launchMode="singleInstance"
+ android:theme="@style/Theme.Transparent"/>
</application>
</manifest>
diff --git a/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml b/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml
index a0d10c383445..56b05159a30f 100644
--- a/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml
+++ b/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml
@@ -18,6 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.settingslib.widget.preference.illustration">
- <uses-sdk android:minSdkVersion="28" />
+ <uses-sdk android:minSdkVersion="30" />
</manifest>
diff --git a/packages/SettingsLib/IllustrationPreference/res/values/strings.xml b/packages/SettingsLib/IllustrationPreference/res/values/strings.xml
new file mode 100644
index 000000000000..3a8aaf8b5092
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for an accessibility action that starts an animation [CHAR LIMIT=30] -->
+ <string name="settingslib_action_label_resume">resume</string>
+ <!-- Label for an accessibility action that stops an animation [CHAR LIMIT=30] -->
+ <string name="settingslib_action_label_pause">pause</string>
+ <!-- Label for an accessibility action that stops an animation [CHAR LIMIT=50] -->
+ <string name="settingslib_state_animation_playing">Animation playing</string>
+ <!-- Label for an accessibility action that stops an animation [CHAR LIMIT=50] -->
+ <string name="settingslib_state_animation_paused">Animation paused</string>
+</resources>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index af40c647e805..e818a603c5b4 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -32,6 +32,8 @@ import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -73,6 +75,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
private boolean mLottieDynamicColor;
private CharSequence mContentDescription;
private boolean mIsTablet;
+ private boolean mIsAnimatable;
private boolean mIsAnimationPaused;
/**
@@ -81,6 +84,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
public interface OnBindListener {
/**
* Called when when {@link #onBindViewHolder(PreferenceViewHolder)} occurs.
+ *
* @param animationView the animation view for this preference.
*/
void onBind(LottieAnimationView animationView);
@@ -144,16 +148,6 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
(FrameLayout) holder.findViewById(R.id.middleground_layout);
final LottieAnimationView illustrationView =
(LottieAnimationView) holder.findViewById(R.id.lottie_view);
- // Pause and resume animation
- illustrationFrame.setOnClickListener(v -> {
- mIsAnimationPaused = !mIsAnimationPaused;
- if (mIsAnimationPaused) {
- illustrationView.pauseAnimation();
- } else {
- illustrationView.resumeAnimation();
- }
- });
-
if (illustrationView != null && !TextUtils.isEmpty(mContentDescription)) {
illustrationView.setContentDescription(mContentDescription);
illustrationView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -171,12 +165,13 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
illustrationView.setCacheComposition(mCacheComposition);
handleImageWithAnimation(illustrationView, illustrationFrame);
+ handleAnimationControl(illustrationView, illustrationFrame);
handleImageFrameMaxHeight(backgroundView, illustrationView);
if (mIsAutoScale) {
illustrationView.setScaleType(mIsAutoScale
- ? ImageView.ScaleType.CENTER_CROP
- : ImageView.ScaleType.CENTER_INSIDE);
+ ? ImageView.ScaleType.CENTER_CROP
+ : ImageView.ScaleType.CENTER_INSIDE);
}
handleMiddleGroundView(middleGroundLayout);
@@ -377,6 +372,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
+ mIsAnimatable = false;
}
}
@@ -386,10 +382,12 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
+ mIsAnimatable = false;
} else {
// The lottie image from the raw folder also returns null because the ImageView
// couldn't handle it now.
startLottieAnimationWith(illustrationView, mImageUri);
+ mIsAnimatable = true;
}
}
@@ -418,10 +416,12 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
+ mIsAnimatable = false;
} else {
// The lottie image from the raw folder also returns null because the ImageView
// couldn't handle it now.
startLottieAnimationWith(illustrationView, mImageResId);
+ mIsAnimatable = true;
}
}
}
@@ -459,6 +459,60 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
((Animatable) drawable).start();
}
+ private void handleAnimationControl(LottieAnimationView illustrationView,
+ ViewGroup container) {
+ if (mIsAnimatable) {
+ // TODO(b/397340540): list out pages having illustration without a content description.
+ if (TextUtils.isEmpty(mContentDescription)) {
+ Log.w(TAG, "Illustration should have a content description. preference key = "
+ + getKey());
+ }
+ // Enable pause and resume abilities to animation only
+ container.setOnClickListener(v -> {
+ mIsAnimationPaused = !mIsAnimationPaused;
+ if (mIsAnimationPaused) {
+ illustrationView.pauseAnimation();
+ } else {
+ illustrationView.resumeAnimation();
+ }
+ updateAccessibilityAction(container);
+ });
+
+ updateAccessibilityAction(container);
+ }
+ }
+
+ private void updateAccessibilityAction(ViewGroup container) {
+ // Setting the state of animation
+ container.setStateDescription(getStateDescriptionForAnimation());
+ container.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ final AccessibilityAction clickAction = new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK,
+ getActionLabelForAnimation());
+ info.addAction(clickAction);
+ }
+ });
+ }
+
+ private String getActionLabelForAnimation() {
+ if (mIsAnimationPaused) {
+ return getContext().getString(R.string.settingslib_action_label_resume);
+ } else {
+ return getContext().getString(R.string.settingslib_action_label_pause);
+ }
+ }
+
+ private String getStateDescriptionForAnimation() {
+ if (mIsAnimationPaused) {
+ return getContext().getString(R.string.settingslib_state_animation_paused);
+ } else {
+ return getContext().getString(R.string.settingslib_state_animation_playing);
+ }
+ }
+
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
Uri imageUri) {
final InputStream inputStream =
@@ -514,15 +568,20 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
mIsAutoScale = false;
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs,
- com.airbnb.lottie.R.styleable.LottieAnimationView, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
- mImageResId = a.getResourceId(com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_rawRes, 0);
+ com.airbnb.lottie.R.styleable.LottieAnimationView, /* defStyleAttr= */ 0,
+ /* defStyleRes= */ 0);
+ mImageResId = a.getResourceId(
+ com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_rawRes,
+ /* defValue= */ 0);
mCacheComposition = a.getBoolean(
- com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_cacheComposition, true);
+ com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_cacheComposition,
+ /* defValue= */ true);
a = context.obtainStyledAttributes(attrs,
- R.styleable.IllustrationPreference, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
+ R.styleable.IllustrationPreference, /* defStyleAttr= */ 0,
+ /* defStyleRes= */ 0);
mLottieDynamicColor = a.getBoolean(R.styleable.IllustrationPreference_dynamicColor,
- false);
+ /* defValue= */ false);
a.recycle();
}
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
index 1776d252e28b..1f4a48df55b0 100644
--- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
@@ -50,10 +50,6 @@ object SettingsThemeHelper {
}
private fun tryInit(context: Context) {
- if (expressiveThemeState != ExpressiveThemeState.UNKNOWN) {
- return
- }
-
expressiveThemeState =
if (
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) &&
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index d94450b1cabd..a029f56cf1d7 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -26,14 +26,14 @@ flag {
name: "enable_le_audio_sharing"
namespace: "pixel_cross_device_control"
description: "Gates whether to enable LE audio sharing"
- bug: "323125723"
+ bug: "388674074"
}
flag {
name: "enable_le_audio_qr_code_private_broadcast_sharing"
namespace: "pixel_cross_device_control"
description: "Gates whether to enable LE audio private broadcast sharing via QR code"
- bug: "323125723"
+ bug: "388674074"
}
flag {
@@ -229,3 +229,23 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "adopt_primary_group_management_api_v2"
+ namespace: "cross_device_experiences"
+ description: "Adopt more Bluetooth LE broadcast primary group management APIs post launch"
+ bug: "381946931"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "promote_audio_sharing_for_second_auto_connected_lea_device"
+ namespace: "cross_device_experiences"
+ description: "Show audio sharing promote notification or dialog when the second lea device is auto connected"
+ bug: "395786392"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/res/res/values-w204dp-round-watch/dimens_watch.xml b/packages/SettingsLib/res/layout/activity_create_new_user.xml
index 3509474c5c2e..7453b53a6956 100644
--- a/core/res/res/values-w204dp-round-watch/dimens_watch.xml
+++ b/packages/SettingsLib/res/layout/activity_create_new_user.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2025 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +13,10 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<resources>
- <!-- watch's indeterminate progress bar dimens based on the current screen size -->
- <dimen name="loader_horizontal_min_width_watch">70dp</dimen>
- <dimen name="loader_horizontal_min_height_watch">15dp</dimen>
-</resources>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:orientation="vertical">
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index 3326b6034237..7ab096fae0db 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -116,4 +116,13 @@
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
<item name="android:textSize">16dp</item>
</style>
+
+ <style name="Theme.Transparent" parent="@android:style/Theme.DeviceDefault.Settings">
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 572444edea29..bf86911ee683 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -30,13 +30,11 @@ import android.util.Log;
import androidx.annotation.ChecksSdkIntAtLeast;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.settingslib.flags.Flags;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -387,7 +385,7 @@ public class CsipDeviceManager {
preferredMainDevice.refresh();
hasChanged = true;
}
- syncAudioSharingStatusIfNeeded(preferredMainDevice);
+ syncAudioSharingSourceIfNeeded(preferredMainDevice);
}
if (hasChanged) {
log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
@@ -401,16 +399,13 @@ public class CsipDeviceManager {
return userManager != null && userManager.isManagedProfile();
}
- private void syncAudioSharingStatusIfNeeded(CachedBluetoothDevice mainDevice) {
+ private void syncAudioSharingSourceIfNeeded(CachedBluetoothDevice mainDevice) {
boolean isAudioSharingEnabled = BluetoothUtils.isAudioSharingUIAvailable(mContext);
- if (isAudioSharingEnabled && mainDevice != null) {
+ if (isAudioSharingEnabled) {
if (isWorkProfile()) {
- log("addMemberDevicesIntoMainDevice: skip sync audio sharing status, work profile");
+ log("addMemberDevicesIntoMainDevice: skip sync source for work profile");
return;
}
- Set<CachedBluetoothDevice> deviceSet = new HashSet<>();
- deviceSet.add(mainDevice);
- deviceSet.addAll(mainDevice.getMemberDevice());
boolean hasBroadcastSource = BluetoothUtils.isBroadcasting(mBtManager)
&& BluetoothUtils.hasConnectedBroadcastSource(
mainDevice, mBtManager);
@@ -424,6 +419,9 @@ public class CsipDeviceManager {
if (metadata != null && assistant != null) {
log("addMemberDevicesIntoMainDevice: sync audio sharing source after "
+ "combining the top level devices.");
+ Set<CachedBluetoothDevice> deviceSet = new HashSet<>();
+ deviceSet.add(mainDevice);
+ deviceSet.addAll(mainDevice.getMemberDevice());
Set<BluetoothDevice> sinksToSync = deviceSet.stream()
.map(CachedBluetoothDevice::getDevice)
.filter(device ->
@@ -437,24 +435,8 @@ public class CsipDeviceManager {
}
}
}
- if (Flags.enableTemporaryBondDevicesUi()) {
- log("addMemberDevicesIntoMainDevice: sync temp bond metadata for audio sharing "
- + "sinks after combining the top level devices.");
- Set<BluetoothDevice> sinksToSync = deviceSet.stream()
- .map(CachedBluetoothDevice::getDevice).filter(Objects::nonNull).collect(
- Collectors.toSet());
- if (sinksToSync.stream().anyMatch(BluetoothUtils::isTemporaryBondDevice)) {
- for (BluetoothDevice device : sinksToSync) {
- if (!BluetoothUtils.isTemporaryBondDevice(device)) {
- log("addMemberDevicesIntoMainDevice: sync temp bond metadata for "
- + device.getAnonymizedAddress());
- BluetoothUtils.setTemporaryBondMetadata(device);
- }
- }
- }
- }
} else {
- log("addMemberDevicesIntoMainDevice: skip sync audio sharing status, flag disabled");
+ log("addMemberDevicesIntoMainDevice: skip sync source, flag disabled");
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 84156429809b..3017d79836e8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -66,6 +66,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -84,6 +85,8 @@ import java.util.stream.Collectors;
public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
public static final String ACTION_LE_AUDIO_SHARING_STATE_CHANGE =
"com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STATE_CHANGE";
+ public static final String ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED =
+ "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_DEVICE_CONNECTED";
public static final String EXTRA_LE_AUDIO_SHARING_STATE = "BLUETOOTH_LE_AUDIO_SHARING_STATE";
public static final String EXTRA_BLUETOOTH_DEVICE = "BLUETOOTH_DEVICE";
public static final String EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE = "BT_DEVICE_TO_AUTO_ADD_SOURCE";
@@ -1189,6 +1192,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
@NonNull
private Map<Integer, List<BluetoothDevice>> getDeviceGroupsInBroadcast() {
+ if (mServiceBroadcastAssistant == null) return new HashMap<>();
boolean hysteresisModeFixEnabled =
BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext);
List<BluetoothDevice> connectedDevices = mServiceBroadcastAssistant.getConnectedDevices();
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
index d5cfe55813ee..460c790174ab 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -35,6 +35,7 @@ import static java.util.Objects.requireNonNull;
import android.annotation.SuppressLint;
import android.app.AutomaticZenRule;
import android.app.NotificationManager;
+import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.os.Parcel;
@@ -117,6 +118,14 @@ public class ZenMode implements Parcelable {
DISABLED_BY_OTHER
}
+ /**
+ * Information about the owner of a {@link ZenMode}. {@link #packageName()} is
+ * {@link SystemZenRules#PACKAGE_ANDROID} if the mode is system-owned; it may also be
+ * {@code null}, but only as an artifact of very old modes.
+ */
+ public record Owner(@Nullable String packageName, @Nullable ComponentName configurationActivity,
+ @Nullable ComponentName conditionProvider) { }
+
private final String mId;
private final AutomaticZenRule mRule;
private final Kind mKind;
@@ -198,7 +207,7 @@ public class ZenMode implements Parcelable {
}
@NonNull
- public AutomaticZenRule getRule() {
+ AutomaticZenRule getRule() {
return mRule;
}
@@ -207,6 +216,10 @@ public class ZenMode implements Parcelable {
return Strings.nullToEmpty(mRule.getName());
}
+ public void setName(@NonNull String name) {
+ mRule.setName(name);
+ }
+
@NonNull
public Kind getKind() {
return mKind;
@@ -217,6 +230,17 @@ public class ZenMode implements Parcelable {
return mStatus;
}
+ @NonNull
+ public Owner getOwner() {
+ return new Owner(mRule.getPackageName(), mRule.getConfigurationActivity(),
+ mRule.getOwner());
+ }
+
+ @Nullable
+ public String getOwnerPackage() {
+ return getOwner().packageName();
+ }
+
@AutomaticZenRule.Type
public int getType() {
return mRule.getType();
@@ -257,6 +281,26 @@ public class ZenMode implements Parcelable {
}
}
+ /**
+ * Returns the resource id of the icon for this mode. Note that this is the <em>stored</em>
+ * resource id, and thus can be different from the value in {@link #getIconKey()} -- in
+ * particular, for modes without a custom icon set, this method returns {@code 0} whereas
+ * {@link #getIconKey()} will return a default icon based on other mode properties.
+ *
+ * <p>Most callers are interested in {@link #getIconKey()}, unless they are editing the icon.
+ */
+ public int getIconResId() {
+ return mRule.getIconResId();
+ }
+
+ /**
+ * Sets the resource id of the icon for this mode.
+ * @see #getIconResId()
+ */
+ public void setIconResId(@DrawableRes int iconResId) {
+ mRule.setIconResId(iconResId);
+ }
+
/** Returns the interruption filter of the mode. */
@NotificationManager.InterruptionFilter
public int getInterruptionFilter() {
@@ -445,6 +489,10 @@ public class ZenMode implements Parcelable {
return mStatus == Status.ENABLED_AND_ACTIVE;
}
+ public boolean isManualInvocationAllowed() {
+ return mRule.isManualInvocationAllowed();
+ }
+
public boolean isSystemOwned() {
return SystemZenRules.PACKAGE_ANDROID.equals(mRule.getPackageName());
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java
index f5776989917e..b67339bace67 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java
@@ -70,8 +70,7 @@ public final class ZenModeDescriptions {
public String getTriggerDescriptionForAccessibility(@NonNull ZenMode mode) {
// Only one special case: time-based schedules, where we want to use full day names.
if (mode.isSystemOwned() && mode.getType() == TYPE_SCHEDULE_TIME) {
- ZenModeConfig.ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(
- mode.getRule().getConditionId());
+ ZenModeConfig.ScheduleInfo schedule = ZenModeSchedules.getTimeSchedule(mode);
if (schedule != null) {
String fullDaysSummary = SystemZenRules.getDaysOfWeekFull(mContext, schedule);
if (fullDaysSummary != null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeSchedules.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeSchedules.java
new file mode 100644
index 000000000000..c981652f231d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeSchedules.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2025 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.settingslib.notification.modes;
+
+import android.service.notification.ZenModeConfig;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public class ZenModeSchedules {
+
+ /**
+ * Returns the {@link ZenModeConfig.ScheduleInfo} time schedule corresponding to the mode, or
+ * {@code null} if the mode is not time-schedule-based.
+ */
+ @Nullable
+ public static ZenModeConfig.ScheduleInfo getTimeSchedule(@NonNull ZenMode mode) {
+ return ZenModeConfig.tryParseScheduleConditionId(mode.getRule().getConditionId());
+ }
+
+ /**
+ * Returns the {@link ZenModeConfig.EventInfo} calendar schedule corresponding to the mode, or
+ * {@code null} if the mode is not calendar-schedule-based.
+ */
+ @Nullable
+ public static ZenModeConfig.EventInfo getCalendarSchedule(@NonNull ZenMode mode) {
+ return ZenModeConfig.tryParseEventConditionId(mode.getRule().getConditionId());
+ }
+
+ private ZenModeSchedules() { }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java
new file mode 100644
index 000000000000..c5e6f60e3fa6
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2025 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.settingslib.users;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.R;
+
+
+public class CreateUserActivity extends Activity {
+ private static final String TAG = "CreateUserActivity";
+
+ public static final String EXTRA_USER_NAME = "new_user_name";
+ public static final String EXTRA_IS_ADMIN = "is_admin";
+ public static final String EXTRA_USER_ICON_PATH = "user_icon_path";
+ private static final String DIALOG_STATE_KEY = "create_user_dialog_state";
+ private static final String EXTRA_CAN_CREATE_ADMIN = "can_create_admin";
+ private static final String EXTRA_FILE_AUTHORITY = "file_authority";
+
+ private CreateUserDialogController mCreateUserDialogController;
+ @VisibleForTesting
+ Dialog mSetupUserDialog;
+
+
+ /**
+ * Creates intent to start CreateUserActivity
+ */
+ public static @NonNull Intent createIntentForStart(@NonNull Context context,
+ boolean canCreateAdminUser, @NonNull String fileAuth) {
+ Intent intent = new Intent(context, CreateUserActivity.class);
+ intent.putExtra(EXTRA_CAN_CREATE_ADMIN, canCreateAdminUser);
+ intent.putExtra(EXTRA_FILE_AUTHORITY, fileAuth);
+ return intent;
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intent = getIntent();
+
+ mCreateUserDialogController = new CreateUserDialogController(
+ intent.getStringExtra(EXTRA_FILE_AUTHORITY));
+ setContentView(R.layout.activity_create_new_user);
+ if (savedInstanceState != null) {
+ mCreateUserDialogController.onRestoreInstanceState(savedInstanceState);
+ }
+ mSetupUserDialog = createDialog(intent.getBooleanExtra(EXTRA_CAN_CREATE_ADMIN, false));
+ mSetupUserDialog.show();
+ }
+
+ @Override
+ protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ Bundle savedDialogState = savedInstanceState.getBundle(DIALOG_STATE_KEY);
+ if (savedDialogState != null && mSetupUserDialog != null) {
+ mSetupUserDialog.onRestoreInstanceState(savedDialogState);
+ }
+ }
+
+ private Dialog createDialog(boolean canCreateAdminUser) {
+ return mCreateUserDialogController.createDialog(
+ this,
+ this::startActivity,
+ canCreateAdminUser,
+ this::setSuccessResult,
+ this::cancel
+ );
+ }
+
+ @Override
+ public boolean onTouchEvent(@Nullable MotionEvent event) {
+ onBackInvoked();
+ return super.onTouchEvent(event);
+ }
+
+ private void onBackInvoked() {
+ if (mSetupUserDialog != null) {
+ mSetupUserDialog.dismiss();
+ }
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+
+ @VisibleForTesting
+ void setSuccessResult(String userName, Drawable userIcon, String path, Boolean isAdmin) {
+ Intent intent = new Intent(this, CreateUserActivity.class);
+ intent.putExtra(EXTRA_USER_NAME, userName);
+ intent.putExtra(EXTRA_IS_ADMIN, isAdmin);
+ intent.putExtra(EXTRA_USER_ICON_PATH, path);
+
+ mSetupUserDialog.dismiss();
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ @VisibleForTesting
+ void cancel() {
+ mSetupUserDialog.dismiss();
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ if (mSetupUserDialog != null && mSetupUserDialog.isShowing()) {
+ outState.putBundle(DIALOG_STATE_KEY, mSetupUserDialog.onSaveInstanceState());
+ }
+ mCreateUserDialogController.onSaveInstanceState(outState);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mCreateUserDialogController.onActivityResult(requestCode, resultCode, data);
+ }
+
+ private void startActivity(Intent intent, int requestCode) {
+ startActivityForResult(intent, requestCode);
+ mCreateUserDialogController.startingActivityForResult();
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
index d71b337228f6..d9f1b632323c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
@@ -242,7 +242,7 @@ public class CreateUserDialogController {
.setMessage(messageResId)
.setNegativeButtonText(R.string.cancel)
.setPositiveButtonText(R.string.next);
- mCustomDialogHelper.requestFocusOnTitle();
+ focus();
break;
case GRANT_ADMIN_DIALOG:
mEditUserInfoView.setVisibility(View.GONE);
@@ -255,7 +255,7 @@ public class CreateUserDialogController {
.setMessage(R.string.user_grant_admin_message)
.setNegativeButtonText(R.string.back)
.setPositiveButtonText(R.string.next);
- mCustomDialogHelper.requestFocusOnTitle();
+ focus();
if (mIsAdmin == null) {
mCustomDialogHelper.setButtonEnabled(false);
}
@@ -267,7 +267,7 @@ public class CreateUserDialogController {
.setTitle(R.string.user_info_settings_title)
.setNegativeButtonText(R.string.back)
.setPositiveButtonText(R.string.done);
- mCustomDialogHelper.requestFocusOnTitle();
+ focus();
mEditUserInfoView.setVisibility(View.VISIBLE);
mGrantAdminView.setVisibility(View.GONE);
break;
@@ -282,7 +282,7 @@ public class CreateUserDialogController {
mCustomDialogHelper.getDialog().dismiss();
break;
case EXIT_DIALOG:
- mCustomDialogHelper.getDialog().dismiss();
+ finish();
break;
default:
if (mCurrentState < EXIT_DIALOG) {
@@ -394,13 +394,21 @@ public class CreateUserDialogController {
return mCustomDialogHelper != null && mCustomDialogHelper.getDialog() != null;
}
+ void focus() {
+ mCustomDialogHelper.requestFocusOnTitle();
+ }
+
/**
* Runs callback and clears saved values after dialog is dismissed.
*/
public void finish() {
if (mCurrentState == CREATE_USER_AND_CLOSE) {
if (mSuccessCallback != null) {
- mSuccessCallback.onSuccess(mUserName, mNewUserIcon, Boolean.TRUE.equals(mIsAdmin));
+ if (mEditUserPhotoController != null && mCachedDrawablePath == null) {
+ mCachedDrawablePath = mEditUserPhotoController.getCachedDrawablePath();
+ }
+ mSuccessCallback.onSuccess(mUserName, mNewUserIcon, mCachedDrawablePath,
+ Boolean.TRUE.equals(mIsAdmin));
}
} else {
if (mCancelCallback != null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java b/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java
index 3d18b59258b3..eed608e98cc9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java
@@ -18,6 +18,8 @@ package com.android.settingslib.users;
import android.graphics.drawable.Drawable;
+import androidx.annotation.Nullable;
+
/**
* Defines a callback when a new user data is filled out.
*/
@@ -27,8 +29,10 @@ public interface NewUserData {
* Consumes data relevant to new user that needs to be created.
* @param userName New user name.
* @param userImage New user icon.
+ * @param iconPath New user icon path.
* @param isNewUserAdmin A boolean that indicated whether new user has admin status.
*/
- void onSuccess(String userName, Drawable userImage, Boolean isNewUserAdmin);
+ void onSuccess(@Nullable String userName, @Nullable Drawable userImage,
+ @Nullable String iconPath, @Nullable Boolean isNewUserAdmin);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
index 2eccaa626f3b..fd14d1ff6786 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
@@ -40,8 +40,6 @@ import android.content.Context;
import android.os.Looper;
import android.os.Parcel;
import android.os.UserManager;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import com.android.settingslib.flags.Flags;
@@ -76,9 +74,6 @@ public class CsipDeviceManagerTest {
private final static String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11";
private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22";
private final static String DEVICE_ADDRESS_3 = "AA:BB:CC:DD:EE:33";
- private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
- private static final String TEMP_BOND_METADATA =
- "<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>";
private final static int GROUP1 = 1;
private final BluetoothClass DEVICE_CLASS_1 =
createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
@@ -342,7 +337,6 @@ public class CsipDeviceManagerTest {
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_returnTrue() {
// Condition: The preferredDevice is main and there is another main device in top list
// Expected Result: return true and there is the preferredDevice in top list
@@ -352,6 +346,7 @@ public class CsipDeviceManagerTest {
mCachedDevices.add(preferredDevice);
mCachedDevices.add(mCachedDevice2);
mCachedDevices.add(mCachedDevice3);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
@@ -364,7 +359,6 @@ public class CsipDeviceManagerTest {
}
@Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
public void
addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_workProfile_doNothing() {
// Condition: The preferredDevice is main and there is another main device in top list
@@ -375,6 +369,7 @@ public class CsipDeviceManagerTest {
mCachedDevices.add(preferredDevice);
mCachedDevices.add(mCachedDevice2);
mCachedDevices.add(mCachedDevice3);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(true);
BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
@@ -382,8 +377,6 @@ public class CsipDeviceManagerTest {
BluetoothLeBroadcastReceiveState.class);
when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state));
- when(mDevice2.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
- .thenReturn(TEMP_BOND_METADATA.getBytes());
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
when(mUserManager.isManagedProfile()).thenReturn(true);
@@ -394,13 +387,10 @@ public class CsipDeviceManagerTest {
assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
verify(mAssistant, never()).addSource(mDevice1, metadata, /* isGroupOp= */ false);
- verify(mDevice1, never()).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
}
@Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
- public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_syncState() {
+ public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_syncSource() {
// Condition: The preferredDevice is main and there is another main device in top list
// Expected Result: return true and there is the preferredDevice in top list
CachedBluetoothDevice preferredDevice = mCachedDevice1;
@@ -409,6 +399,7 @@ public class CsipDeviceManagerTest {
mCachedDevices.add(preferredDevice);
mCachedDevices.add(mCachedDevice2);
mCachedDevices.add(mCachedDevice3);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(true);
BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
@@ -416,8 +407,6 @@ public class CsipDeviceManagerTest {
BluetoothLeBroadcastReceiveState.class);
when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state));
- when(mDevice2.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
- .thenReturn(TEMP_BOND_METADATA.getBytes());
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
@@ -426,8 +415,6 @@ public class CsipDeviceManagerTest {
assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
verify(mAssistant).addSource(mDevice1, metadata, /* isGroupOp= */ false);
- verify(mDevice1).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
}
@Test
@@ -449,13 +436,13 @@ public class CsipDeviceManagerTest {
}
@Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_returnTrue() {
// Condition: The preferredDevice is member and there are two main device in top list
// Expected Result: return true and there is the preferredDevice in top list
CachedBluetoothDevice preferredDevice = mCachedDevice2;
BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
mCachedDevice3.setGroupId(GROUP1);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(false);
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
@@ -470,20 +457,16 @@ public class CsipDeviceManagerTest {
assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
verify(mAssistant, never()).addSource(any(BluetoothDevice.class),
any(BluetoothLeBroadcastMetadata.class), anyBoolean());
- verify(mDevice2, never()).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
- verify(mDevice3, never()).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
}
@Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
- public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_syncState() {
+ public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_syncSource() {
// Condition: The preferredDevice is member and there are two main device in top list
// Expected Result: return true and there is the preferredDevice in top list
CachedBluetoothDevice preferredDevice = mCachedDevice2;
BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
mCachedDevice3.setGroupId(GROUP1);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(true);
BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
@@ -491,8 +474,6 @@ public class CsipDeviceManagerTest {
BluetoothLeBroadcastReceiveState.class);
when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
when(mAssistant.getAllSources(mDevice1)).thenReturn(ImmutableList.of(state));
- when(mDevice1.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
- .thenReturn(TEMP_BOND_METADATA.getBytes());
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
@@ -507,10 +488,6 @@ public class CsipDeviceManagerTest {
assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
verify(mAssistant).addSource(mDevice2, metadata, /* isGroupOp= */ false);
verify(mAssistant).addSource(mDevice3, metadata, /* isGroupOp= */ false);
- verify(mDevice2).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
- verify(mDevice3).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java
index 6b30f159129e..71ecf5b76296 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java
@@ -21,6 +21,7 @@ import static android.app.AutomaticZenRule.TYPE_DRIVING;
import static android.app.AutomaticZenRule.TYPE_IMMERSIVE;
import static android.app.AutomaticZenRule.TYPE_OTHER;
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
+import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
import static android.app.AutomaticZenRule.TYPE_THEATER;
import static android.app.AutomaticZenRule.TYPE_UNKNOWN;
import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS;
@@ -35,6 +36,8 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import android.app.AutomaticZenRule;
+import android.content.ComponentName;
+import android.content.Context;
import android.net.Uri;
import android.os.Parcel;
import android.service.notification.Condition;
@@ -43,13 +46,17 @@ import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenPolicy;
+import androidx.test.core.app.ApplicationProvider;
+
import com.android.internal.R;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@@ -72,6 +79,13 @@ public class ZenModeTest {
.setType(TYPE_OTHER)
.build();
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = ApplicationProvider.getApplicationContext();
+ }
+
@Test
public void testBasicMethods_mode() {
ZenMode zenMode = new ZenMode("id", ZEN_RULE, zenConfigRuleFor(ZEN_RULE, true));
@@ -95,7 +109,7 @@ public class ZenModeTest {
assertThat(manualMode.canEditPolicy()).isTrue();
assertThat(manualMode.canBeDeleted()).isFalse();
assertThat(manualMode.isActive()).isFalse();
- assertThat(manualMode.getRule().getPackageName()).isEqualTo(PACKAGE_ANDROID);
+ assertThat(manualMode.getOwnerPackage()).isEqualTo(PACKAGE_ANDROID);
}
@Test
@@ -153,7 +167,7 @@ public class ZenModeTest {
public void isCustomManual_scheduleTime_false() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Mode", Uri.parse("x"))
.setPackage(SystemZenRules.PACKAGE_ANDROID)
- .setType(AutomaticZenRule.TYPE_SCHEDULE_TIME)
+ .setType(TYPE_SCHEDULE_TIME)
.build();
ZenMode mode = new ZenMode("id", rule, zenConfigRuleFor(rule, false));
@@ -194,6 +208,23 @@ public class ZenModeTest {
}
@Test
+ public void getOwner_returnsOwnerDetails() {
+ AutomaticZenRule azr = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
+ .setPackage("package")
+ .setConfigurationActivity(new ComponentName("package", "configActivity"))
+ .setOwner(new ComponentName("package", "conditionService"))
+ .build();
+ ZenMode zenMode = new ZenMode("id", azr, zenConfigRuleFor(azr, false));
+
+ ZenMode.Owner owner = zenMode.getOwner();
+ assertThat(owner.packageName()).isEqualTo("package");
+ assertThat(owner.configurationActivity()).isEqualTo(
+ new ComponentName("package", "configActivity"));
+ assertThat(owner.conditionProvider()).isEqualTo(
+ new ComponentName("package", "conditionService"));
+ }
+
+ @Test
public void getPolicy_interruptionFilterPriority_returnsZenPolicy() {
AutomaticZenRule azr = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
@@ -245,7 +276,7 @@ public class ZenModeTest {
zenMode.setPolicy(ZEN_POLICY);
- assertThat(zenMode.getRule().getInterruptionFilter()).isEqualTo(
+ assertThat(zenMode.getInterruptionFilter()).isEqualTo(
INTERRUPTION_FILTER_PRIORITY);
assertThat(zenMode.getPolicy()).isEqualTo(ZEN_POLICY);
assertThat(zenMode.getRule().getZenPolicy()).isEqualTo(ZEN_POLICY);
@@ -397,6 +428,7 @@ public class ZenModeTest {
assertThat(iconKey.resPackage()).isEqualTo("some.package");
assertThat(iconKey.resId()).isEqualTo(123);
+ assertThat(mode.getIconResId()).isEqualTo(123);
}
@Test
@@ -411,6 +443,7 @@ public class ZenModeTest {
assertThat(iconKey.resPackage()).isNull();
assertThat(iconKey.resId()).isEqualTo(123);
+ assertThat(mode.getIconResId()).isEqualTo(123);
}
@Test
@@ -425,15 +458,18 @@ public class ZenModeTest {
assertThat(iconKey.resPackage()).isEqualTo("some.package");
assertThat(iconKey.resId()).isEqualTo(123);
+ assertThat(mode.getIconResId()).isEqualTo(123);
}
@Test
public void getIconKey_manualDnd_isDndIcon() {
- ZenIcon.Key iconKey = TestModeBuilder.MANUAL_DND.getIconKey();
+ ZenMode mode = TestModeBuilder.MANUAL_DND;
+ ZenIcon.Key iconKey = mode.getIconKey();
assertThat(iconKey.resPackage()).isNull();
assertThat(iconKey.resId()).isEqualTo(
com.android.internal.R.drawable.ic_zen_mode_type_special_dnd);
+ assertThat(mode.getIconResId()).isEqualTo(0);
}
@Test
@@ -448,6 +484,7 @@ public class ZenModeTest {
assertThat(iconKey.resPackage()).isNull();
assertThat(iconKey.resId()).isEqualTo(
com.android.internal.R.drawable.ic_zen_mode_type_bedtime);
+ assertThat(mode.getIconResId()).isEqualTo(0);
}
@Test
@@ -462,6 +499,7 @@ public class ZenModeTest {
assertThat(iconKey.resPackage()).isNull();
assertThat(iconKey.resId()).isEqualTo(
com.android.internal.R.drawable.ic_zen_mode_type_schedule_calendar);
+ assertThat(mode.getIconResId()).isEqualTo(0);
}
@Test
@@ -477,6 +515,77 @@ public class ZenModeTest {
assertThat(iconKey.resPackage()).isNull();
assertThat(iconKey.resId()).isEqualTo(
com.android.internal.R.drawable.ic_zen_mode_type_special_dnd);
+ assertThat(mode.getIconResId()).isEqualTo(0);
+ }
+
+ @Test
+ public void setCustomModeConditionId_timeSchedule() {
+ ZenMode mode = new TestModeBuilder()
+ .setPackage(PACKAGE_ANDROID)
+ .build();
+ ZenModeConfig.ScheduleInfo timeSchedule = new ZenModeConfig.ScheduleInfo();
+ timeSchedule.startHour = 9;
+ timeSchedule.endHour = 12;
+ timeSchedule.days = new int[] {Calendar.SATURDAY, Calendar.SUNDAY};
+ Uri scheduleUri = ZenModeConfig.toScheduleConditionId(timeSchedule);
+
+ mode.setCustomModeConditionId(mContext, scheduleUri);
+
+ assertThat(mode.getType()).isEqualTo(TYPE_SCHEDULE_TIME);
+ assertThat(ZenModeSchedules.getTimeSchedule(mode)).isEqualTo(timeSchedule);
+ assertThat(mode.getTriggerDescription()).isEqualTo("Sun, Sat, 9:00 AM - 12:00 PM");
+
+ assertThat(mode.getRule().getConditionId()).isEqualTo(scheduleUri);
+ assertThat(mode.getRule().getOwner()).isEqualTo(
+ ZenModeConfig.getScheduleConditionProvider());
+ }
+
+ @Test
+ public void setCustomModeConditionId_calendarSchedule() {
+ ZenMode mode = new TestModeBuilder()
+ .setPackage(PACKAGE_ANDROID)
+ .build();
+ ZenModeConfig.EventInfo calendarSchedule = new ZenModeConfig.EventInfo();
+ calendarSchedule.calendarId = 1L;
+ calendarSchedule.calName = "My events";
+ Uri scheduleUri = ZenModeConfig.toEventConditionId(calendarSchedule);
+
+ mode.setCustomModeConditionId(mContext, scheduleUri);
+
+ assertThat(mode.getType()).isEqualTo(TYPE_SCHEDULE_CALENDAR);
+ assertThat(ZenModeSchedules.getCalendarSchedule(mode)).isEqualTo(calendarSchedule);
+ assertThat(mode.getTriggerDescription()).isEqualTo("My events");
+
+ assertThat(mode.getRule().getConditionId()).isEqualTo(scheduleUri);
+ assertThat(mode.getRule().getOwner()).isEqualTo(
+ ZenModeConfig.getEventConditionProvider());
+ }
+
+ @Test
+ public void setCustomModeConditionId_manualSchedule() {
+ ZenMode mode = new TestModeBuilder()
+ .setPackage(PACKAGE_ANDROID)
+ .build();
+
+ mode.setCustomModeConditionId(mContext, ZenModeConfig.toCustomManualConditionId());
+
+ assertThat(mode.getType()).isEqualTo(TYPE_OTHER);
+ assertThat(mode.getTriggerDescription()).isEqualTo("");
+
+ assertThat(mode.getRule().getConditionId()).isEqualTo(
+ ZenModeConfig.toCustomManualConditionId());
+ assertThat(mode.getRule().getOwner()).isEqualTo(
+ ZenModeConfig.getCustomManualConditionProvider());
+ }
+
+ @Test
+ public void setCustomModeConditionId_nonSystemRule_throws() {
+ ZenMode mode = new TestModeBuilder()
+ .setPackage("some.other.package")
+ .build();
+
+ assertThrows(IllegalStateException.class,
+ () -> mode.setCustomModeConditionId(mContext, Uri.parse("blah")));
}
private static void assertUnparceledIsEqualToOriginal(String type, ZenMode original) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java
new file mode 100644
index 000000000000..f58eb7cc2e31
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2025 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.settingslib.users;
+
+import static com.android.settingslib.users.CreateUserActivity.EXTRA_IS_ADMIN;
+import static com.android.settingslib.users.CreateUserActivity.EXTRA_USER_ICON_PATH;
+import static com.android.settingslib.users.CreateUserActivity.EXTRA_USER_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class CreateUserActivityTest {
+
+ private static final String TEST_USER_NAME = "test_user";
+ private static final String TEST_USER_ICON_PATH = "/test_path";
+ private static final boolean TEST_IS_ADMIN = true;
+
+ private Context mContext;
+ private CreateUserActivity mCreateUserActivity;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mCreateUserActivity = Robolectric.buildActivity(CreateUserActivity.class).setup().get();
+ }
+
+ @Test
+ public void startActivity_startsActivityForResult() {
+ Intent activityIntent = CreateUserActivity.createIntentForStart(mContext, true, "");
+ mCreateUserActivity.startActivity(activityIntent, null);
+
+ assertThat(shadowOf(mCreateUserActivity).getNextStartedActivityForResult().intent)
+ .isEqualTo(activityIntent);
+ }
+
+ @Test
+ public void onTouchEvent_dismissesDialogAndCancelsResult() {
+ mCreateUserActivity.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0,
+ 0));
+
+ assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse();
+ assertThat(shadowOf(mCreateUserActivity).getResultCode())
+ .isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ public void setSuccessResult_dismissesDialogAndSetsSuccessResult() {
+ Drawable mockDrawable = mock(Drawable.class);
+
+ mCreateUserActivity.setSuccessResult(TEST_USER_NAME, mockDrawable, TEST_USER_ICON_PATH,
+ TEST_IS_ADMIN);
+
+ assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse();
+ assertThat(shadowOf(mCreateUserActivity).getResultCode()).isEqualTo(Activity.RESULT_OK);
+
+ Intent resultIntent = shadowOf(mCreateUserActivity).getResultIntent();
+ assertThat(resultIntent.getStringExtra(EXTRA_USER_NAME)).isEqualTo(TEST_USER_NAME);
+ assertThat(resultIntent.getBooleanExtra(EXTRA_IS_ADMIN, false)).isEqualTo(TEST_IS_ADMIN);
+ assertThat(resultIntent.getStringExtra(EXTRA_USER_ICON_PATH))
+ .isEqualTo(TEST_USER_ICON_PATH);
+ }
+
+ @Test
+ public void cancel_dismissesDialogAndSetsCancelResult() {
+ mCreateUserActivity.cancel();
+
+ assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse();
+ assertThat(shadowOf(mCreateUserActivity).getResultCode())
+ .isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ public void onSaveInstanceState_savesDialogState() {
+ Bundle outState = new Bundle();
+ mCreateUserActivity.onSaveInstanceState(outState);
+
+ CreateUserActivity restoredActivity =
+ Robolectric.buildActivity(CreateUserActivity.class).setup(outState).get();
+
+ assertThat(restoredActivity.mSetupUserDialog).isNotNull();
+ assertThat(restoredActivity.mSetupUserDialog.isShowing()).isTrue();
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
index 68312223b4b1..e60232339e4c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
@@ -211,7 +211,7 @@ public class CreateUserDialogControllerTest {
editText.setText(expectedNewName);
next.performClick();
verify(successCallback, times(1))
- .onSuccess(expectedNewName, null, true);
+ .onSuccess(expectedNewName, null, null, true);
verifyNoInteractions(cancelCallback);
}
@@ -233,7 +233,7 @@ public class CreateUserDialogControllerTest {
editText.setText(expectedNewName);
next.performClick();
verify(successCallback, times(1))
- .onSuccess(expectedNewName, null, false);
+ .onSuccess(expectedNewName, null, null, false);
verifyNoInteractions(cancelCallback);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 8e3aa65fa5c7..bc281eea39d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1503,7 +1503,7 @@ public class SettingsProvider extends ContentProvider {
if (DEBUG) {
Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ", "
+ ", " + tag + ", " + makeDefault + ", " + requestingUserId
- + ", " + forceNotify + ")");
+ + ", " + forceNotify + ", " + overrideableByRestore + ")");
}
return mutateGlobalSetting(name, value, tag, makeDefault, requestingUserId,
MUTATION_OPERATION_INSERT, forceNotify, 0, overrideableByRestore);
@@ -1785,7 +1785,7 @@ public class SettingsProvider extends ContentProvider {
if (DEBUG) {
Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", "
+ ", " + tag + ", " + makeDefault + ", " + requestingUserId
- + ", " + forceNotify + ")");
+ + ", " + forceNotify + ", " + overrideableByRestore + ")");
}
return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId,
MUTATION_OPERATION_INSERT, forceNotify, 0, overrideableByRestore);
@@ -1946,7 +1946,7 @@ public class SettingsProvider extends ContentProvider {
boolean overrideableByRestore) {
if (DEBUG) {
Slog.v(LOG_TAG, "insertSystemSetting(" + name + ", " + value + ", "
- + requestingUserId + ")");
+ + requestingUserId + ", " + overrideableByRestore + ")");
}
return mutateSystemSetting(name, value, /* tag= */ null, requestingUserId,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
index 17ebf6fc3235..0484defeb4d7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
@@ -30,6 +30,7 @@ import android.os.ShellCommand;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.util.Slog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -94,6 +95,8 @@ final public class SettingsService extends Binder {
}
final static class MyShellCommand extends ShellCommand {
+ private static final String LOG_TAG = "SettingsShellCmd";
+
final SettingsProvider mProvider;
final boolean mDumping;
@@ -115,6 +118,7 @@ final public class SettingsService extends Binder {
String mTag = null;
int mResetMode = -1;
boolean mMakeDefault;
+ boolean mOverrideableByRestore;
MyShellCommand(SettingsProvider provider, boolean dumping) {
mProvider = provider;
@@ -209,6 +213,7 @@ final public class SettingsService extends Binder {
return -1;
}
break;
+ // At this point, mVerb == PUT
} else if (mKey == null) {
mKey = arg;
// keep going; there's another PUT arg
@@ -217,36 +222,8 @@ final public class SettingsService extends Binder {
// what we have so far is a valid command
valid = true;
// keep going; there may be another PUT arg
- } else if (mTag == null) {
- mTag = arg;
- if ("default".equalsIgnoreCase(mTag)) {
- mTag = null;
- mMakeDefault = true;
- if (peekNextArg() == null) {
- valid = true;
- } else {
- perr.println("Too many arguments");
- return -1;
- }
- break;
- }
- if (peekNextArg() == null) {
- valid = true;
- break;
- }
- } else { // PUT, final arg
- if (!"default".equalsIgnoreCase(arg)) {
- perr.println("Argument expected to be 'default'");
- return -1;
- }
- mMakeDefault = true;
- if (peekNextArg() == null) {
- valid = true;
- } else {
- perr.println("Too many arguments");
- return -1;
- }
- break;
+ } else {
+ valid = parseOptionalPutArgument(arg);
}
} while ((arg = getNextArg()) != null);
@@ -275,7 +252,8 @@ final public class SettingsService extends Binder {
pout.println(getForUser(iprovider, mUser, mTable, mKey));
break;
case PUT:
- putForUser(iprovider, mUser, mTable, mKey, mValue, mTag, mMakeDefault);
+ putForUser(iprovider, mUser, mTable, mKey, mValue, mTag, mMakeDefault,
+ mOverrideableByRestore);
break;
case DELETE:
pout.println("Deleted "
@@ -297,6 +275,41 @@ final public class SettingsService extends Binder {
return 0;
}
+ private boolean parseOptionalPutArgument(String arg) {
+ boolean valid = true;
+ // Given that the order is TAG default overrideableByRestore, we need to parse from the
+ // opposite direction
+ switch (arg) {
+ case "overrideableByRestore":
+ if (mOverrideableByRestore) {
+ valid = false;
+ } else {
+ mOverrideableByRestore = true;
+ }
+ break;
+ case "default":
+ if (mMakeDefault || mOverrideableByRestore) {
+ valid = false;
+ } else {
+ mMakeDefault = true;
+ }
+ break;
+ default: // tag
+ if (mMakeDefault || mOverrideableByRestore || mTag != null) {
+ valid = false;
+ } else {
+ mTag = arg;
+ }
+ break;
+ }
+ if (!valid) {
+ Slog.e(LOG_TAG, "parseOptionalPutArgument(" + arg + "): invalid state ("
+ + "mTag=" + mTag + ", mMakeDefault=" + mMakeDefault
+ + ", mOverrideableByRestore=" + mOverrideableByRestore + ")");
+ }
+ return valid;
+ }
+
List<String> listForUser(IContentProvider provider, int userHandle, String table) {
final String callListCommand;
if ("system".equals(table)) callListCommand = Settings.CALL_METHOD_LIST_SYSTEM;
@@ -351,7 +364,11 @@ final public class SettingsService extends Binder {
}
void putForUser(IContentProvider provider, int userHandle, final String table,
- final String key, final String value, String tag, boolean makeDefault) {
+ final String key, final String value, String tag, boolean makeDefault,
+ boolean overrideableByRestore) {
+ Slog.v(LOG_TAG, "putForUser(userId=" + userHandle + ", table=" + table + ", key=" + key
+ + ", value=" + value + ", tag=" + tag + ", makeDefault=" + makeDefault
+ + ", overrideableByRestore=" + overrideableByRestore + ")");
final String callPutCommand;
if ("system".equals(table)) {
callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM;
@@ -377,6 +394,9 @@ final public class SettingsService extends Binder {
if (makeDefault) {
arg.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
}
+ if (overrideableByRestore) {
+ arg.putBoolean(Settings.CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY, true);
+ }
final AttributionSource attributionSource = new AttributionSource(
Binder.getCallingUid(), resolveCallingPackage(), /*attributionTag*/ null);
provider.call(attributionSource, Settings.AUTHORITY,
@@ -474,10 +494,11 @@ final public class SettingsService extends Binder {
pw.println(" Print this help text.");
pw.println(" get [--user <USER_ID> | current] NAMESPACE KEY");
pw.println(" Retrieve the current value of KEY.");
- pw.println(" put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TAG] [default]");
+ pw.println(" put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TAG] [default] [overrideableByRestore]");
pw.println(" Change the contents of KEY to VALUE.");
- pw.println(" TAG to associate with the setting.");
+ pw.println(" TAG to associate with the setting (cannot be default or overrideableByRestore).");
pw.println(" {default} to set as the default, case-insensitive only for global/secure namespace");
+ pw.println(" {overrideableByRestore} to let the value be overridden by BackupManager on restore operations");
pw.println(" delete [--user <USER_ID> | current] NAMESPACE KEY");
pw.println(" Delete the entry for KEY.");
pw.println(" reset [--user <USER_ID> | current] NAMESPACE {PACKAGE_NAME | RESET_MODE}");
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
index 444389fb26ea..fdb07bdbe7f3 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
@@ -155,7 +155,7 @@ constructor(
/** [ViewTransitionToken] to be used for storing transitioning view in [transitionRegistry] */
private val transitionToken =
if (Flags.decoupleViewControllerInAnimlib()) {
- ViewTransitionToken(transitioningView::class.java)
+ transitionRegistry?.register(transitioningView)
} else {
null
}
@@ -164,7 +164,7 @@ constructor(
private val ghostedView: View
get() =
if (Flags.decoupleViewControllerInAnimlib()) {
- transitionRegistry?.getView(transitionToken!!)
+ transitionToken?.let { token -> transitionRegistry?.getView(token) }
} else {
_ghostedView
}!!
@@ -186,10 +186,6 @@ constructor(
)
}
- if (Flags.decoupleViewControllerInAnimlib()) {
- transitionRegistry?.register(transitionToken!!, transitioningView)
- }
-
/** Find the first view with a background in [view] and its children. */
fun findBackground(view: View): Drawable? {
if (view.background != null) {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt
index af3ca87bf788..280d90de7ace 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt
@@ -22,12 +22,12 @@ import android.view.View
interface IViewTransitionRegistry {
/**
- * Registers the transitioning [view] mapped to a [token]
+ * Registers the transitioning [view] mapped to returned token
*
- * @param token The token corresponding to the transitioning view
* @param view The view undergoing transition
+ * @return token mapped to the transitioning view
*/
- fun register(token: ViewTransitionToken, view: View)
+ fun register(view: View): ViewTransitionToken
/**
* Unregisters the transitioned view from its corresponding [token]
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt
index 86c7f76c6bee..882ff3b61ba9 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt
@@ -22,21 +22,21 @@ import java.lang.ref.WeakReference
/**
* A registry to temporarily store the view being transitioned into a Dialog (using
- * [DialogTransitionAnimator]) or an Activity (using [ActivityTransitionAnimator])
+ * [DialogTransitionAnimator]) or an Activity (using [ActivityTransitionAnimator]).
*/
class ViewTransitionRegistry : IViewTransitionRegistry {
/**
* A map of a unique token to a WeakReference of the View being transitioned. WeakReference
* ensures that Views are garbage collected whenever they become eligible and avoid any
- * memory leaks
+ * memory leaks.
*/
- private val registry by lazy { mutableMapOf<ViewTransitionToken, WeakReference<View>>() }
+ private val registry by lazy { mutableMapOf<ViewTransitionToken, ViewTransitionInfo>() }
/**
* A [View.OnAttachStateChangeListener] to be attached to all views stored in the registry to
* ensure that views (and their corresponding entry) is automatically removed when the view is
- * detached from the Window
+ * detached from the Window.
*/
private val listener by lazy {
object : View.OnAttachStateChangeListener {
@@ -45,74 +45,121 @@ class ViewTransitionRegistry : IViewTransitionRegistry {
}
override fun onViewDetachedFromWindow(view: View) {
- getViewToken(view)?.let { token -> unregister(token) }
+ // if view is detached from window, remove it from registry irrespective of number
+ // of reference held by clients/user of this registry
+ getViewToken(view)?.let { token -> remove(token) }
}
}
}
/**
- * Creates an entry of a unique "token" mapped to "transitioning view" in the registry
+ * Creates an entry of a unique token mapped to transitioning [view] in the registry.
*
- * @param token unique token associated with the transitioning view
* @param view view undergoing transitions
+ * @return unique token mapped to the view being registered
*/
- override fun register(token: ViewTransitionToken, view: View) {
+ override fun register(view: View): ViewTransitionToken {
+ // if view being registered is already present in the registry and has a unique token
+ // assigned to it, reuse that token
+ getViewToken(view)?.let { token ->
+ registry[token]?.let { info -> info.viewRefCount += 1 }
+ return token
+ }
+
// token embedded as a view tag enables to use a single listener for all views
+ val token = ViewTransitionToken(view::class.java)
view.setTag(R.id.tag_view_transition_token, token)
view.addOnAttachStateChangeListener(listener)
- registry[token] = WeakReference(view)
+ registry[token] = ViewTransitionInfo(WeakReference(view))
onRegistryUpdate()
+
+ return token
}
/**
- * Removes the entry associated with the unique "token" in the registry
+ * Unregisters a view mapped to the unique [token] in the registry. This will either remove the
+ * entry entirely from registry (if the reference count of the associated view reached zero) or
+ * will decrement the reference count of the associated view in the registry.
*
* @param token unique token associated with the transitioning view
*/
override fun unregister(token: ViewTransitionToken) {
- registry.remove(token)?.let {
- it.get()?.let { view ->
+ registry[token]?.let { info ->
+ info.viewRefCount -= 1
+ if (info.viewRefCount == 0) {
+ remove(token)
+ }
+ }
+ }
+
+ /**
+ * Removes the entry associated with the unique [token] in the registry.
+ *
+ * @param token unique token associated with the transitioning view
+ */
+ private fun remove(token: ViewTransitionToken) {
+ registry.remove(token)?.let { removedInfo ->
+ removedInfo.viewRef.get()?.let { view ->
view.removeOnAttachStateChangeListener(listener)
view.setTag(R.id.tag_view_transition_token, null)
}
- it.clear()
+ removedInfo.viewRef.clear()
onRegistryUpdate()
}
}
/**
- * Access a view from registry using unique "token" associated with it
+ * Access a view from registry using unique [token] associated with it.
* WARNING - this returns a StrongReference to the View stored in the registry
*/
override fun getView(token: ViewTransitionToken): View? {
- return registry[token]?.get()
+ return registry[token]?.viewRef?.get()
}
/**
- * Return token mapped to the [view], if it is present in the registry
+ * Return token mapped to the [view], if it is present in the registry.
*
* @param view the transitioning view whose token we are requesting
* @return token associated with the [view] if present, else null
*/
override fun getViewToken(view: View): ViewTransitionToken? {
- return (view.getTag(R.id.tag_view_transition_token) as? ViewTransitionToken)?.let { token ->
- getView(token)?.let { token }
+ // extract token from the view if it is embedded inside it as a tag
+ val token = view.getTag(R.id.tag_view_transition_token) as? ViewTransitionToken
+
+ // this should never really happen, but if token embedded inside the view as tag, doesn't
+ // point to a valid view in the registry, remove that token (tag) from the view and registry
+ if (token != null && getView(token) == null) {
+ view.setTag(R.id.tag_view_transition_token, null)
+ remove(token)
+ return null
}
+
+ return token
}
- /** Event call to run on registry update (on both [register] and [unregister]) */
+ /** Event call to run on registry update (on both [register] and [unregister]). */
override fun onRegistryUpdate() {
emitCountForTrace()
}
/**
* Utility function to emit number of non-null views in the registry whenever the registry is
- * updated (via [register] or [unregister])
+ * updated (via [register] or [unregister]).
*/
private fun emitCountForTrace() {
Trace.setCounter("transition_registry_view_count", registry.count().toLong())
}
+ /** Information associated with each transitioning view in the registry. */
+ private data class ViewTransitionInfo(
+
+ /** View being transitioned */
+ val viewRef: WeakReference<View>,
+
+ /** Count of clients (users of this registry) referencing same transitioning view */
+ var viewRefCount: Int = 1
+ )
+
companion object {
val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ViewTransitionRegistry() }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
index 60eaa28e3822..b9aca25e1675 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
@@ -21,7 +21,6 @@ import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
-import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.observableTransitionState
import com.android.systemui.scene.shared.model.SceneDataSource
import kotlinx.coroutines.CoroutineScope
@@ -106,6 +105,6 @@ class SceneTransitionLayoutDataSource(
}
override fun freezeAndAnimateToCurrentState() {
- (state.transitionState as? TransitionState.Transition)?.freezeAndAnimateToCurrentState()
+ state.currentTransition?.freezeAndAnimateToCurrentState()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
index 052d520ac92f..18b68d2fa8a3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
@@ -153,10 +153,12 @@ class GhostedViewTransitionAnimatorControllerTest : SysuiTestCase() {
private class FakeViewTransitionRegistry : IViewTransitionRegistry {
val registry = mutableMapOf<ViewTransitionToken, View>()
+ val token = ViewTransitionToken()
- override fun register(token: ViewTransitionToken, view: View) {
+ override fun register(view: View): ViewTransitionToken {
registry[token] = view
view.setTag(R.id.tag_view_transition_token, token)
+ return token
}
override fun unregister(token: ViewTransitionToken) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/ViewTransitionRegistryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/ViewTransitionRegistryTest.kt
index ef91c793a2f3..b18eafd206ca 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/ViewTransitionRegistryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/ViewTransitionRegistryTest.kt
@@ -25,9 +25,9 @@ import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.runner.RunWith
import org.mockito.kotlin.argumentCaptor
-import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
import kotlin.test.Test
@SmallTest
@@ -36,24 +36,22 @@ class ViewTransitionRegistryTest : SysuiTestCase() {
private lateinit var view: View
private lateinit var underTest: ViewTransitionRegistry
- private var token: ViewTransitionToken = ViewTransitionToken()
@Before
fun setup() {
view = FrameLayout(mContext)
underTest = ViewTransitionRegistry()
- token = ViewTransitionToken()
}
@Test
fun testSuccessfulRegisterInViewTransitionRegistry() {
- underTest.register(token, view)
+ val token = underTest.register(view)
assertThat(underTest.getView(token)).isNotNull()
}
@Test
fun testSuccessfulUnregisterInViewTransitionRegistry() {
- underTest.register(token, view)
+ val token = underTest.register(view)
assertThat(underTest.getView(token)).isNotNull()
underTest.unregister(token)
@@ -62,13 +60,14 @@ class ViewTransitionRegistryTest : SysuiTestCase() {
@Test
fun testSuccessfulUnregisterOnViewDetachedFromWindow() {
- val view: View = mock {
- on { getTag(R.id.tag_view_transition_token) } doReturn token
- }
+ val view: View = mock()
- underTest.register(token, view)
+ val token = underTest.register(view)
+ assertThat(token).isEqualTo(token)
assertThat(underTest.getView(token)).isNotNull()
+ whenever(view.getTag(R.id.tag_view_transition_token)).thenReturn(token)
+
argumentCaptor<View.OnAttachStateChangeListener>()
.apply { verify(view).addOnAttachStateChangeListener(capture()) }
.firstValue
@@ -76,4 +75,58 @@ class ViewTransitionRegistryTest : SysuiTestCase() {
assertThat(underTest.getView(token)).isNull()
}
+
+ @Test
+ fun testMultipleRegisterOnSameView() {
+ val token = underTest.register(view)
+
+ // multiple register on same view should return same token
+ assertThat(underTest.register(view)).isEqualTo(token)
+
+ // 1st unregister doesn't remove the token from registry as refCount = 2
+ underTest.unregister(token)
+ assertThat(underTest.getView(token)).isNotNull()
+
+ // 2nd unregister removes the token from registry
+ underTest.unregister(token)
+ assertThat(underTest.getView(token)).isNull()
+ }
+
+ @Test
+ fun testMultipleRegisterOnSameViewRemovedAfterViewDetached() {
+ val view: View = mock()
+
+ val token = underTest.register(view)
+ whenever(view.getTag(R.id.tag_view_transition_token)).thenReturn(token)
+
+ assertThat(underTest.getViewToken(view)).isEqualTo(token)
+
+ // mock view's detach event
+ val caller = argumentCaptor<View.OnAttachStateChangeListener>()
+ .apply { verify(view).addOnAttachStateChangeListener(capture()) }
+ .firstValue
+
+ // register 3 times
+ underTest.register(view)
+ underTest.register(view)
+ underTest.register(view)
+
+ // unregister 1 time and verify entry should still be present in registry
+ underTest.unregister(token)
+ assertThat(underTest.getView(token)).isNotNull()
+
+ // view's associated entry should be gone from registry, after view detaches
+ caller.onViewDetachedFromWindow(view)
+ assertThat(underTest.getView(token)).isNull()
+ }
+
+ @Test
+ fun testDistinctViewsSameClassRegisterWithDifferentToken() {
+ var prev: ViewTransitionToken? = underTest.register(FrameLayout(mContext))
+ for (i in 0 until 10) {
+ val curr = underTest.register(FrameLayout(mContext))
+ assertThat(curr).isNotEqualTo(prev)
+ prev = curr
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 50762edc1179..88c9e74551fd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -21,6 +21,7 @@ import android.content.res.Configuration
import android.hardware.biometrics.BiometricAuthenticator
import android.hardware.biometrics.BiometricConstants
import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricPrompt
import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
@@ -290,7 +291,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
verify(callback)
.onDismissed(
- eq(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED),
+ eq(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L),
)
@@ -310,7 +311,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
)
verify(callback)
.onDismissed(
- eq(AuthDialogCallback.DISMISSED_USER_CANCELED),
+ eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L),
)
@@ -325,7 +326,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
verify(callback)
.onDismissed(
- eq(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE),
+ eq(BiometricPrompt.DISMISSED_REASON_NEGATIVE),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L),
)
@@ -352,7 +353,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
verify(callback)
.onDismissed(
- eq(AuthDialogCallback.DISMISSED_ERROR),
+ eq(BiometricPrompt.DISMISSED_REASON_ERROR),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L),
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
index acc97a9f8642..a1a2aa70d869 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -138,9 +138,9 @@ public class AuthControllerTest extends SysuiTestCase {
@Mock
private IBiometricContextListener mContextListener;
@Mock
- private AuthDialog mDialog1;
+ private AuthContainerView mDialog1;
@Mock
- private AuthDialog mDialog2;
+ private AuthContainerView mDialog2;
@Mock
private CommandQueue mCommandQueue;
@Mock
@@ -382,7 +382,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception {
showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -393,7 +393,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonNegative_whenDismissedByButtonNegative() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -404,7 +404,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonConfirmed_whenDismissedByButtonPositive() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -415,7 +415,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonConfirmNotRequired_whenDismissedByAuthenticated() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -426,7 +426,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonError_whenDismissedByError() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_ERROR,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_ERROR,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -437,7 +437,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonServerRequested_whenDismissedByServer() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -452,7 +452,7 @@ public class AuthControllerTest extends SysuiTestCase {
final byte[] credentialAttestation = generateRandomHAT();
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED,
credentialAttestation, mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED),
@@ -462,7 +462,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonContentViewMoreOptions_whenButtonPressed() throws Exception {
showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -696,7 +696,7 @@ public class AuthControllerTest extends SysuiTestCase {
final byte[] credentialAttestation = generateRandomHAT();
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED,
credentialAttestation, mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED),
@@ -755,7 +755,7 @@ public class AuthControllerTest extends SysuiTestCase {
public void testDoesNotCrash_whenTryAgainPressedAfterDismissal() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final long requestID = mAuthController.mCurrentDialog.getRequestId();
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
null, /* credentialAttestation */requestID);
mAuthController.onTryAgainPressed(requestID);
}
@@ -764,7 +764,7 @@ public class AuthControllerTest extends SysuiTestCase {
public void testDoesNotCrash_whenDeviceCredentialPressedAfterDismissal() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final long requestID = mAuthController.mCurrentDialog.getRequestId();
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
null /* credentialAttestation */, requestID);
mAuthController.onDeviceCredentialPressed(requestID);
}
@@ -818,7 +818,7 @@ public class AuthControllerTest extends SysuiTestCase {
// WHEN dialog is shown and then dismissed
showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
null /* credentialAttestation */,
mAuthController.mCurrentDialog.getRequestId());
@@ -1218,14 +1218,14 @@ public class AuthControllerTest extends SysuiTestCase {
}
@Override
- protected AuthDialog buildDialog(DelayableExecutor bgExecutor, PromptInfo promptInfo,
+ protected AuthContainerView buildDialog(DelayableExecutor bgExecutor, PromptInfo promptInfo,
boolean requireConfirmation, int userId, int[] sensorIds,
String opPackageName, boolean skipIntro, long operationId, long requestId,
WakefulnessLifecycle wakefulnessLifecycle,
UserManager userManager,
LockPatternUtils lockPatternUtils, PromptViewModel viewModel) {
- AuthDialog dialog;
+ AuthContainerView dialog;
if (mBuildCount == 0) {
dialog = mDialog1;
} else if (mBuildCount == 1) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
index 98486a22854a..af6c65ec6d6d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -538,7 +538,6 @@ object TestShortcuts {
simpleShortcutCategory(System, "System apps", "Open settings"),
simpleShortcutCategory(System, "System controls", "Lock screen"),
simpleShortcutCategory(System, "System controls", "View notifications"),
- simpleShortcutCategory(System, "System apps", "Take a note"),
simpleShortcutCategory(System, "System controls", "Take screenshot"),
simpleShortcutCategory(System, "System controls", "Go back"),
simpleShortcutCategory(MultiTasking, "Split screen", "Use full screen"),
@@ -570,7 +569,6 @@ object TestShortcuts {
simpleInputGestureData(
keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
),
- simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES),
simpleInputGestureData(
keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
index 208abf39611d..6c4325adced4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
@@ -35,12 +35,20 @@ package com.android.systemui.keyguard.domain.interactor
import android.os.PowerManager
import android.platform.test.annotations.DisableFlags
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.systemui.Flags
+import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.common.data.repository.batteryRepository
+import com.android.systemui.common.data.repository.fake
+import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalV2Available
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -54,6 +62,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
@@ -62,6 +72,8 @@ import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.testKosmos
+import com.android.systemui.util.settings.fakeSettings
+import com.google.common.truth.Truth
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.advanceTimeBy
@@ -416,4 +428,25 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
assertThat(transitionRepository)
.startedTransition(from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN)
}
+
+ @Test
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun testTransitionToGlanceableHub_onWakeUpFromAod() =
+ kosmos.runTest {
+ val user = setCommunalV2Available(true)
+ fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, user.id)
+ batteryRepository.fake.setDevicePluggedIn(true)
+
+ val currentScene by collectLastValue(communalSceneInteractor.currentScene)
+ fakeCommunalSceneRepository.changeScene(CommunalScenes.Blank)
+
+ // Communal is not showing
+ Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+
+ powerInteractor.setAwakeForTest()
+ testScope.advanceTimeBy(100) // account for debouncing
+
+ Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
+ assertThat(transitionRepository).noTransitionsStarted()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt
new file mode 100644
index 000000000000..052dfd52887f
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2025 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.kosmos.collectValues
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DozingToDreamingTransitionViewModelTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+
+ val underTest by lazy { kosmos.dozingToDreamingTransitionViewModel }
+
+ @Test
+ fun notificationShadeAlpha() =
+ kosmos.runTest {
+ val values by collectValues(underTest.notificationAlpha)
+ assertThat(values).isEmpty()
+
+ fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.DREAMING,
+ testScope,
+ )
+
+ assertThat(values).isNotEmpty()
+ values.forEach { assertThat(it).isEqualTo(0) }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
index 645efae16b8b..ab217a3f50ef 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
@@ -31,21 +31,18 @@ class MutableSelectionStateTest : SysuiTestCase() {
@Test
fun selectTile_isCorrectlySelected() {
- assertThat(underTest.selection?.tileSpec).isNotEqualTo(TEST_SPEC)
+ assertThat(underTest.selection).isNotEqualTo(TEST_SPEC)
- underTest.select(TEST_SPEC, manual = true)
- assertThat(underTest.selection?.tileSpec).isEqualTo(TEST_SPEC)
- assertThat(underTest.selection?.manual).isTrue()
+ underTest.select(TEST_SPEC)
+ assertThat(underTest.selection).isEqualTo(TEST_SPEC)
underTest.unSelect()
assertThat(underTest.selection).isNull()
val newSpec = TileSpec.create("newSpec")
- underTest.select(TEST_SPEC, manual = true)
- underTest.select(newSpec, manual = false)
- assertThat(underTest.selection?.tileSpec).isNotEqualTo(TEST_SPEC)
- assertThat(underTest.selection?.tileSpec).isEqualTo(newSpec)
- assertThat(underTest.selection?.manual).isFalse()
+ underTest.select(TEST_SPEC)
+ underTest.select(newSpec)
+ assertThat(underTest.selection).isEqualTo(newSpec)
}
companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
index fee358a7c15d..83860ecf168b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
@@ -63,6 +63,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
+import java.util.Optional;
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
@@ -100,7 +101,7 @@ public class RotationLockTileTest extends SysuiTestCase {
@Mock
private BatteryController mBatteryController;
@Mock
- DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+ Optional<DeviceStateRotationLockSettingController> mDeviceStateRotationLockSettingController;
@Mock
RotationPolicyWrapper mRotationPolicyWrapper;
@Mock
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
index c7b3175a636f..e044d1db92a9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
@@ -35,14 +35,14 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
-import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.shared.CallType
-import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
@@ -314,7 +314,7 @@ class CallChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_inCall_nullIntent_nullClickListener() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -325,7 +325,7 @@ class CallChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_inCall_positiveStartTime_validIntent_clickListenerLaunchesIntent() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -343,7 +343,7 @@ class CallChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_inCall_zeroStartTime_validIntent_clickListenerLaunchesIntent() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -362,7 +362,7 @@ class CallChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_inCall_nullIntent_noneClickBehavior() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -378,7 +378,7 @@ class CallChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_inCall_positiveStartTime_validIntent_clickBehaviorLaunchesIntent() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -403,7 +403,7 @@ class CallChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_inCall_zeroStartTime_validIntent_clickBehaviorLaunchesIntent() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
index 6cfad8540491..005af366a6c0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
@@ -17,8 +17,6 @@
package com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel
import android.content.DialogInterface
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -44,10 +42,10 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog
-import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
-import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization
import com.android.systemui.testKosmos
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -282,7 +280,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_notProjecting_clickListenerShowsDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -299,7 +297,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_projectingEntireScreen_clickListenerShowsDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -317,7 +315,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_projectingSingleTask_clickListenerShowsDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -339,7 +337,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_clickListenerHasCujLegacy() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -359,7 +357,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_recordingState_hasClickBehavior() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -370,7 +368,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_notProjecting_expandActionBehaviorShowsDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -386,7 +384,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_projectingEntireScreen_expandActionBehaviorShowsDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -401,7 +399,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_projectingSingleTask_expandActionBehaviorShowsDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
index e708382799c2..d6b10a89726e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
@@ -49,10 +49,10 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog
-import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
-import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization
import com.android.systemui.testKosmos
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -506,7 +506,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
@Test
@EnableFlags(FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP)
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_noScreen_clickListenerShowsGenericShareDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -527,7 +527,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_entireScreen_clickListenerShowsScreenShareDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -548,7 +548,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_singleTask_clickListenerShowsScreenShareDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -573,7 +573,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun chip_clickListenerHasCuj() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -597,7 +597,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_noScreen_hasClickBehavior() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -609,7 +609,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_entireScreen_hasClickBehavior() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -621,7 +621,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_singleTask_hasClickBehavior() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -637,11 +637,8 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(
- FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP,
- StatusBarRootModernization.FLAG_NAME,
- StatusBarChipsModernization.FLAG_NAME,
- )
+ @EnableFlags(FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP)
+ @EnableChipsModernization
fun chip_noScreen_clickBehaviorShowsGenericShareDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -657,7 +654,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_entireScreen_clickBehaviorShowsScreenShareDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -673,7 +670,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun chip_singleTask_clickBehaviorShowsScreenShareDialog() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt
index fc3af11c30b3..39b19d3c4191 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.chips.ui.viewmodel
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -31,9 +29,9 @@ import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener
-import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization
import kotlin.test.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyBoolean
@@ -64,7 +62,7 @@ class OngoingActivityChipViewModelTest : SysuiTestCase() {
mock<Expandable>().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) }
@Test
- @DisableFlags(StatusBarChipsModernization.FLAG_NAME)
+ @DisableChipsModernization
fun createDialogLaunchOnClickListener_showsDialogOnClick() {
val cuj = DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Test")
val clickListener =
@@ -82,7 +80,7 @@ class OngoingActivityChipViewModelTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun createDialogLaunchOnClickCallback_showsDialogOnClick() {
val cuj = DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Test")
val clickCallback =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
index 9d17348d95a0..bab349aa7a74 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone.ongoingcall.domain.interactor
import android.app.PendingIntent
-import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -29,12 +28,10 @@ import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.statusbar.StatusBarIconView
-import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
import com.android.systemui.statusbar.gesture.swipeStatusBarAwayGestureHandler
-import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
-import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.addOngoingCallState
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.removeOngoingCallState
@@ -52,10 +49,9 @@ import org.mockito.kotlin.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
-@EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+@EnableChipsModernization
class OngoingCallInteractorTest : SysuiTestCase() {
private val kosmos = Kosmos().useUnconfinedTestDispatcher()
- private val repository = kosmos.activeNotificationListRepository
private val underTest = kosmos.ongoingCallInteractor
@Before
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
index cd8ca23e0964..51484baf1b7b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
@@ -86,6 +86,7 @@ import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataS
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher
import com.android.systemui.statusbar.phone.data.repository.fakeDarkIconRepository
+import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarIconBlockList
import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarInteractorShowOperatorName
@@ -835,7 +836,7 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
}
@Test
- @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
+ @EnableChipsModernization
fun isNotificationIconContainerVisible_anyChipShowing_ChipsModernizationOn() =
kosmos.runTest {
val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
index 8593f6a08b5a..605e4a47275b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
@@ -37,15 +37,19 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@SmallTest
public class RotationLockControllerImplTest extends SysuiTestCase {
- private static final String[] DEFAULT_SETTINGS = new String[] {"0:0", "1:2"};
+ private static final String[] DEFAULT_SETTINGS = new String[]{"0:0", "1:2"};
- @Mock RotationPolicyWrapper mRotationPolicyWrapper;
- @Mock DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+ @Mock
+ RotationPolicyWrapper mRotationPolicyWrapper;
+ @Mock
+ DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
private ArgumentCaptor<RotationPolicy.RotationPolicyListener> mRotationPolicyListenerCaptor;
@@ -93,7 +97,7 @@ public class RotationLockControllerImplTest extends SysuiTestCase {
private void createRotationLockController(String[] deviceStateRotationLockDefaults) {
new RotationLockControllerImpl(
mRotationPolicyWrapper,
- mDeviceStateRotationLockSettingController,
+ Optional.of(mDeviceStateRotationLockSettingController),
deviceStateRotationLockDefaults);
}
}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6fe598435433..3fc46ed6c9d1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2560,6 +2560,9 @@
<!-- SysUI Tuner: Other section -->
<string name="other">Other</string>
+ <!-- Accessibility description of action to toggle QS tile size on click. It will read as "Double-tap to toggle the tile's size" in screen readers [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_toggle_tile_size_action">toggle the tile\'s size</string>
+
<!-- Accessibility description of action to remove QS tile on click. It will read as "Double-tap to remove tile" in screen readers [CHAR LIMIT=NONE] -->
<string name="accessibility_qs_edit_remove_tile_action">remove tile</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS b/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS
index 429b4b0fccab..329aa07fdd9e 100644
--- a/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS
@@ -3,6 +3,5 @@
dupin@google.com
linyuh@google.com
pauldpong@google.com
-praveenj@google.com
vicliang@google.com
yuklimko@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index b6537118324e..4c8a8f1c13d7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -33,6 +33,7 @@ import android.graphics.PixelFormat;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -100,7 +101,7 @@ import javax.inject.Provider;
*/
@Deprecated
public class AuthContainerView extends LinearLayout
- implements AuthDialog, WakefulnessLifecycle.Observer, CredentialView.Host {
+ implements WakefulnessLifecycle.Observer, CredentialView.Host {
private static final String TAG = "AuthContainerView";
@@ -158,12 +159,11 @@ public class AuthContainerView extends LinearLayout
private final Set<Integer> mFailedModalities = new HashSet<Integer>();
private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;
- private final @Background DelayableExecutor mBackgroundExecutor;
private final MSDLPlayer mMSDLPlayer;
// Non-null only if the dialog is in the act of dismissing and has not sent the reason yet.
- @Nullable @AuthDialogCallback.DismissedReason private Integer mPendingCallbackReason;
+ @Nullable @BiometricPrompt.DismissedReason private Integer mPendingCallbackReason;
// HAT received from LockSettingsService when credential is verified.
@Nullable private byte[] mCredentialAttestation;
@@ -188,18 +188,18 @@ public class AuthContainerView extends LinearLayout
final class BiometricCallback implements Spaghetti.Callback {
@Override
public void onAuthenticated() {
- animateAway(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED);
}
@Override
public void onUserCanceled() {
sendEarlyUserCanceled();
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
}
@Override
public void onButtonNegative() {
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE);
+ animateAway(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
}
@Override
@@ -210,12 +210,12 @@ public class AuthContainerView extends LinearLayout
@Override
public void onContentViewMoreOptionsButtonPressed() {
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS);
+ animateAway(BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS);
}
@Override
public void onError() {
- animateAway(AuthDialogCallback.DISMISSED_ERROR);
+ animateAway(BiometricPrompt.DISMISSED_REASON_ERROR);
}
@Override
@@ -234,20 +234,20 @@ public class AuthContainerView extends LinearLayout
@Override
public void onAuthenticatedAndConfirmed() {
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE);
+ animateAway(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED);
}
}
@Override
public void onCredentialMatched(@NonNull byte[] attestation) {
mCredentialAttestation = attestation;
- animateAway(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED);
}
@Override
public void onCredentialAborted() {
sendEarlyUserCanceled();
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
}
@Override
@@ -277,7 +277,7 @@ public class AuthContainerView extends LinearLayout
com.android.settingslib.R.string.failed_attempts_now_wiping_dialog_dismiss,
null /* OnClickListener */)
.setOnDismissListener(
- dialog -> animateAway(AuthDialogCallback.DISMISSED_ERROR))
+ dialog -> animateAway(BiometricPrompt.DISMISSED_REASON_ERROR))
.create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
alertDialog.show();
@@ -349,7 +349,6 @@ public class AuthContainerView extends LinearLayout
mPanelView = mLayout.findViewById(R.id.panel);
mPanelController = new AuthPanelController(mContext, mPanelView);
- mBackgroundExecutor = bgExecutor;
mInteractionJankMonitor = jankMonitor;
mCredentialViewModelProvider = credentialViewModelProvider;
@@ -394,7 +393,7 @@ public class AuthContainerView extends LinearLayout
@VisibleForTesting
public void onBackInvoked() {
sendEarlyUserCanceled();
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
}
void sendEarlyUserCanceled() {
@@ -402,7 +401,6 @@ public class AuthContainerView extends LinearLayout
BiometricConstants.BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL, getRequestId());
}
- @Override
public boolean isAllowDeviceCredentials() {
return Utils.isDeviceCredentialAllowed(mConfig.mPromptInfo);
}
@@ -450,7 +448,6 @@ public class AuthContainerView extends LinearLayout
mPanelController.setContainerDimensions(getMeasuredWidth(), getMeasuredHeight());
}
- @Override
public void onOrientationChanged() {
}
@@ -538,10 +535,9 @@ public class AuthContainerView extends LinearLayout
@Override
public void onStartedGoingToSleep() {
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
}
- @Override
public void show(WindowManager wm) {
wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle()));
}
@@ -559,7 +555,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void dismissWithoutCallback(boolean animate) {
if (animate) {
animateAway(false /* sendReason */, 0 /* reason */);
@@ -569,12 +564,10 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void dismissFromSystemServer() {
animateAway(false /* sendReason */, 0 /* reason */);
}
- @Override
public void onAuthenticationSucceeded(@Modality int modality) {
if (mBiometricView != null) {
mBiometricView.onAuthenticationSucceeded(modality);
@@ -583,7 +576,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void onAuthenticationFailed(@Modality int modality, String failureReason) {
if (mBiometricView != null) {
mFailedModalities.add(modality);
@@ -593,7 +585,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void onHelp(@Modality int modality, String help) {
if (mBiometricView != null) {
mBiometricView.onHelp(modality, help);
@@ -602,7 +593,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void onError(@Modality int modality, String error) {
if (mBiometricView != null) {
mBiometricView.onError(modality, error);
@@ -611,7 +601,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void onPointerDown() {
if (mBiometricView != null) {
if (mFailedModalities.contains(TYPE_FACE)) {
@@ -624,22 +613,18 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public String getOpPackageName() {
return mConfig.mOpPackageName;
}
- @Override
public String getClassNameIfItIsConfirmDeviceCredentialActivity() {
return mConfig.mPromptInfo.getClassNameIfItIsConfirmDeviceCredentialActivity();
}
- @Override
public long getRequestId() {
return mConfig.mRequestId;
}
- @Override
public void animateToCredentialUI(boolean isError) {
if (mBiometricView != null) {
mBiometricView.startTransitionToCredentialUI(isError);
@@ -648,11 +633,11 @@ public class AuthContainerView extends LinearLayout
}
}
- void animateAway(@AuthDialogCallback.DismissedReason int reason) {
+ void animateAway(@BiometricPrompt.DismissedReason int reason) {
animateAway(true /* sendReason */, reason);
}
- private void animateAway(boolean sendReason, @AuthDialogCallback.DismissedReason int reason) {
+ private void animateAway(boolean sendReason, @BiometricPrompt.DismissedReason int reason) {
if (mContainerState == STATE_ANIMATING_IN) {
Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn");
mContainerState = STATE_PENDING_DISMISS;
@@ -732,7 +717,7 @@ public class AuthContainerView extends LinearLayout
private void onDialogAnimatedIn() {
if (mContainerState == STATE_PENDING_DISMISS) {
Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now");
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
return;
}
if (mContainerState == STATE_ANIMATING_OUT || mContainerState == STATE_GONE) {
@@ -748,7 +733,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public PromptViewModel getViewModel() {
return mPromptViewModel;
}
@@ -776,7 +760,6 @@ public class AuthContainerView extends LinearLayout
return lp;
}
- @Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println(" isAttachedToWindow=" + isAttachedToWindow());
pw.println(" containerState=" + mContainerState);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index eee5f9e34317..68a282018ba4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -163,7 +163,7 @@ public class AuthController implements
// TODO: These should just be saved from onSaveState
private SomeArgs mCurrentDialogArgs;
@VisibleForTesting
- AuthDialog mCurrentDialog;
+ AuthContainerView mCurrentDialog;
@NonNull private final WindowManager mWindowManager;
@NonNull private final DisplayManager mDisplayManager;
@@ -222,7 +222,7 @@ public class AuthController implements
closeDialog(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, reasonString);
}
- private void closeDialog(@DismissedReason int reason, String reasonString) {
+ private void closeDialog(@BiometricPrompt.DismissedReason int reason, String reasonString) {
if (isShowing()) {
Log.i(TAG, "Close BP, reason :" + reasonString);
mCurrentDialog.dismissWithoutCallback(true /* animate */);
@@ -511,60 +511,14 @@ public class AuthController implements
}
@Override
- public void onDismissed(@DismissedReason int reason,
- @Nullable byte[] credentialAttestation, long requestId) {
-
+ public void onDismissed(@BiometricPrompt.DismissedReason int reason,
+ @Nullable byte[] credentialAttestation, long requestId) {
if (mCurrentDialog != null && requestId != mCurrentDialog.getRequestId()) {
Log.w(TAG, "requestId doesn't match, skip onDismissed");
return;
}
- switch (reason) {
- case AuthDialogCallback.DISMISSED_USER_CANCELED:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_NEGATIVE,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BUTTON_POSITIVE:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED:
- sendResultAndCleanUp(
- BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_ERROR:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_ERROR,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS:
- sendResultAndCleanUp(
- BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS,
- credentialAttestation);
- break;
- default:
- Log.e(TAG, "Unhandled reason: " + reason);
- break;
- }
+ sendResultAndCleanUp(reason, credentialAttestation);
}
@Override
@@ -699,7 +653,7 @@ public class AuthController implements
mUdfpsController.onAodInterrupt(screenX, screenY, major, minor);
}
- private void sendResultAndCleanUp(@DismissedReason int reason,
+ private void sendResultAndCleanUp(@BiometricPrompt.DismissedReason int reason,
@Nullable byte[] credentialAttestation) {
if (mReceiver == null) {
Log.e(TAG, "sendResultAndCleanUp: Receiver is null");
@@ -1244,7 +1198,7 @@ public class AuthController implements
final long requestId = args.argl2;
// Create a new dialog but do not replace the current one yet.
- final AuthDialog newDialog = buildDialog(
+ final AuthContainerView newDialog = buildDialog(
mBackgroundExecutor,
promptInfo,
requireConfirmation,
@@ -1327,7 +1281,7 @@ public class AuthController implements
return mContext.createDisplayContext(display).getSystemService(WindowManager.class);
}
- private void onDialogDismissed(@DismissedReason int reason) {
+ private void onDialogDismissed(@BiometricPrompt.DismissedReason int reason) {
if (DEBUG) Log.d(TAG, "onDialogDismissed: " + reason);
if (mCurrentDialog == null) {
Log.w(TAG, "Dialog already dismissed");
@@ -1361,7 +1315,7 @@ public class AuthController implements
}
}
- protected AuthDialog buildDialog(@Background DelayableExecutor bgExecutor,
+ protected AuthContainerView buildDialog(@Background DelayableExecutor bgExecutor,
PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds,
String opPackageName, boolean skipIntro, long operationId, long requestId,
@NonNull WakefulnessLifecycle wakefulnessLifecycle,
@@ -1389,7 +1343,7 @@ public class AuthController implements
@Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
- final AuthDialog dialog = mCurrentDialog;
+ final AuthContainerView dialog = mCurrentDialog;
pw.println(" mCachedDisplayInfo=" + mCachedDisplayInfo);
pw.println(" mScaleFactor=" + mScaleFactor);
pw.println(" fingerprintSensorLocationInNaturalOrientation="
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
deleted file mode 100644
index 861191671ba9..000000000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2019 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.biometrics;
-
-import android.hardware.biometrics.BiometricAuthenticator.Modality;
-import android.view.WindowManager;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
-
-/**
- * Interface for the biometric dialog UI.
- *
- * TODO(b/287311775): remove along with legacy controller once flag is removed
- */
-@Deprecated
-public interface AuthDialog extends Dumpable {
-
- /**
- * Parameters used when laying out {@link AuthBiometricView}, its subclasses, and
- * {@link AuthPanelController}.
- */
- class LayoutParams {
- public final int mMediumHeight;
- public final int mMediumWidth;
-
- public LayoutParams(int mediumWidth, int mediumHeight) {
- mMediumWidth = mediumWidth;
- mMediumHeight = mediumHeight;
- }
- }
-
- /**
- * Show the dialog.
- * @param wm
- */
- void show(WindowManager wm);
-
- /**
- * Dismiss the dialog without sending a callback.
- */
- void dismissWithoutCallback(boolean animate);
-
- /**
- * Dismiss the dialog. Animate away.
- */
- void dismissFromSystemServer();
-
- /**
- * Biometric authenticated. May be pending user confirmation, or completed.
- */
- void onAuthenticationSucceeded(@Modality int modality);
-
- /**
- * Authentication failed (reject, timeout). Dialog stays showing.
- * @param modality sensor modality that triggered the error
- * @param failureReason message
- */
- void onAuthenticationFailed(@Modality int modality, String failureReason);
-
- /**
- * Authentication rejected, or help message received.
- * @param modality sensor modality that triggered the help message
- * @param help message
- */
- void onHelp(@Modality int modality, String help);
-
- /**
- * Authentication failed. Dialog going away.
- * @param modality sensor modality that triggered the error
- * @param error message
- */
- void onError(@Modality int modality, String error);
-
- /** UDFPS pointer down event. */
- void onPointerDown();
-
- /**
- * Get the client's package name
- */
- String getOpPackageName();
-
- /**
- * Get the class name of ConfirmDeviceCredentialActivity. Returns null if the direct caller is
- * not ConfirmDeviceCredentialActivity.
- */
- String getClassNameIfItIsConfirmDeviceCredentialActivity();
-
- /** The requestId of the underlying operation within the framework. */
- long getRequestId();
-
- /**
- * Animate to credential UI. Typically called after biometric is locked out.
- */
- void animateToCredentialUI(boolean isError);
-
- /**
- * @return true if device credential is allowed.
- */
- boolean isAllowDeviceCredentials();
-
- /**
- * Called when the device's orientation changed and the dialog may need to do another
- * layout. This is most relevant to UDFPS since configuration changes are not sent by
- * the framework in equivalent cases (landscape to reverse landscape) but the dialog
- * must remain fixed on the physical sensor location.
- */
- void onOrientationChanged();
-
- PromptViewModel getViewModel();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
index 024c6eaa75bb..31c63d3c57e0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
@@ -16,40 +16,20 @@
package com.android.systemui.biometrics;
-import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.hardware.biometrics.BiometricPrompt;
/**
* Callback interface for dialog views. These should be implemented by the controller (e.g.
* FingerprintDialogImpl) and passed into their views (e.g. FingerprintDialogView).
*/
public interface AuthDialogCallback {
-
- int DISMISSED_USER_CANCELED = 1;
- int DISMISSED_BUTTON_NEGATIVE = 2;
- int DISMISSED_BUTTON_POSITIVE = 3;
- int DISMISSED_BIOMETRIC_AUTHENTICATED = 4;
- int DISMISSED_ERROR = 5;
- int DISMISSED_BY_SYSTEM_SERVER = 6;
- int DISMISSED_CREDENTIAL_AUTHENTICATED = 7;
- int DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS = 8;
-
- @IntDef({DISMISSED_USER_CANCELED,
- DISMISSED_BUTTON_NEGATIVE,
- DISMISSED_BUTTON_POSITIVE,
- DISMISSED_BIOMETRIC_AUTHENTICATED,
- DISMISSED_ERROR,
- DISMISSED_BY_SYSTEM_SERVER,
- DISMISSED_CREDENTIAL_AUTHENTICATED,
- DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS})
- @interface DismissedReason {}
-
/**
* Invoked when the dialog is dismissed
- * @param reason
+ * @param reason - the {@link BiometricPrompt.DismissedReason} for dismissing
* @param credentialAttestation the HAT received from LockSettingsService upon verification
*/
- void onDismissed(@DismissedReason int reason,
+ void onDismissed(@BiometricPrompt.DismissedReason int reason,
@Nullable byte[] credentialAttestation, long requestId);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 3c68e3a09f02..a25faa3a7aec 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -56,6 +56,7 @@ import com.android.systemui.reardisplay.RearDisplayModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
import com.android.systemui.recents.RecentsModule;
+import com.android.systemui.rotationlock.DeviceStateAutoRotateModule;
import com.android.systemui.rotationlock.RotationLockModule;
import com.android.systemui.rotationlock.RotationLockNewModule;
import com.android.systemui.scene.SceneContainerFrameworkModule;
@@ -132,6 +133,7 @@ import javax.inject.Named;
CollapsedStatusBarFragmentStartableModule.class,
ConnectingDisplayViewModel.StartableModule.class,
DefaultBlueprintModule.class,
+ DeviceStateAutoRotateModule.class,
EmergencyGestureModule.class,
GestureModule.class,
HeadsUpModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index fe5a82cb5b8c..f8cf6b007041 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -105,6 +105,7 @@ import com.android.systemui.qs.footer.dagger.FooterActionsModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.recordissue.RecordIssueModule;
import com.android.systemui.retail.RetailModeModule;
+import com.android.systemui.rotationlock.DeviceStateAutoRotateModule.BoundsDeviceStateAutoRotateModule;
import com.android.systemui.scene.shared.model.SceneContainerConfig;
import com.android.systemui.scene.shared.model.SceneDataSource;
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator;
@@ -145,6 +146,7 @@ import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.ConfigurationControllerModule;
import com.android.systemui.statusbar.phone.LetterboxModule;
import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule;
+import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.PolicyModule;
import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
@@ -391,6 +393,11 @@ public abstract class SystemUIModule {
@BindsOptionalOf
abstract LockscreenContent optionalLockscreenContent();
+ @BindsOptionalOf
+ @BoundsDeviceStateAutoRotateModule
+ abstract Optional<DeviceStateRotationLockSettingController>
+ optionalDeviceStateRotationLockSettingController();
+
@SysUISingleton
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
@@ -466,6 +473,16 @@ public abstract class SystemUIModule {
return new SceneDataSourceDelegator(applicationScope, config);
}
+ @Provides
+ @SysUISingleton
+ static Optional<DeviceStateRotationLockSettingController>
+ provideDeviceStateRotationLockSettingController(
+ @BoundsDeviceStateAutoRotateModule
+ Optional<Optional<DeviceStateRotationLockSettingController>> optionalOfOptional
+ ) {
+ return optionalOfOptional.orElseGet(Optional::empty);
+ }
+
@Binds
abstract SceneDataSource bindSceneDataSource(SceneDataSourceDelegator delegator);
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt
index 0908e3b5bf85..a779c4c998a7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt
@@ -31,7 +31,6 @@ import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN
import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW
import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY
import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
-import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES
import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER
import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS
import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER
@@ -67,7 +66,6 @@ class InputGestureMaps @Inject constructor(private val context: Context) {
KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to System,
KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to System,
KEY_GESTURE_TYPE_LOCK_SCREEN to System,
- KEY_GESTURE_TYPE_OPEN_NOTES to System,
KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to System,
KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to System,
KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to System,
@@ -113,7 +111,6 @@ class InputGestureMaps @Inject constructor(private val context: Context) {
R.string.shortcut_helper_category_system_controls,
KEY_GESTURE_TYPE_LOCK_SCREEN to R.string.shortcut_helper_category_system_controls,
KEY_GESTURE_TYPE_ALL_APPS to R.string.shortcut_helper_category_system_controls,
- KEY_GESTURE_TYPE_OPEN_NOTES to R.string.shortcut_helper_category_system_apps,
KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to
R.string.shortcut_helper_category_system_apps,
KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to R.string.shortcut_helper_category_system_apps,
@@ -173,7 +170,6 @@ class InputGestureMaps @Inject constructor(private val context: Context) {
R.string.group_system_access_notification_shade,
KEY_GESTURE_TYPE_LOCK_SCREEN to R.string.group_system_lock_screen,
KEY_GESTURE_TYPE_ALL_APPS to R.string.group_system_access_all_apps_search,
- KEY_GESTURE_TYPE_OPEN_NOTES to R.string.group_system_quick_memo,
KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to R.string.group_system_access_system_settings,
KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to R.string.group_system_access_google_assistant,
KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
index 8bed8537b6c5..a7375f7e7efc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
@@ -178,11 +178,6 @@ constructor(@Main private val resources: Resources, private val inputManager: In
private fun systemAppsShortcuts() =
listOf(
- // Pull up Notes app for quick memo:
- // - Meta + Ctrl + N
- shortcutInfo(resources.getString(R.string.group_system_quick_memo)) {
- command(META_META_ON or META_CTRL_ON, KEYCODE_N)
- },
// Access system settings:
// - Meta + I
shortcutInfo(resources.getString(R.string.group_system_access_system_settings)) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 4ad04bef6836..ef06a85bd0d9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -20,6 +20,10 @@ import android.animation.ValueAnimator
import android.util.Log
import com.android.app.animation.Interpolators
import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -54,6 +58,9 @@ constructor(
keyguardOcclusionInteractor: KeyguardOcclusionInteractor,
val deviceEntryRepository: DeviceEntryRepository,
private val wakeToGoneInteractor: KeyguardWakeDirectlyToGoneInteractor,
+ private val communalSettingsInteractor: CommunalSettingsInteractor,
+ private val communalSceneInteractor: CommunalSceneInteractor,
+ private val communalInteractor: CommunalInteractor,
) :
TransitionInteractor(
fromState = KeyguardState.AOD,
@@ -103,6 +110,7 @@ constructor(
val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value
val biometricUnlockMode = keyguardInteractor.biometricUnlockState.value.mode
val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value
+ val shouldShowCommunal = communalInteractor.shouldShowCommunal.value
if (!maybeHandleInsecurePowerGesture()) {
val shouldTransitionToLockscreen =
@@ -129,6 +137,9 @@ constructor(
(!KeyguardWmStateRefactor.isEnabled && canDismissLockscreen()) ||
(KeyguardWmStateRefactor.isEnabled && canWakeDirectlyToGone)
+ val shouldTransitionToCommunal =
+ communalSettingsInteractor.isV2FlagEnabled() && shouldShowCommunal
+
if (shouldTransitionToGone) {
// TODO(b/360368320): Adapt for scene framework
if (SceneContainerFlag.isEnabled) return@collect
@@ -137,6 +148,11 @@ constructor(
modeOnCanceled = TransitionModeOnCanceled.REVERSE,
ownerReason = "canWakeDirectlyToGone = true",
)
+ } else if (shouldTransitionToCommunal) {
+ communalSceneInteractor.changeScene(
+ CommunalScenes.Communal,
+ "listen for aod to communal",
+ )
} else if (shouldTransitionToLockscreen) {
val modeOnCanceled =
if (startedStep.from == KeyguardState.LOCKSCREEN) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 6f5f662d6fa3..0700ec639153 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -159,6 +159,7 @@ constructor(
val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value
val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value
val isKeyguardGoingAway = keyguardInteractor.isKeyguardGoingAway.value
+ val canStartDreaming = dreamManager.canStartDreaming(false)
if (!deviceEntryInteractor.isLockscreenEnabled()) {
if (!SceneContainerFlag.isEnabled) {
@@ -191,6 +192,13 @@ constructor(
if (!SceneContainerFlag.isEnabled) {
transitionToGlanceableHub()
}
+ } else if (canStartDreaming) {
+ // If we're waking up to dream, transition directly to dreaming without
+ // showing the lockscreen.
+ startTransitionTo(
+ KeyguardState.DREAMING,
+ ownerReason = "moving from doze to dream",
+ )
} else {
startTransitionTo(KeyguardState.LOCKSCREEN)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index 2eeba0f10e0c..3ad862b761fc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -77,7 +77,7 @@ constructor(
if (!communalSettingsInteractor.isCommunalFlagEnabled()) {
return
}
- listenForHubToDozing()
+ listenForHubToAodOrDozing()
listenForHubToPrimaryBouncer()
listenForHubToAlternateBouncer()
listenForHubToOccluded()
@@ -123,15 +123,15 @@ constructor(
}
}
- private fun listenForHubToDozing() {
+ private fun listenForHubToAodOrDozing() {
scope.launch {
powerInteractor.isAsleep
.filterRelevantKeyguardStateAnd { isAsleep -> isAsleep }
.collect {
- communalSceneInteractor.snapToScene(
+ communalSceneInteractor.changeScene(
newScene = CommunalScenes.Blank,
- loggingReason = "hub to dozing",
- keyguardState = KeyguardState.DOZING,
+ loggingReason = "hub to sleep",
+ keyguardState = keyguardInteractor.asleepKeyguardState.value,
)
}
}
@@ -254,5 +254,6 @@ constructor(
val TO_LOCKSCREEN_DURATION = 1.seconds
val TO_BOUNCER_DURATION = 400.milliseconds
val TO_OCCLUDED_DURATION = 450.milliseconds
+ val TO_AOD_DURATION = 500.milliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
index dba2578f79da..c4a7e1ed95e1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
@@ -21,6 +21,7 @@ import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransiti
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AodToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToOccludedTransitionViewModel
@@ -33,6 +34,7 @@ import com.android.systemui.keyguard.ui.viewmodel.DozingToPrimaryBouncerTransiti
import com.android.systemui.keyguard.ui.viewmodel.DreamingToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel
@@ -118,6 +120,12 @@ abstract class DeviceEntryIconTransitionModule {
@Binds
@IntoSet
+ abstract fun aodToGlanceableHub(
+ impl: AodToGlanceableHubTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
abstract fun dozingToGone(impl: DozingToGoneTransitionViewModel): DeviceEntryIconTransition
@Binds
@@ -258,6 +266,12 @@ abstract class DeviceEntryIconTransitionModule {
@Binds
@IntoSet
+ abstract fun glanceableHubToAod(
+ impl: GlanceableHubToAodTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
abstract fun occludedToGlanceableHub(
impl: OccludedToGlanceableHubTransitionViewModel
): DeviceEntryIconTransition
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModel.kt
new file mode 100644
index 000000000000..45f8f10595e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModel.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2025 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.keyguard.ui.viewmodel
+
+import android.util.MathUtils
+import com.android.systemui.Flags.lightRevealMigration
+import com.android.systemui.communal.ui.compose.TransitionDuration
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent
+import com.android.systemui.keyguard.shared.model.Edge
+import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition
+import com.android.systemui.scene.shared.model.Scenes
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class AodToGlanceableHubTransitionViewModel
+@Inject
+constructor(
+ animationFlow: KeyguardTransitionAnimationFlow,
+ blurFactory: GlanceableHubBlurComponent.Factory,
+) : DeviceEntryIconTransition, GlanceableHubTransition {
+ private val transitionAnimation =
+ animationFlow
+ .setup(
+ duration = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS.milliseconds,
+ edge = Edge.create(AOD, Scenes.Communal),
+ )
+ .setupWithoutSceneContainer(edge = Edge.create(AOD, GLANCEABLE_HUB))
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(1f)
+
+ /** Fade out the lockscreen during a transition to GLANCEABLE_HUB. */
+ fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
+ var currentAlpha = 0f
+ return transitionAnimation.sharedFlow(
+ duration = 250.milliseconds,
+ startTime =
+ if (lightRevealMigration()) {
+ 100.milliseconds // Wait for the light reveal to "hit" the LS elements.
+ } else {
+ 0.milliseconds
+ },
+ onStart = {
+ currentAlpha =
+ if (lightRevealMigration()) {
+ viewState.alpha()
+ } else {
+ 0f
+ }
+ },
+ onStep = { MathUtils.lerp(currentAlpha, 0f, it) },
+ )
+ }
+
+ override val windowBlurRadius: Flow<Float> =
+ blurFactory.create(transitionAnimation).getBlurProvider().enterBlurRadius
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 75bba489f893..0ccb24a9858a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -60,6 +60,7 @@ constructor(
primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel,
primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel,
lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
+ glanceableHubToAodTransitionViewModel: GlanceableHubToAodTransitionViewModel,
) {
val color: Flow<Int> =
deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground ->
@@ -106,6 +107,7 @@ constructor(
primaryBouncerToLockscreenTransitionViewModel
.deviceEntryBackgroundViewAlpha,
lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ glanceableHubToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
)
.merge()
.onStart {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt
index e6a85c6860c5..9018c58a7e36 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt
@@ -39,4 +39,6 @@ constructor(animationFlow: KeyguardTransitionAnimationFlow) {
)
val lockscreenAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(0f)
+ // Notifications should not be shown while transitioning to dream.
+ val notificationAlpha = transitionAnimation.immediatelyTransitionTo(0f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModel.kt
new file mode 100644
index 000000000000..6a45845a02c6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModel.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2025 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromGlanceableHubTransitionInteractor
+import com.android.systemui.keyguard.shared.model.Edge
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import com.android.systemui.scene.shared.model.Scenes
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class GlanceableHubToAodTransitionViewModel
+@Inject
+constructor(
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+ animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+
+ private val transitionAnimation =
+ animationFlow
+ .setup(
+ duration = FromGlanceableHubTransitionInteractor.TO_AOD_DURATION,
+ edge = Edge.create(from = Scenes.Communal, to = AOD),
+ )
+ .setupWithoutSceneContainer(edge = Edge.create(KeyguardState.GLANCEABLE_HUB, AOD))
+
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(0f)
+
+ /** Lockscreen views alpha */
+ val lockscreenAlpha: Flow<Float> =
+ transitionAnimation.sharedFlow(
+ startTime = 233.milliseconds,
+ duration = 250.milliseconds,
+ onStep = { it },
+ )
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled
+ ->
+ if (udfpsEnrolledAndEnabled) {
+ transitionAnimation.immediatelyTransitionTo(1f)
+ } else {
+ emptyFlow()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 8e21745e1a31..def87a8e2717 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -100,6 +100,7 @@ constructor(
private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
private val aodToOccludedTransitionViewModel: AodToOccludedTransitionViewModel,
private val aodToPrimaryBouncerTransitionViewModel: AodToPrimaryBouncerTransitionViewModel,
+ private val aodToGlanceableHubTransitionViewModel: AodToGlanceableHubTransitionViewModel,
private val dozingToDreamingTransitionViewModel: DozingToDreamingTransitionViewModel,
private val dozingToGoneTransitionViewModel: DozingToGoneTransitionViewModel,
private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
@@ -111,6 +112,7 @@ constructor(
private val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
private val glanceableHubToLockscreenTransitionViewModel:
GlanceableHubToLockscreenTransitionViewModel,
+ private val glanceableHubToAodTransitionViewModel: GlanceableHubToAodTransitionViewModel,
private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
private val goneToDreamingTransitionViewModel: GoneToDreamingTransitionViewModel,
@@ -258,6 +260,7 @@ constructor(
aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
aodToOccludedTransitionViewModel.lockscreenAlpha(viewState),
aodToPrimaryBouncerTransitionViewModel.lockscreenAlpha,
+ aodToGlanceableHubTransitionViewModel.lockscreenAlpha(viewState),
dozingToDreamingTransitionViewModel.lockscreenAlpha,
dozingToGoneTransitionViewModel.lockscreenAlpha(viewState),
dozingToLockscreenTransitionViewModel.lockscreenAlpha,
@@ -267,6 +270,7 @@ constructor(
dreamingToGoneTransitionViewModel.lockscreenAlpha,
dreamingToLockscreenTransitionViewModel.lockscreenAlpha,
glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
+ glanceableHubToAodTransitionViewModel.lockscreenAlpha,
goneToAodTransitionViewModel.enterFromTopAnimationAlpha,
goneToDozingTransitionViewModel.lockscreenAlpha,
goneToDreamingTransitionViewModel.lockscreenAlpha,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt
index 302242ca11dd..eb6f97942ec0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt
@@ -19,8 +19,6 @@ package com.android.systemui.qs.panels.ui.compose
import androidx.compose.runtime.Stable
import com.android.compose.animation.Bounceable
import com.android.systemui.qs.panels.shared.model.SizedTile
-import com.android.systemui.qs.panels.ui.model.GridCell
-import com.android.systemui.qs.panels.ui.model.TileGridCell
import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
@@ -32,18 +30,6 @@ data class BounceableInfo(
val bounceEnd: Boolean,
)
-fun List<Pair<GridCell, BounceableTileViewModel>>.bounceableInfo(
- index: Int,
- columns: Int,
-): BounceableInfo {
- val cell = this[index].first as TileGridCell
- // Only look for neighbor bounceables if they are on the same row
- val onLastColumn = cell.onLastColumn(cell.column, columns)
- val previousTile = getOrNull(index - 1)?.takeIf { cell.column != 0 }
- val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn }
- return BounceableInfo(this[index].second, previousTile?.second, nextTile?.second, !onLastColumn)
-}
-
fun List<BounceableTileViewModel>.bounceableInfo(
sizedTile: SizedTile<TileViewModel>,
index: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
index ebfe101948c2..ddadb8879f07 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
@@ -22,7 +22,6 @@ import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.animateDpAsState
-import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@@ -34,7 +33,6 @@ import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.clipScrollableContainer
import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
@@ -47,28 +45,27 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeightIn
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyGridScope
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.systemGestureExclusion
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Clear
-import androidx.compose.material.icons.filled.Remove
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
-import androidx.compose.material3.LocalMinimumInteractiveComponentSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
@@ -91,12 +88,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.isSpecified
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.onGloballyPositioned
@@ -113,24 +107,17 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import androidx.compose.ui.unit.toSize
import androidx.compose.ui.util.fastMap
-import androidx.compose.ui.zIndex
-import com.android.app.tracing.coroutines.launchTraced as launch
-import com.android.compose.animation.bounceable
import com.android.compose.modifiers.height
import com.android.systemui.common.ui.compose.load
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
-import com.android.systemui.qs.panels.ui.compose.BounceableInfo
import com.android.systemui.qs.panels.ui.compose.DragAndDropState
import com.android.systemui.qs.panels.ui.compose.DragType
import com.android.systemui.qs.panels.ui.compose.EditTileListState
-import com.android.systemui.qs.panels.ui.compose.bounceableInfo
import com.android.systemui.qs.panels.ui.compose.dragAndDropRemoveZone
import com.android.systemui.qs.panels.ui.compose.dragAndDropTileList
import com.android.systemui.qs.panels.ui.compose.dragAndDropTileSource
@@ -142,13 +129,14 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaul
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AUTO_SCROLL_SPEED
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AvailableTilesGridMinHeight
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding
-import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.TileBadgeSize
+import com.android.systemui.qs.panels.ui.compose.selection.InteractiveTileContainer
import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState
-import com.android.systemui.qs.panels.ui.compose.selection.ResizableTileContainer
import com.android.systemui.qs.panels.ui.compose.selection.ResizingState
import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation
import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.FinalResizeOperation
import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.TemporaryResizeOperation
+import com.android.systemui.qs.panels.ui.compose.selection.StaticTileBadge
+import com.android.systemui.qs.panels.ui.compose.selection.TileState
import com.android.systemui.qs.panels.ui.compose.selection.rememberResizingState
import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState
import com.android.systemui.qs.panels.ui.compose.selection.selectableTile
@@ -252,13 +240,15 @@ fun DefaultEditTileGrid(
AnimatedContent(
targetState = listState.dragInProgress || selectionState.selected,
label = "QSEditHeader",
+ contentAlignment = Alignment.Center,
+ modifier = Modifier.fillMaxWidth().heightIn(min = 80.dp),
) { showRemoveTarget ->
- EditGridHeader(Modifier.padding(bottom = 26.dp)) {
+ EditGridHeader {
if (showRemoveTarget) {
RemoveTileTarget {
selectionState.selection?.let {
selectionState.unSelect()
- onRemoveTile(it.tileSpec)
+ onRemoveTile(it)
}
}
} else {
@@ -380,7 +370,7 @@ private fun RemoveTileTarget(onClick: () -> Unit) {
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = tileHorizontalArrangement(),
modifier =
- Modifier.fillMaxHeight()
+ Modifier.wrapContentSize()
.clickable(onClick = onClick)
.border(1.dp, LocalContentColor.current, shape = CircleShape)
.padding(10.dp),
@@ -430,22 +420,15 @@ private fun CurrentTilesGrid(
)
.dragAndDropTileList(gridState, { gridContentOffset }, listState) { spec ->
onSetTiles(currentListState.tileSpecs())
- selectionState.select(spec, manual = false)
+ selectionState.select(spec)
}
.onGloballyPositioned { coordinates ->
gridContentOffset = coordinates.positionInRoot()
}
.testTag(CURRENT_TILES_GRID_TEST_TAG),
) {
- EditTiles(
- cells,
- columns,
- listState,
- selectionState,
- coroutineScope,
- largeTilesSpan,
- onRemoveTile,
- ) { resizingOperation ->
+ EditTiles(cells, listState, selectionState, coroutineScope, largeTilesSpan, onRemoveTile) {
+ resizingOperation ->
when (resizingOperation) {
is TemporaryResizeOperation -> {
currentListState.resizeTile(resizingOperation.spec, resizingOperation.toIcon)
@@ -453,10 +436,6 @@ private fun CurrentTilesGrid(
is FinalResizeOperation -> {
// Commit the new size of the tile
onResize(resizingOperation.spec, resizingOperation.toIcon)
-
- // Mark the selection as automatic in case the tile ends up moving to a
- // different row with its new size.
- selectionState.select(resizingOperation.spec, manual = false)
}
}
}
@@ -536,7 +515,6 @@ private fun GridCell.key(index: Int): Any {
* Adds a list of [GridCell] to the lazy grid
*
* @param cells the pairs of [GridCell] to [BounceableTileViewModel]
- * @param columns the number of columns of this tile grid
* @param dragAndDropState the [DragAndDropState] for this grid
* @param selectionState the [MutableSelectionState] for this grid
* @param coroutineScope the [CoroutineScope] to be used for the tiles
@@ -545,7 +523,6 @@ private fun GridCell.key(index: Int): Any {
*/
fun LazyGridScope.EditTiles(
cells: List<Pair<GridCell, BounceableTileViewModel>>,
- columns: Int,
dragAndDropState: DragAndDropState,
selectionState: MutableSelectionState,
coroutineScope: CoroutineScope,
@@ -581,7 +558,6 @@ fun LazyGridScope.EditTiles(
onResize = onResize,
onRemoveTile = onRemoveTile,
coroutineScope = coroutineScope,
- bounceableInfo = cells.bounceableInfo(index, columns),
largeTilesSpan = largeTilesSpan,
modifier = Modifier.animateItem(),
)
@@ -601,83 +577,84 @@ private fun TileGridCell(
onRemoveTile: (TileSpec) -> Unit,
coroutineScope: CoroutineScope,
largeTilesSpan: Int,
- bounceableInfo: BounceableInfo,
modifier: Modifier = Modifier,
) {
val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
- var selected by remember { mutableStateOf(false) }
- val showRemovalBadge =
- !selected && cell.tile.availableEditActions.contains(AvailableEditActions.REMOVE)
- val selectionAlpha by
- animateFloatAsState(
- targetValue = if (selected) 1f else 0f,
- label = "QSEditTileSelectionAlpha",
- )
- val selectionColor = MaterialTheme.colorScheme.primary
- val colors = EditModeTileDefaults.editTileColors()
- val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
-
- LaunchedEffect(selectionState.selection?.tileSpec) {
- selectionState.selection?.let {
- // A delay is introduced on automatic selections such as dragged tiles or reflow caused
- // by resizing. This avoids clipping issues on the border and resizing handle, as well
- // as letting the selection animation play correctly.
- if (!it.manual) {
- delay(250)
+ val canShowRemovalBadge = cell.tile.availableEditActions.contains(AvailableEditActions.REMOVE)
+ var tileState by remember { mutableStateOf(TileState.None) }
+
+ LaunchedEffect(selectionState.selection, canShowRemovalBadge) {
+ tileState =
+ when {
+ selectionState.selection == cell.tile.tileSpec -> {
+ if (tileState == TileState.None && canShowRemovalBadge) {
+ // The tile decoration is None if a tile is newly composed OR the removal
+ // badge can't be shown.
+ // For newly composed and selected tiles, such as dragged tiles or moved
+ // tiles from resizing, introduce a short delay. This avoids clipping issues
+ // on the border and resizing handle, as well as letting the selection
+ // animation play correctly.
+ delay(250)
+ }
+ TileState.Selected
+ }
+ canShowRemovalBadge -> TileState.Removable
+ else -> TileState.None
}
- }
- selected = selectionState.selection?.tileSpec == cell.tile.tileSpec
}
- val state = rememberResizingState(cell.tile.tileSpec, cell.isIcon)
-
+ val resizingState = rememberResizingState(cell.tile.tileSpec, cell.isIcon)
val progress: () -> Float = {
- if (selected) {
- // If selected, return the manual progress from the drag
- state.progress()
+ if (tileState == TileState.Selected) {
+ resizingState.progress()
} else {
- // Else, return the target progress for the tile format
if (cell.isIcon) 0f else 1f
}
}
- if (!selected) {
+ if (tileState != TileState.Selected) {
// Update the draggable anchor state when the tile's size is not manually toggled
- LaunchedEffect(cell.isIcon) { state.updateCurrentValue(cell.isIcon) }
+ LaunchedEffect(cell.isIcon) { resizingState.updateCurrentValue(cell.isIcon) }
} else {
// If the tile is selected, listen to new target values from the draggable anchor to toggle
// the tile's size
- LaunchedEffect(state.temporaryResizeOperation) { onResize(state.temporaryResizeOperation) }
- LaunchedEffect(state.finalResizeOperation) { onResize(state.finalResizeOperation) }
+ LaunchedEffect(resizingState.temporaryResizeOperation) {
+ onResize(resizingState.temporaryResizeOperation)
+ }
+ LaunchedEffect(resizingState.finalResizeOperation) {
+ onResize(resizingState.finalResizeOperation)
+ }
}
val totalPadding =
with(LocalDensity.current) { (largeTilesSpan - 1) * TileArrangementPadding.roundToPx() }
-
- ResizableTileContainer(
- selected = selected,
- state = state,
- selectionAlpha = { selectionAlpha },
- selectionColor = selectionColor,
+ val colors = EditModeTileDefaults.editTileColors()
+ val toggleSizeLabel = stringResource(R.string.accessibility_qs_edit_toggle_tile_size_action)
+ val clickLabel =
+ when (tileState) {
+ TileState.None -> null
+ TileState.Removable ->
+ stringResource(id = R.string.accessibility_qs_edit_remove_tile_action)
+ TileState.Selected -> toggleSizeLabel
+ }
+ InteractiveTileContainer(
+ tileState = tileState,
+ resizingState = resizingState,
modifier =
- modifier
- .height(TileHeight)
- .fillMaxWidth()
- .onSizeChanged {
- // Grab the size before the bounceable to get the idle width
- val min =
- if (cell.isIcon) it.width else (it.width - totalPadding) / largeTilesSpan
- val max =
- if (cell.isIcon) (it.width * largeTilesSpan) + totalPadding else it.width
- state.updateAnchors(min.toFloat(), max.toFloat())
- }
- .bounceable(
- bounceable = currentBounceableInfo.bounceable,
- previousBounceable = currentBounceableInfo.previousTile,
- nextBounceable = currentBounceableInfo.nextTile,
- orientation = Orientation.Horizontal,
- bounceEnd = currentBounceableInfo.bounceEnd,
- ),
+ modifier.height(TileHeight).fillMaxWidth().onSizeChanged {
+ // Calculate the min/max width from the idle size
+ val min = if (cell.isIcon) it.width else (it.width - totalPadding) / largeTilesSpan
+ val max = if (cell.isIcon) (it.width * largeTilesSpan) + totalPadding else it.width
+ resizingState.updateAnchors(min.toFloat(), max.toFloat())
+ },
+ onClick = {
+ if (tileState == TileState.Removable) {
+ onRemoveTile(cell.tile.tileSpec)
+ } else if (tileState == TileState.Selected) {
+ coroutineScope.launch { resizingState.toggleCurrentValue() }
+ }
+ },
+ onClickLabel = clickLabel,
) {
Box(
modifier
@@ -688,15 +665,13 @@ private fun TileGridCell(
customActions =
listOf(
// TODO(b/367748260): Add final accessibility actions
- CustomAccessibilityAction("Toggle size") {
+ CustomAccessibilityAction(toggleSizeLabel) {
onResize(FinalResizeOperation(cell.tile.tileSpec, !cell.isIcon))
true
}
)
}
- .selectableTile(cell.tile.tileSpec, selectionState) {
- coroutineScope.launch { currentBounceableInfo.bounceable.animateBounce() }
- }
+ .selectableTile(cell.tile.tileSpec, selectionState)
.dragAndDropTileSource(
SizedTileImpl(cell.tile, cell.width),
dragAndDropState,
@@ -705,16 +680,7 @@ private fun TileGridCell(
)
.tileBackground(colors.background)
) {
- EditTile(tile = cell.tile, state = state, progress = progress)
- }
-
- if (showRemovalBadge) {
- TileBadge(
- icon = Icons.Default.Remove,
- contentDescription = stringResource(R.string.qs_customize_remove),
- ) {
- onRemoveTile(cell.tile.tileSpec)
- }
+ EditTile(tile = cell.tile, state = resizingState, progress = progress)
}
}
}
@@ -733,7 +699,7 @@ private fun AvailableTileGridCell(
val colors = EditModeTileDefaults.editTileColors()
val onClick = {
onAddTile(cell.tile.tileSpec)
- selectionState.select(cell.tile.tileSpec, manual = false)
+ selectionState.select(cell.tile.tileSpec)
}
// Displays the tile as an icon tile with the label underneath
@@ -742,10 +708,9 @@ private fun AvailableTileGridCell(
verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top),
modifier = modifier,
) {
- Box {
+ Box(Modifier.fillMaxWidth().height(TileHeight)) {
Box(
- Modifier.fillMaxWidth()
- .height(TileHeight)
+ Modifier.fillMaxSize()
.clickable(onClick = onClick, onClickLabel = onClickActionName)
.semantics(mergeDescendants = true) { this.stateDescription = stateDescription }
.dragAndDropTileSource(
@@ -756,7 +721,6 @@ private fun AvailableTileGridCell(
selectionState.unSelect()
}
.tileBackground(colors.background)
- .tilePadding()
) {
// Icon
SmallTileContent(
@@ -767,7 +731,7 @@ private fun AvailableTileGridCell(
)
}
- TileBadge(
+ StaticTileBadge(
icon = Icons.Default.Add,
contentDescription = onClickActionName,
onClick = onClick,
@@ -787,39 +751,6 @@ private fun AvailableTileGridCell(
}
@Composable
-private fun TileBadge(icon: ImageVector, contentDescription: String?, onClick: () -> Unit) {
- // Use a higher zIndex than the tile to draw over it, and manually create the touch target as
- // we're drawing over neighbor tiles as well.
- val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
-
- Box(
- Modifier.zIndex(2f)
- .layout { measurable, constraints ->
- val size = minTouchTargetSize.roundToPx()
- val placeable = measurable.measure(Constraints(size))
- layout(placeable.width, placeable.height) {
- val iconRadius = TileBadgeSize.roundToPx() / 2
- val x = constraints.maxWidth - placeable.width / 2 - iconRadius
- val y = 0 - placeable.height / 2 + iconRadius
- placeable.place(x, y)
- }
- }
- .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
- .pointerInput(Unit) { detectTapGestures { onClick() } }
- ) {
- val secondaryColor = MaterialTheme.colorScheme.secondary
- Icon(
- icon,
- contentDescription = contentDescription,
- modifier =
- Modifier.size(TileBadgeSize).align(Alignment.Center).drawBehind {
- drawCircle(secondaryColor)
- },
- )
- }
-}
-
-@Composable
private fun SpacerGridCell(modifier: Modifier = Modifier) {
// By default, spacers are invisible and exist purely to catch drag movements
Box(modifier.height(TileHeight).fillMaxWidth())
@@ -902,9 +833,8 @@ private object EditModeTileDefaults {
const val PLACEHOLDER_ALPHA = .3f
const val AUTO_SCROLL_DISTANCE = 100
const val AUTO_SCROLL_SPEED = 2 // 2ms per pixel
- val CurrentTilesGridPadding = 8.dp
+ val CurrentTilesGridPadding = 10.dp
val AvailableTilesGridMinHeight = 200.dp
- val TileBadgeSize = 20.dp
@Composable
fun editTileColors(): TileColors =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
index 26dfc7224ff9..3dfde86bf8d9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
@@ -32,23 +32,17 @@ fun rememberSelectionState(): MutableSelectionState {
return remember { MutableSelectionState() }
}
-/**
- * Holds the selected [TileSpec] and whether the selection was manual, i.e. caused by a tap from the
- * user.
- */
-data class Selection(val tileSpec: TileSpec, val manual: Boolean)
-
/** Holds the state of the current selection. */
class MutableSelectionState {
- /** The [Selection] if a tile is selected, null if not. */
- var selection by mutableStateOf<Selection?>(null)
+ /** The [TileSpec] of a tile is selected, null if not. */
+ var selection by mutableStateOf<TileSpec?>(null)
private set
val selected: Boolean
get() = selection != null
- fun select(tileSpec: TileSpec, manual: Boolean) {
- selection = Selection(tileSpec, manual)
+ fun select(tileSpec: TileSpec) {
+ selection = tileSpec
}
fun unSelect() {
@@ -68,10 +62,10 @@ fun Modifier.selectableTile(
return pointerInput(Unit) {
detectTapGestures(
onTap = {
- if (selectionState.selection?.tileSpec == tileSpec) {
+ if (selectionState.selection == tileSpec) {
selectionState.unSelect()
} else {
- selectionState.select(tileSpec, manual = true)
+ selectionState.select(tileSpec)
}
onClick()
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
index 7c472638da63..699e5f6b77e9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
@@ -16,141 +16,232 @@
package com.android.systemui.qs.panels.ui.compose.selection
-import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.animateDpAsState
-import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.core.spring
-import androidx.compose.foundation.Canvas
+import androidx.compose.animation.animateColor
+import androidx.compose.animation.core.Transition
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.animateOffset
+import androidx.compose.animation.core.animateSize
+import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.anchoredDraggable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.systemGestureExclusion
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Remove
+import androidx.compose.material3.Icon
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.geometry.center
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.layout
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize
import androidx.compose.ui.zIndex
+import com.android.compose.modifiers.size
import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
-import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingDotSize
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BADGE_ANGLE_RAD
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BadgeSize
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BadgeXOffset
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BadgeYOffset
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.RESIZING_PILL_ANGLE_RAD
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingPillHeight
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingPillWidth
import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.SelectedBorderWidth
+import com.android.systemui.qs.panels.ui.compose.selection.TileState.None
+import com.android.systemui.qs.panels.ui.compose.selection.TileState.Removable
+import com.android.systemui.qs.panels.ui.compose.selection.TileState.Selected
+import kotlin.math.cos
import kotlin.math.roundToInt
-import kotlinx.coroutines.launch
+import kotlin.math.sin
/**
- * Places a dot to handle resizing drag events. Use this on tiles to resize.
+ * Draws a tile decoration and handles click and drag events for them.
*
- * The dot is placed vertically centered on the right border. The [content] will have a border when
- * selected.
+ * In states:
+ * - [TileState.Removable]: removal icon shown in the top end
+ * - [TileState.Selected]: pill shaped handle shown on the end border, as well as a colored border
+ * around the content.
+ * - [TileState.None]: nothing
*
- * @param selected whether resizing drag events should be handled
- * @param state the [ResizingState] for the tile
- * @param selectionAlpha the animated value for the dot and border alpha
- * @param selectionColor the [Color] of the dot and border
+ * @param tileState the state for the tile decoration
+ * @param resizingState the [ResizingState] for the tile
+ * @param onClick the callback when the tile decoration is clicked
*/
@Composable
-fun ResizableTileContainer(
- selected: Boolean,
- state: ResizingState,
- selectionAlpha: () -> Float,
- selectionColor: Color,
+fun InteractiveTileContainer(
+ tileState: TileState,
+ resizingState: ResizingState,
modifier: Modifier = Modifier,
+ onClick: () -> Unit = {},
+ onClickLabel: String? = null,
content: @Composable BoxScope.() -> Unit = {},
) {
- Box(modifier.resizable(selected, state).selectionBorder(selectionColor, selectionAlpha)) {
- content()
- ResizingHandle(
- enabled = selected,
- state = state,
- modifier =
- // Higher zIndex to make sure the handle is drawn above the content
- Modifier.zIndex(if (selected) 2f else 1f),
- )
- }
-}
+ val transition: Transition<TileState> = updateTransition(tileState)
+ val decorationColor by transition.animateColor()
+ val decorationAngle by transition.animateAngle()
+ val decorationSize by transition.animateSize()
+ val decorationOffset by transition.animateOffset()
+ val decorationAlpha by transition.animateFloat { state -> if (state == None) 0f else 1f }
+ val badgeIconAlpha by transition.animateFloat { state -> if (state == Removable) 1f else 0f }
+ val selectionBorderAlpha by
+ transition.animateFloat { state -> if (state == Selected) 1f else 0f }
-@Composable
-private fun ResizingHandle(enabled: Boolean, state: ResizingState, modifier: Modifier = Modifier) {
- // Manually creating the touch target around the resizing dot to ensure that the next tile
- // does not receive the touch input accidentally.
- val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
- val scope = rememberCoroutineScope()
Box(
- modifier
- .layout { measurable, constraints ->
- val size = minTouchTargetSize.roundToPx()
- val placeable = measurable.measure(Constraints(size, size, size, size))
- layout(placeable.width, placeable.height) {
- placeable.place(
- x = constraints.maxWidth - placeable.width / 2,
- y = constraints.maxHeight / 2 - placeable.height / 2,
- )
- }
- }
- .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
- .anchoredDraggable(
- enabled = enabled,
- state = state.anchoredDraggableState,
- orientation = Orientation.Horizontal,
- )
- .clickable(enabled = enabled, interactionSource = null, indication = null) {
- scope.launch { state.toggleCurrentValue() }
- }
+ modifier.resizable(tileState == Selected, resizingState).selectionBorder(
+ MaterialTheme.colorScheme.primary,
+ SelectedBorderWidth,
+ ) {
+ selectionBorderAlpha
+ }
) {
- ResizingDot(enabled = enabled, modifier = Modifier.align(Alignment.Center))
- }
-}
+ content()
-@Composable
-private fun ResizingDot(
- enabled: Boolean,
- modifier: Modifier = Modifier,
- color: Color = MaterialTheme.colorScheme.primary,
-) {
- val alpha by animateFloatAsState(if (enabled) 1f else 0f)
- val radius by
- animateDpAsState(
- if (enabled) ResizingDotSize / 2 else 0.dp,
- animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy),
- )
- Canvas(modifier = modifier.size(ResizingDotSize)) {
- drawCircle(color = color, radius = radius.toPx(), alpha = alpha)
+ MinimumInteractiveSizeComponent(
+ angle = { decorationAngle },
+ offset = { decorationOffset },
+ ) {
+ Box(
+ Modifier.fillMaxSize()
+ .drawBehind {
+ drawRoundRect(
+ color = decorationColor,
+ topLeft = center - decorationSize.center,
+ size = decorationSize,
+ cornerRadius = CornerRadius(size.width / 2),
+ )
+ }
+ .graphicsLayer { this.alpha = decorationAlpha }
+ .anchoredDraggable(
+ enabled = tileState == Selected,
+ state = resizingState.anchoredDraggableState,
+ orientation = Orientation.Horizontal,
+ )
+ .clickable(
+ enabled = tileState != None,
+ interactionSource = null,
+ indication = null,
+ onClickLabel = onClickLabel,
+ onClick = onClick,
+ )
+ ) {
+ Icon(
+ Icons.Default.Remove,
+ contentDescription = null,
+ modifier =
+ Modifier.size(
+ width = { decorationSize.width.roundToInt() },
+ height = { decorationSize.height.roundToInt() },
+ )
+ .align(Alignment.Center)
+ .graphicsLayer { this.alpha = badgeIconAlpha },
+ )
+ }
+ }
}
}
private fun Modifier.selectionBorder(
selectionColor: Color,
+ selectionBorderWidth: Dp,
selectionAlpha: () -> Float = { 0f },
): Modifier {
return drawWithContent {
drawContent()
+
+ // Draw the border on the inside of the tile
+ val borderWidth = selectionBorderWidth.toPx()
drawRoundRect(
SolidColor(selectionColor),
cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
- style = Stroke(SelectedBorderWidth.toPx()),
+ topLeft = Offset(borderWidth / 2, borderWidth / 2),
+ size = Size(size.width - borderWidth, size.height - borderWidth),
+ style = Stroke(borderWidth),
alpha = selectionAlpha(),
)
}
}
@Composable
+fun StaticTileBadge(icon: ImageVector, contentDescription: String?, onClick: () -> Unit) {
+ val offset = with(LocalDensity.current) { Offset(BadgeXOffset.toPx(), BadgeYOffset.toPx()) }
+ MinimumInteractiveSizeComponent(angle = { BADGE_ANGLE_RAD }, offset = { offset }) {
+ Box(
+ Modifier.fillMaxSize()
+ .clickable(
+ interactionSource = null,
+ indication = null,
+ onClickLabel = contentDescription,
+ onClick = onClick,
+ )
+ ) {
+ val secondaryColor = MaterialTheme.colorScheme.secondary
+ Icon(
+ icon,
+ contentDescription = contentDescription,
+ modifier =
+ Modifier.size(BadgeSize).align(Alignment.Center).drawBehind {
+ drawCircle(secondaryColor)
+ },
+ )
+ }
+ }
+}
+
+@Composable
+private fun MinimumInteractiveSizeComponent(
+ angle: () -> Float,
+ offset: () -> Offset,
+ content: @Composable BoxScope.() -> Unit,
+) {
+ // Use a higher zIndex than the tile to draw over it, and manually create the touch target
+ // as we're drawing over neighbor tiles as well.
+ val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier =
+ Modifier.zIndex(2f)
+ .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
+ .layout { measurable, constraints ->
+ val size = minTouchTargetSize.roundToPx()
+ val placeable = measurable.measure(Constraints.fixed(size, size))
+ layout(placeable.width, placeable.height) {
+ val radius = constraints.maxHeight / 2f
+ val rotationCenter = Offset(constraints.maxWidth - radius, radius)
+ val position = offsetForAngle(angle(), radius, rotationCenter) + offset()
+ placeable.place(
+ position.x.roundToInt() - placeable.width / 2,
+ position.y.roundToInt() - placeable.height / 2,
+ )
+ }
+ },
+ content = content,
+ )
+}
+
+@Composable
private fun Modifier.resizable(selected: Boolean, state: ResizingState): Modifier {
if (!selected) return zIndex(1f)
@@ -165,7 +256,69 @@ private fun Modifier.resizable(selected: Boolean, state: ResizingState): Modifie
}
}
+enum class TileState {
+ None,
+ Removable,
+ Selected,
+}
+
+@Composable
+private fun Transition<TileState>.animateColor(): State<Color> {
+ return animateColor { state ->
+ when (state) {
+ None -> Color.Transparent
+ Removable -> MaterialTheme.colorScheme.secondary
+ Selected -> MaterialTheme.colorScheme.primary
+ }
+ }
+}
+
+@Composable
+private fun Transition<TileState>.animateAngle(): State<Float> {
+ return animateFloat { state ->
+ if (state == Removable) BADGE_ANGLE_RAD else RESIZING_PILL_ANGLE_RAD
+ }
+}
+
+@Composable
+private fun Transition<TileState>.animateSize(): State<Size> {
+ return animateSize { state ->
+ with(LocalDensity.current) {
+ when (state) {
+ None -> Size.Zero
+ Removable -> Size(BadgeSize.toPx())
+ Selected -> Size(ResizingPillWidth.toPx(), ResizingPillHeight.toPx())
+ }
+ }
+ }
+}
+
+@Composable
+private fun Transition<TileState>.animateOffset(): State<Offset> {
+ return animateOffset { state ->
+ with(LocalDensity.current) {
+ when (state) {
+ None -> Offset.Zero
+ Removable -> Offset(BadgeXOffset.toPx(), BadgeYOffset.toPx())
+ Selected -> Offset(-SelectedBorderWidth.toPx(), 0f)
+ }
+ }
+ }
+}
+
+private fun Size(size: Float) = Size(size, size)
+
+private fun offsetForAngle(angle: Float, radius: Float, center: Offset): Offset {
+ return Offset(x = radius * cos(angle) + center.x, y = radius * sin(angle) + center.y)
+}
+
private object SelectionDefaults {
- val ResizingDotSize = 16.dp
val SelectedBorderWidth = 2.dp
+ val BadgeSize = 24.dp
+ val BadgeXOffset = -4.dp
+ val BadgeYOffset = 4.dp
+ val ResizingPillWidth = 8.dp
+ val ResizingPillHeight = 16.dp
+ const val BADGE_ANGLE_RAD = -.8f
+ const val RESIZING_PILL_ANGLE_RAD = 0f
}
diff --git a/packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt b/packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt
new file mode 100644
index 000000000000..628280210236
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2025 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.rotationlock
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController
+import com.android.window.flags.Flags
+import dagger.Module
+import dagger.Provides
+import java.util.Optional
+import javax.inject.Provider
+import javax.inject.Qualifier
+
+@Module
+class DeviceStateAutoRotateModule {
+ /** Qualifier for dependencies to be bound with [DeviceStateAutoRotateModule]. */
+ @Qualifier
+ @MustBeDocumented
+ @Retention(AnnotationRetention.RUNTIME)
+ annotation class BoundsDeviceStateAutoRotateModule
+
+ /**
+ * Provides an instance of [DeviceStateRotationLockSettingController].
+ *
+ * @param controllerProvider The provider for [DeviceStateRotationLockSettingController].
+ * @return An [Optional] containing the [DeviceStateRotationLockSettingController] instance if
+ * the `Flags.enableDeviceStateAutoRotateSettingRefactor()` flag is disabled, or an empty
+ * [Optional] otherwise.
+ */
+ @Provides
+ @BoundsDeviceStateAutoRotateModule
+ @SysUISingleton
+ fun provideDeviceStateRotationLockSettingController(
+ controllerProvider: Provider<DeviceStateRotationLockSettingController>
+ ): Optional<DeviceStateRotationLockSettingController> =
+ if (Flags.enableDeviceStateAutoRotateSettingRefactor()) {
+ Optional.empty()
+ } else {
+ Optional.of(controllerProvider.get())
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index 79a872edd2c5..bfd512fa6a2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -607,13 +607,6 @@ public final class KeyboardShortcutListSearch {
context.getString(R.string.group_system_lock_screen),
Arrays.asList(
Pair.create(KeyEvent.KEYCODE_L, KeyEvent.META_META_ON))),
- /* Pull up Notes app for quick memo: Meta + Ctrl + N */
- new ShortcutKeyGroupMultiMappingInfo(
- context.getString(R.string.group_system_quick_memo),
- Arrays.asList(
- Pair.create(
- KeyEvent.KEYCODE_N,
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON))),
/* Access system settings: Meta + I */
new ShortcutKeyGroupMultiMappingInfo(
context.getString(R.string.group_system_access_system_settings),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
index dba8a9a6ddec..867db8ec8235 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
@@ -163,6 +163,7 @@ constructor(
if (entry in nextMap) nextMap.remove(entry)
if (entry in nextList) nextList.remove(entry)
+ outcome = "add next"
addToNext(entry, runnable)
// Shorten headsUpEntryShowing display time
@@ -174,7 +175,7 @@ constructor(
headsUpEntryShowing!!.updateEntry(
/* updatePostTime= */ false,
/* updateEarliestRemovalTime= */ false,
- /* reason= */ "avalanche duration update",
+ /* reason= */ "shorten duration of previously-last HUN",
)
}
}
@@ -269,8 +270,10 @@ constructor(
}
nextList.sort()
val entryList = showingList + nextList
+ val thisKey = getKey(entry)
if (entryList.isEmpty()) {
- log { "No avalanche HUNs, use default ms: $autoDismissMs" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, autoDismissMs, "No avalanche HUNs, use default", nextKey = "")
return autoDismissMs
}
// entryList.indexOf(entry) returns -1 even when the entry is in entryList
@@ -281,27 +284,29 @@ constructor(
}
}
if (thisEntryIndex == -1) {
- log { "Untracked entry, use default ms: $autoDismissMs" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, autoDismissMs, "Untracked entry, use default", nextKey = "")
return autoDismissMs
}
val nextEntryIndex = thisEntryIndex + 1
-
- // If last entry, use default duration
if (nextEntryIndex >= entryList.size) {
- log { "Last entry, use default ms: $autoDismissMs" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, autoDismissMs, "Last entry, use default", nextKey = "")
return autoDismissMs
}
val nextEntry = entryList[nextEntryIndex]
+ val nextKey = getKey(nextEntry)
if (nextEntry.compareNonTimeFields(entry) == -1) {
- // Next entry is higher priority
- log { "Next entry is higher priority: 500ms" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, 500, "LOWER priority than next: ", nextKey)
return 500
} else if (nextEntry.compareNonTimeFields(entry) == 0) {
- // Next entry is same priority
- log { "Next entry is same priority: 1000ms" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, 1000, "SAME priority as next: ", nextKey)
return 1000
} else {
- log { "Next entry is lower priority, use default ms: $autoDismissMs" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, autoDismissMs, "HIGHER priority than next: ", nextKey)
return autoDismissMs
}
}
@@ -355,25 +360,28 @@ constructor(
}
private fun showNow(entry: HeadsUpEntry, runnableList: MutableList<Runnable>) {
- log { "SHOW: " + getKey(entry) }
-
+ headsUpManagerLogger.logAvalancheStage("show", getKey(entry))
uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_SHOWN)
headsUpEntryShowing = entry
- runnableList.forEach {
- if (it in debugRunnableLabelMap) {
- log { "RUNNABLE: ${debugRunnableLabelMap[it]}" }
+ runnableList.forEach { runnable ->
+ if (debug) {
+ debugRunnableLabelMap[runnable]?.let { label ->
+ headsUpManagerLogger.logAvalancheStage("run", label)
+ // Remove label after logging to avoid memory leak
+ debugRunnableLabelMap.remove(runnable)
+ }
}
- it.run()
+ runnable.run()
}
}
private fun showNext() {
- log { "SHOW NEXT" }
+ headsUpManagerLogger.logAvalancheStage("show next", key = "")
headsUpEntryShowing = null
if (nextList.isEmpty()) {
- log { "NO MORE TO SHOW" }
+ headsUpManagerLogger.logAvalancheStage("no more", key = "")
previousHunKey = ""
return
}
@@ -395,11 +403,7 @@ constructor(
debugRunnableLabelMap.remove(r)
}
}
- val queue = ArrayList<String>()
- for (entry in listToDrop) {
- queue.add("[${getKey(entry)}]")
- }
- val dropList = java.lang.String.join("\n", queue)
+ val dropList = listToDrop.joinToString("\n ") { getKey(it) }
headsUpManagerLogger.logDroppedHuns(dropList)
}
clearNext()
@@ -424,38 +428,24 @@ constructor(
// Methods below are for logging only ==========================================================
- private inline fun log(s: () -> String) {
- if (debug) {
- Log.d(tag, s())
- }
- }
-
private fun getStateStr(): String {
- return "\navalanche state:" +
- "\n\tshowing: [${getKey(headsUpEntryShowing)}]" +
- "\n\tprevious: [$previousHunKey]" +
- "\n\tnext list: $nextListStr" +
- "\n\tnext map: $nextMapStr" +
- "\nBHUM.mHeadsUpEntryMap: " +
- baseEntryMapStr()
+ return "\n[AC state]" +
+ "\nshow: ${getKey(headsUpEntryShowing)}" +
+ "\nprevious: $previousHunKey" +
+ "\n$nextStr" +
+ "\n[HeadsUpManagerImpl.mHeadsUpEntryMap] " + baseEntryMapStr() + "\n"
}
- private val nextListStr: String
+ private val nextStr: String
get() {
- val queue = ArrayList<String>()
- for (entry in nextList) {
- queue.add("[${getKey(entry)}]")
+ val nextListStr = nextList.joinToString("\n ") { getKey(it) }
+ if (nextList.toSet() == nextMap.keys.toSet()) {
+ return "next (${nextList.size}):\n $nextListStr"
}
- return java.lang.String.join("\n", queue)
- }
-
- private val nextMapStr: String
- get() {
- val queue = ArrayList<String>()
- for (entry in nextMap.keys) {
- queue.add("[${getKey(entry)}]")
- }
- return java.lang.String.join("\n", queue)
+ // This should never happen
+ val nextMapStr = nextMap.keys.joinToString("\n ") { getKey(it) }
+ return "next list (${nextList.size}):\n $nextListStr" +
+ "\nnext map (${nextMap.size}):\n $nextMapStr"
}
fun getKey(entry: HeadsUpEntry?): String {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
index 7d74a496853f..87b9bf87c680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
@@ -856,11 +856,11 @@ public class HeadsUpManagerImpl
private String getEntryMapStr() {
if (mHeadsUpEntryMap.isEmpty()) {
- return "EMPTY";
+ return "";
}
StringBuilder entryMapStr = new StringBuilder();
for (HeadsUpEntry entry: mHeadsUpEntryMap.values()) {
- entryMapStr.append("\n\t").append(
+ entryMapStr.append("\n ").append(
entry.mEntry == null ? "null" : entry.mEntry.getKey());
}
return entryMapStr.toString();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
index 65fb9ca558d7..388d357b3b15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
@@ -71,7 +71,7 @@ constructor(@NotificationHeadsUpLog private val buffer: LogBuffer) {
str3 = outcome
bool1 = isEnabled
},
- { "$str1\n\t=> AC[isEnabled:$bool1] update: $str2\n\t=> $str3" },
+ { "$str1\n=> AC[enabled:$bool1] update: $str2\n=> $str3" },
)
}
@@ -90,7 +90,33 @@ constructor(@NotificationHeadsUpLog private val buffer: LogBuffer) {
str3 = outcome
bool1 = isEnabled
},
- { "$str1\n\t=> AC[isEnabled:$bool1] delete: $str2\n\t=> $str3" },
+ { "$str1\n=> AC[enabled:$bool1] delete: $str2\n=> $str3" },
+ )
+ }
+
+ fun logAvalancheStage(stage: String, key: String) {
+ buffer.log(
+ TAG,
+ INFO,
+ {
+ str1 = stage
+ str2 = key
+ },
+ { "[AC] $str1 $str2" },
+ )
+ }
+
+ fun logAvalancheDuration(thisKey: String, duration: Int, reason: String, nextKey: String) {
+ buffer.log(
+ TAG,
+ INFO,
+ {
+ str1 = thisKey
+ int1 = duration
+ str2 = reason
+ str3 = nextKey
+ },
+ { "[AC] $str1 | $int1 ms | $str2 $str3" },
)
}
@@ -325,7 +351,7 @@ constructor(@NotificationHeadsUpLog private val buffer: LogBuffer) {
}
fun logDroppedHuns(entryList: String) {
- buffer.log(TAG, VERBOSE, { str1 = entryList }, { "[AC] Drop HUNs: $str1" })
+ buffer.log(TAG, VERBOSE, { str1 = entryList }, { "[AC] dropped:\n $str1" })
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 54efa4a2bcf2..5c81c8e22bfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -44,15 +44,18 @@ import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AodToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DozingToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToPrimaryBouncerTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel
@@ -135,7 +138,9 @@ constructor(
private val aodToGoneTransitionViewModel: AodToGoneTransitionViewModel,
private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
private val aodToOccludedTransitionViewModel: AodToOccludedTransitionViewModel,
+ private val aodToGlanceableHubTransitionViewModel: AodToGlanceableHubTransitionViewModel,
private val aodToPrimaryBouncerTransitionViewModel: AodToPrimaryBouncerTransitionViewModel,
+ private val dozingToDreamingTransitionViewModel: DozingToDreamingTransitionViewModel,
dozingToGlanceableHubTransitionViewModel: DozingToGlanceableHubTransitionViewModel,
private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
private val dozingToOccludedTransitionViewModel: DozingToOccludedTransitionViewModel,
@@ -144,6 +149,7 @@ constructor(
private val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
private val glanceableHubToLockscreenTransitionViewModel:
GlanceableHubToLockscreenTransitionViewModel,
+ private val glanceableHubToAodTransitionViewModel: GlanceableHubToAodTransitionViewModel,
private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
private val goneToDreamingTransitionViewModel: GoneToDreamingTransitionViewModel,
@@ -571,7 +577,9 @@ constructor(
aodToGoneTransitionViewModel.notificationAlpha(viewState),
aodToLockscreenTransitionViewModel.notificationAlpha,
aodToOccludedTransitionViewModel.lockscreenAlpha(viewState),
+ aodToGlanceableHubTransitionViewModel.lockscreenAlpha(viewState),
aodToPrimaryBouncerTransitionViewModel.notificationAlpha,
+ dozingToDreamingTransitionViewModel.notificationAlpha,
dozingToLockscreenTransitionViewModel.lockscreenAlpha,
dozingToOccludedTransitionViewModel.lockscreenAlpha(viewState),
dozingToPrimaryBouncerTransitionViewModel.notificationAlpha,
@@ -591,6 +599,7 @@ constructor(
offToLockscreenTransitionViewModel.lockscreenAlpha,
primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
+ glanceableHubToAodTransitionViewModel.lockscreenAlpha,
lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index de7215461c80..36193bd87ce2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -441,6 +441,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
mAnimationScheduler.addCallback(mAnimationCallback);
mUserInfoController.addCallback(mOnUserInfoChangedListener);
mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mStatusBarState = mStatusBarStateController.getState();
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
mDisableStateTracker.startTracking(mCommandQueue, mView.getDisplay().getDisplayId());
if (mTintedIconManager == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 6c8e1825ea0a..ba41fd4c40ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -65,6 +65,7 @@ import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -116,6 +117,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final static String TAG = "StatusBarNotificationActivityStarter";
private final Context mContext;
+ private final ShadeDialogContextInteractor mContextInteractor;
private final Handler mMainThreadHandler;
private final Executor mUiBgExecutor;
@@ -156,6 +158,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
@Inject
StatusBarNotificationActivityStarter(
@ShadeDisplayAware Context context,
+ ShadeDialogContextInteractor contextInteractor,
@Main Handler mainThreadHandler,
@Background Executor uiBgExecutor,
NotificationVisibilityProvider visibilityProvider,
@@ -188,6 +191,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
PowerInteractor powerInteractor,
UserTracker userTracker) {
mContext = context;
+ mContextInteractor = contextInteractor;
mMainThreadHandler = mainThreadHandler;
mUiBgExecutor = uiBgExecutor;
mVisibilityProvider = visibilityProvider;
@@ -491,7 +495,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
boolean animate,
boolean isActivityIntent) {
mLogger.logStartNotificationIntent(entry);
- final int displayId = mContext.getDisplayId();
+ final int displayId = mContextInteractor.getContext().getDisplayId();
try {
ActivityTransitionAnimator.Controller animationController =
new StatusBarTransitionAnimatorController(
@@ -532,7 +536,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
public void startNotificationGutsIntent(@NonNull final Intent intent, final int appUid,
@NonNull ExpandableNotificationRow row) {
boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */);
- final int displayId = mContext.getDisplayId();
+ final int displayId = mContextInteractor.getContext().getDisplayId();
ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() {
@Override
public boolean onDismiss() {
@@ -571,7 +575,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
@Override
public void startHistoryIntent(View view, boolean showHistory) {
ModesEmptyShadeFix.assertInLegacyMode();
- final int displayId = mContext.getDisplayId();
+ final int displayId = mContextInteractor.getContext().getDisplayId();
boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */);
ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() {
@Override
@@ -621,7 +625,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
@Override
public void startSettingsIntent(@NonNull View view, @NonNull SettingsIntent intentInfo) {
- final int displayId = mContext.getDisplayId();
+ final int displayId = mContextInteractor.getContext().getDisplayId();
boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */);
ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
index d3e37119fdcb..2433d112bc69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
@@ -27,6 +27,7 @@ import com.android.systemui.common.shared.model.Text
import com.android.systemui.common.shared.model.Text.Companion.loadText
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
/** Model describing the state that the QS Internet tile should be in. */
sealed interface InternetTileModel {
@@ -49,11 +50,14 @@ sealed interface InternetTileModel {
state.contentDescription = contentDescription.loadContentDescription(context)
// To support both SignalDrawable and other icons, give priority to icons over IDs
- if (icon != null) {
- state.icon = icon
- } else if (iconId != null) {
- state.icon = QSTileImpl.maybeLoadResourceIcon(iconId!!, context)
- }
+ state.icon =
+ when {
+ icon is ResourceIcon ->
+ QSTileImpl.maybeLoadResourceIcon((icon as ResourceIcon).resId, context)
+ icon != null -> icon
+ iconId != null -> QSTileImpl.maybeLoadResourceIcon(iconId!!, context)
+ else -> null
+ }
state.state =
if (this is Active) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
index 88cf46a0ca07..b13e01be40f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -29,7 +29,6 @@ import androidx.annotation.NonNull;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
@@ -43,7 +42,6 @@ import javax.inject.Inject;
* Handles reading and writing of rotation lock settings per device state, as well as setting the
* rotation lock when device state changes.
*/
-@SysUISingleton
public final class DeviceStateRotationLockSettingController
implements Listenable, RotationLockController.RotationLockControllerCallback, Dumpable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index 797aa1f3a3dd..3ee7f33e3d3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -27,8 +27,10 @@ import androidx.annotation.NonNull;
import com.android.internal.view.RotationPolicy.RotationPolicyListener;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.rotationlock.DeviceStateAutoRotateModule.BoundsDeviceStateAutoRotateModule;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Inject;
@@ -50,21 +52,25 @@ public final class RotationLockControllerImpl implements RotationLockController
};
private final RotationPolicyWrapper mRotationPolicy;
- private final DeviceStateRotationLockSettingController
+ private final Optional<DeviceStateRotationLockSettingController>
mDeviceStateRotationLockSettingController;
private final boolean mIsPerDeviceStateRotationLockEnabled;
@Inject
public RotationLockControllerImpl(
RotationPolicyWrapper rotationPolicyWrapper,
- DeviceStateRotationLockSettingController deviceStateRotationLockSettingController,
+ Optional<DeviceStateRotationLockSettingController>
+ deviceStateRotationLockSettingController,
@Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
) {
mRotationPolicy = rotationPolicyWrapper;
- mDeviceStateRotationLockSettingController = deviceStateRotationLockSettingController;
mIsPerDeviceStateRotationLockEnabled = deviceStateRotationLockDefaults.length > 0;
- if (mIsPerDeviceStateRotationLockEnabled) {
- mCallbacks.add(mDeviceStateRotationLockSettingController);
+ mDeviceStateRotationLockSettingController =
+ deviceStateRotationLockSettingController;
+
+ if (mIsPerDeviceStateRotationLockEnabled
+ && mDeviceStateRotationLockSettingController.isPresent()) {
+ mCallbacks.add(mDeviceStateRotationLockSettingController.get());
}
setListening(true);
@@ -113,8 +119,9 @@ public final class RotationLockControllerImpl implements RotationLockController
} else {
mRotationPolicy.unregisterRotationPolicyListener(mRotationPolicyListener);
}
- if (mIsPerDeviceStateRotationLockEnabled) {
- mDeviceStateRotationLockSettingController.setListening(listening);
+ if (mIsPerDeviceStateRotationLockEnabled
+ && mDeviceStateRotationLockSettingController.isPresent()) {
+ mDeviceStateRotationLockSettingController.get().setListening(listening);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLogger.kt
index 33ed419afef2..5dbe9b145bc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLogger.kt
@@ -21,29 +21,25 @@ import com.android.settingslib.notification.modes.ZenMode
import com.android.systemui.qs.QSModesEvent
import javax.inject.Inject
-class ModesDialogEventLogger
-@Inject
-constructor(
- private val uiEventLogger: UiEventLogger,
-) {
+class ModesDialogEventLogger @Inject constructor(private val uiEventLogger: UiEventLogger) {
fun logModeOn(mode: ZenMode) {
val id =
if (mode.isManualDnd) QSModesEvent.QS_MODES_DND_ON else QSModesEvent.QS_MODES_MODE_ON
- uiEventLogger.log(id, /* uid= */ 0, mode.rule.packageName)
+ uiEventLogger.log(id, /* uid= */ 0, mode.ownerPackage)
}
fun logModeOff(mode: ZenMode) {
val id =
if (mode.isManualDnd) QSModesEvent.QS_MODES_DND_OFF else QSModesEvent.QS_MODES_MODE_OFF
- uiEventLogger.log(id, /* uid= */ 0, mode.rule.packageName)
+ uiEventLogger.log(id, /* uid= */ 0, mode.ownerPackage)
}
fun logModeSettings(mode: ZenMode) {
val id =
if (mode.isManualDnd) QSModesEvent.QS_MODES_DND_SETTINGS
else QSModesEvent.QS_MODES_MODE_SETTINGS
- uiEventLogger.log(id, /* uid= */ 0, mode.rule.packageName)
+ uiEventLogger.log(id, /* uid= */ 0, mode.ownerPackage)
}
fun logOpenDurationDialog(mode: ZenMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
index 07f1c3470c83..dc07202dc486 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
@@ -71,10 +71,10 @@ constructor(
mode.id in prevIds -> true
// Mode is enabled -> show if active (so user can toggle off), or if it
// can be manually toggled on
- mode.rule.isEnabled -> mode.isActive || mode.rule.isManualInvocationAllowed
+ mode.isEnabled -> mode.isActive || mode.isManualInvocationAllowed
// Mode was created as disabled, or disabled by the app that owns it ->
// will be shown with a "Not set" text
- !mode.rule.isEnabled -> mode.status == ZenMode.Status.DISABLED_BY_OTHER
+ !mode.isEnabled -> mode.status == ZenMode.Status.DISABLED_BY_OTHER
else -> false
}
}
@@ -97,13 +97,13 @@ constructor(
if (mode.isActive) R.string.zen_mode_on else R.string.zen_mode_off
),
onClick = {
- if (!mode.rule.isEnabled) {
+ if (!mode.isEnabled) {
openSettings(mode)
} else if (mode.isActive) {
dialogEventLogger.logModeOff(mode)
zenModeInteractor.deactivateMode(mode)
} else {
- if (mode.rule.isManualInvocationAllowed) {
+ if (mode.isManualInvocationAllowed) {
if (zenModeInteractor.shouldAskForZenDuration(mode)) {
dialogEventLogger.logOpenDurationDialog(mode)
// NOTE: The dialog handles turning on the mode itself.
@@ -144,10 +144,10 @@ constructor(
* readers, and for the tile subtext will be augmented with the current status of the mode.
*/
private fun getModeDescription(mode: ZenMode, forAccessibility: Boolean): String? {
- if (!mode.rule.isEnabled) {
+ if (!mode.isEnabled) {
return context.resources.getString(R.string.zen_mode_set_up)
}
- if (!mode.rule.isManualInvocationAllowed && !mode.isActive) {
+ if (!mode.isManualInvocationAllowed && !mode.isActive) {
return context.resources.getString(R.string.zen_mode_no_manual_invocation)
}
return if (forAccessibility)
diff --git a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
index 32f2ca6fb696..367f54cf4936 100644
--- a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
@@ -147,7 +147,7 @@ public class CreateUserActivity extends Activity {
super.onDestroy();
}
- private void addUserNow(String userName, Drawable userIcon, Boolean isAdmin) {
+ private void addUserNow(String userName, Drawable userIcon, String iconPath, Boolean isAdmin) {
mSetupUserDialog.dismiss();
userName = (userName == null || userName.trim().isEmpty())
? getString(com.android.settingslib.R.string.user_new_user_name)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
index a0be02f1ef7e..bd4c5f50eee7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
@@ -43,6 +43,7 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.DefaultEditTileGri
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.shared.model.TileCategory
+import com.android.systemui.res.R
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
@@ -85,7 +86,9 @@ class ResizingTest : SysuiTestCase() {
composeRule
.onNodeWithContentDescription("tileA")
- .performCustomAccessibilityActionWithLabel("Toggle size")
+ .performCustomAccessibilityActionWithLabel(
+ context.getString(R.string.accessibility_qs_edit_toggle_tile_size_action)
+ )
assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2)
}
@@ -101,7 +104,9 @@ class ResizingTest : SysuiTestCase() {
composeRule
.onNodeWithContentDescription("tileD_large")
- .performCustomAccessibilityActionWithLabel("Toggle size")
+ .performCustomAccessibilityActionWithLabel(
+ context.getString(R.string.accessibility_qs_edit_toggle_tile_size_action)
+ )
assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 3190d3ae8f16..28eafa937097 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -76,6 +76,7 @@ import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeControllerImpl;
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.data.repository.ShadeAnimationRepository;
+import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl;
import com.android.systemui.statusbar.CommandQueue;
@@ -171,6 +172,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
private final FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private ExpandableNotificationRow mNotificationRow;
private ExpandableNotificationRow mBubbleNotificationRow;
+ private FakeShadeDialogContextInteractor mContextInteractor;
private final Answer<Void> mCallOnDismiss = answerVoid(
(OnDismissAction dismissAction, Runnable cancel,
@@ -187,6 +189,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mDependency,
TestableLooper.get(this));
+ mContextInteractor = new FakeShadeDialogContextInteractor(mContext);
+
// Create standard notification with contentIntent
mNotificationRow = notificationTestHelper.createRow();
StatusBarNotification sbn = mNotificationRow.getEntry().getSbn();
@@ -199,10 +203,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
bubbleSbn.getNotification().contentIntent = mContentIntent;
bubbleSbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL;
-// ArrayList<NotificationEntry> activeNotifications = new ArrayList<>();
-// activeNotifications.add(mNotificationRow.getEntry());
-// activeNotifications.add(mBubbleNotificationRow.getEntry());
-// when(mEntryManager.getVisibleNotifications()).thenReturn(activeNotifications);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mOnUserInteractionCallback.registerFutureDismissal(eq(mNotificationRow.getEntry()),
anyInt())).thenReturn(mFutureDismissalRunnable);
@@ -232,6 +232,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mNotificationActivityStarter =
new StatusBarNotificationActivityStarter(
getContext(),
+ mContextInteractor,
mHandler,
mUiBgExecutor,
mVisibilityProvider,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index 0f21a16147f0..b8b2ec5a58ae 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.communal.domain.interactor
+import android.content.pm.UserInfo
import android.content.testableContext
import android.os.userManager
import com.android.systemui.broadcast.broadcastDispatcher
@@ -85,27 +86,28 @@ fun Kosmos.setCommunalV2ConfigEnabled(enabled: Boolean) {
)
}
-suspend fun Kosmos.setCommunalEnabled(enabled: Boolean) {
+suspend fun Kosmos.setCommunalEnabled(enabled: Boolean): UserInfo {
fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, enabled)
- if (enabled) {
+ return if (enabled) {
fakeUserRepository.asMainUser()
} else {
fakeUserRepository.asDefaultUser()
}
}
-suspend fun Kosmos.setCommunalV2Enabled(enabled: Boolean) {
+suspend fun Kosmos.setCommunalV2Enabled(enabled: Boolean): UserInfo {
setCommunalV2ConfigEnabled(enabled)
- setCommunalEnabled(enabled)
+ return setCommunalEnabled(enabled)
}
-suspend fun Kosmos.setCommunalAvailable(available: Boolean) {
- setCommunalEnabled(available)
+suspend fun Kosmos.setCommunalAvailable(available: Boolean): UserInfo {
+ val user = setCommunalEnabled(available)
fakeKeyguardRepository.setKeyguardShowing(available)
fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, available)
+ return user
}
-suspend fun Kosmos.setCommunalV2Available(available: Boolean) {
+suspend fun Kosmos.setCommunalV2Available(available: Boolean): UserInfo {
setCommunalV2ConfigEnabled(available)
- setCommunalAvailable(available)
+ return setCommunalAvailable(available)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
index 93a59eb8ca0c..bdfa875f5429 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
@@ -16,6 +16,9 @@
package com.android.systemui.keyguard.domain.interactor
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
+import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.deviceentry.data.repository.deviceEntryRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
@@ -38,5 +41,8 @@ val Kosmos.fromAodTransitionInteractor by
keyguardOcclusionInteractor = keyguardOcclusionInteractor,
deviceEntryRepository = deviceEntryRepository,
wakeToGoneInteractor = keyguardWakeDirectlyToGoneInteractor,
+ communalSettingsInteractor = communalSettingsInteractor,
+ communalSceneInteractor = communalSceneInteractor,
+ communalInteractor = communalInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModelKosmos.kt
new file mode 100644
index 000000000000..1eeecd4b7520
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModelKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2025 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.keyguard.ui.viewmodel
+
+import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory
+import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.aodToGlanceableHubTransitionViewModel by
+ Kosmos.Fixture {
+ AodToGlanceableHubTransitionViewModel(
+ animationFlow = keyguardTransitionAnimationFlow,
+ blurFactory = glanceableHubBlurComponentFactory,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
index bd0045501ec8..2797b4409ff0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
@@ -47,5 +47,6 @@ val Kosmos.deviceEntryBackgroundViewModel by Fixture {
primaryBouncerToLockscreenTransitionViewModel =
primaryBouncerToLockscreenTransitionViewModel,
lockscreenToDozingTransitionViewModel = lockscreenToDozingTransitionViewModel,
+ glanceableHubToAodTransitionViewModel = glanceableHubToAodTransitionViewModel,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModelKosmos.kt
new file mode 100644
index 000000000000..6004c7f2caec
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModelKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2025 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.keyguard.ui.viewmodel
+
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.glanceableHubToAodTransitionViewModel by
+ Kosmos.Fixture {
+ GlanceableHubToAodTransitionViewModel(
+ deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+ animationFlow = keyguardTransitionAnimationFlow,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index 78356318cbb4..27ca0f867855 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -94,5 +94,7 @@ val Kosmos.keyguardRootViewModel by Fixture {
shadeInteractor = shadeInteractor,
wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor,
dumpManager = dumpManager,
+ glanceableHubToAodTransitionViewModel = glanceableHubToAodTransitionViewModel,
+ aodToGlanceableHubTransitionViewModel = aodToGlanceableHubTransitionViewModel,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 7a2b7c24252b..51bb94fd2ab9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -25,15 +25,18 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac
import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToPrimaryBouncerTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.aodToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.dozingToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToPrimaryBouncerTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dreamingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.goneToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.goneToDozingTransitionViewModel
@@ -81,6 +84,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture {
aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
aodToOccludedTransitionViewModel = aodToOccludedTransitionViewModel,
aodToPrimaryBouncerTransitionViewModel = aodToPrimaryBouncerTransitionViewModel,
+ dozingToDreamingTransitionViewModel = dozingToDreamingTransitionViewModel,
dozingToGlanceableHubTransitionViewModel = dozingToGlanceableHubTransitionViewModel,
dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
dozingToOccludedTransitionViewModel = dozingToOccludedTransitionViewModel,
@@ -110,5 +114,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture {
headsUpNotificationInteractor = { headsUpNotificationInteractor },
largeScreenHeaderHelperLazy = { largeScreenHeaderHelper },
unfoldTransitionInteractor = unfoldTransitionInteractor,
+ glanceableHubToAodTransitionViewModel = glanceableHubToAodTransitionViewModel,
+ aodToGlanceableHubTransitionViewModel = aodToGlanceableHubTransitionViewModel,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
index d787e2c190c8..91404e0688ed 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
@@ -30,6 +30,7 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.plugins.activityStarter
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.settings.userTracker
+import com.android.systemui.shade.data.repository.shadeDialogContextInteractor
import com.android.systemui.shade.domain.interactor.panelExpansionInteractor
import com.android.systemui.shade.domain.interactor.shadeAnimationInteractor
import com.android.systemui.shade.shadeController
@@ -52,6 +53,7 @@ val Kosmos.statusBarNotificationActivityStarter by
Kosmos.Fixture {
StatusBarNotificationActivityStarter(
applicationContext,
+ shadeDialogContextInteractor,
fakeExecutorHandler,
fakeExecutor,
notificationVisibilityProvider,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapterKosmos.kt
index 4e3c3caa2428..d4d589663477 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapterKosmos.kt
@@ -21,9 +21,9 @@ import com.android.systemui.statusbar.phone.ui.statusBarIconController
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.wifiViewModel
val Kosmos.wifiUiAdapter by
-Kosmos.Fixture {
- WifiUiAdapter(
+ Kosmos.Fixture {
+ WifiUiAdapter(
statusBarIconController,
wifiViewModel,
- )
-}
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelKosmos.kt
index 15057cd5bd0c..3f876ef0536b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelKosmos.kt
@@ -24,14 +24,14 @@ import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.airplaneMod
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.wifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
-import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import org.mockito.kotlin.mock
val Kosmos.wifiViewModel by
- Kosmos.Fixture {
+ Kosmos.Fixture {
WifiViewModel(
airplaneModeViewModel,
- { MutableStateFlow(false) },
+ { flowOf(false) },
mock<ConnectivityConstants>(),
applicationContext,
logcatTableLogBuffer(this, "WifiViewModelTest"),
@@ -39,4 +39,4 @@ val Kosmos.wifiViewModel by
applicationCoroutineScope,
mock<WifiConstants>(),
)
- }
+ }
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 139bbae26289..93b4de856463 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -891,6 +891,11 @@ public class VirtualDeviceManagerService extends SystemService {
}
@Override
+ public VirtualDevice getVirtualDevice(int deviceId) {
+ return mImpl.getVirtualDevice(deviceId);
+ }
+
+ @Override
public long getDimDurationMillisForDeviceId(int deviceId) {
VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId);
return virtualDevice == null ? -1 : virtualDevice.getDimDurationMillis();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index cce29592d912..125824c3f37e 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -618,7 +618,7 @@ public final class ActiveServices {
Slog.i(TAG, " Stopping fg for service " + r);
}
setServiceForegroundInnerLocked(r, 0, null, 0, 0,
- 0);
+ 0, /* systemRequestedTransition= */ true);
}
}
@@ -1839,7 +1839,7 @@ public final class ActiveServices {
ServiceRecord r = findServiceLocked(className, token, userId);
if (r != null) {
setServiceForegroundInnerLocked(r, id, notification, flags, foregroundServiceType,
- callingUid);
+ callingUid, /* systemRequestedTransition= */ false);
}
} finally {
mAm.mInjector.restoreCallingIdentity(origId);
@@ -2155,7 +2155,7 @@ public final class ActiveServices {
@GuardedBy("mAm")
private void setServiceForegroundInnerLocked(final ServiceRecord r, int id,
Notification notification, int flags, int foregroundServiceType,
- int callingUidIfStart) {
+ int callingUidIfStart, boolean systemRequestedTransition) {
if (id != 0) {
if (notification == null) {
throw new IllegalArgumentException("null notification");
@@ -2800,6 +2800,7 @@ public final class ActiveServices {
// earlier.
r.foregroundServiceType = 0;
r.mFgsNotificationWasDeferred = false;
+ r.systemRequestedFgToBg = systemRequestedTransition;
signalForegroundServiceObserversLocked(r);
resetFgsRestrictionLocked(r);
mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
@@ -9339,14 +9340,22 @@ public final class ActiveServices {
if (sr.foregroundServiceType
== ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE
&& sr.foregroundId == notificationId) {
- if (DEBUG_FOREGROUND_SERVICE) {
- Slog.d(TAG, "Moving media service to foreground for package "
- + packageName);
+ // check if service is explicitly requested by app to not be in foreground.
+ if (sr.systemRequestedFgToBg) {
+ Slog.d(TAG,
+ "System initiated service transition to foreground "
+ + "for package "
+ + packageName);
+ setServiceForegroundInnerLocked(sr, sr.foregroundId,
+ sr.foregroundNoti, /* flags */ 0,
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
+ /* callingUidStart */ 0, /* systemRequestedTransition */ true);
+ } else {
+ Slog.d(TAG,
+ "Ignoring system initiated foreground service transition for "
+ + "package"
+ + packageName);
}
- setServiceForegroundInnerLocked(sr, sr.foregroundId,
- sr.foregroundNoti, /* flags */ 0,
- ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
- /* callingUidStart */ 0);
}
}
}
@@ -9379,13 +9388,14 @@ public final class ActiveServices {
if (sr.foregroundServiceType
== ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
&& sr.foregroundId == notificationId) {
- if (DEBUG_FOREGROUND_SERVICE) {
- Slog.d(TAG, "Forcing media foreground service to background for package "
- + packageName);
- }
+ Slog.d(TAG,
+ "System initiated transition of foreground service(type:media) to bg "
+ + "for package"
+ + packageName);
setServiceForegroundInnerLocked(sr, /* id */ 0,
/* notification */ null, /* flags */ 0,
- /* foregroundServiceType */ 0, /* callingUidStart */ 0);
+ /* foregroundServiceType */ 0, /* callingUidStart */ 0,
+ /* systemRequestedTransition */ true);
}
}
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index b677297dfef2..4bfee1d8398f 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1464,7 +1464,10 @@ public class CachedAppOptimizer {
void onProcessFrozen(ProcessRecord frozenProc) {
if (useCompaction()) {
synchronized (mProcLock) {
- compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false);
+ // only full-compact if process is cached
+ if (frozenProc.mState.getSetAdj() >= mCompactThrottleMinOomAdj) {
+ compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false);
+ }
}
}
frozenProc.onProcessFrozen();
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index ca34a13c55b1..f443e4455734 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -158,6 +158,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
boolean fgWaiting; // is a timeout for going foreground already scheduled?
boolean isNotAppComponentUsage; // is service binding not considered component/package usage?
boolean isForeground; // is service currently in foreground mode?
+ boolean systemRequestedFgToBg; // system requested service to transition to background.
boolean inSharedIsolatedProcess; // is the service in a shared isolated process
int foregroundId; // Notification ID of last foreground req.
Notification foregroundNoti; // Notification record of foreground state.
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index d412277d2605..f5284a3ed589 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -211,4 +211,20 @@ public abstract class VirtualDeviceManagerInternal {
*/
public abstract @NonNull VirtualDeviceManager.VirtualDevice createVirtualDevice(
@NonNull VirtualDeviceParams params);
+
+ /**
+ * Returns the details of the virtual device with the given ID, if any.
+ *
+ * <p>The returned object is a read-only representation of the virtual device that expose its
+ * properties.</p>
+ *
+ * <p>Note that if the virtual device is closed and becomes invalid, the returned object will
+ * not be updated and may contain stale values. Use a {@link VirtualDeviceListener} for real
+ * time updates of the availability of virtual devices.</p>
+ *
+ * @return the virtual device with the requested ID, or {@code null} if no such device exists or
+ * it has already been closed.
+ */
+ @Nullable
+ public abstract VirtualDevice getVirtualDevice(int deviceId);
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 88f5c81231b8..c41b8db1ce75 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -333,7 +333,7 @@ public class AutomaticBrightnessController {
int ambientLightHorizonLong, float userLux, float userNits,
DisplayManagerFlags displayManagerFlags) {
mInjector = injector;
- mClock = injector.createClock(displayManagerFlags.offloadControlsDozeAutoBrightness());
+ mClock = injector.createClock();
mContext = context;
mCallbacks = callbacks;
mSensorManager = sensorManager;
@@ -1402,8 +1402,7 @@ public class AutomaticBrightnessController {
public void onSensorChanged(SensorEvent event) {
if (mLightSensorEnabled) {
// The time received from the sensor is in nano seconds, hence changing it to ms
- final long time = (mDisplayManagerFlags.offloadControlsDozeAutoBrightness())
- ? TimeUnit.NANOSECONDS.toMillis(event.timestamp) : mClock.uptimeMillis();
+ final long time = TimeUnit.NANOSECONDS.toMillis(event.timestamp);
final float lux = event.values[0];
handleLightSensorEvent(time, lux);
}
@@ -1616,20 +1615,13 @@ public class AutomaticBrightnessController {
}
private static class RealClock implements Clock {
- private final boolean mOffloadControlsDozeBrightness;
-
- RealClock(boolean offloadControlsDozeBrightness) {
- mOffloadControlsDozeBrightness = offloadControlsDozeBrightness;
- }
-
@Override
public long uptimeMillis() {
return SystemClock.uptimeMillis();
}
public long getSensorEventScaleTime() {
- return (mOffloadControlsDozeBrightness)
- ? SystemClock.elapsedRealtime() : uptimeMillis();
+ return SystemClock.elapsedRealtime();
}
}
@@ -1638,8 +1630,8 @@ public class AutomaticBrightnessController {
return BackgroundThread.getHandler();
}
- Clock createClock(boolean offloadControlsDozeBrightness) {
- return new RealClock(offloadControlsDozeBrightness);
+ Clock createClock() {
+ return new RealClock();
}
}
}
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 2c6f37448735..6510441ba28f 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -291,8 +291,7 @@ public class DisplayBrightnessStrategySelector {
void setAllowAutoBrightnessWhileDozing(
DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) {
mAllowAutoBrightnessWhileDozing = mAllowAutoBrightnessWhileDozingConfig;
- if (mDisplayManagerFlags.offloadControlsDozeAutoBrightness()
- && mDisplayManagerFlags.isDisplayOffloadEnabled()
+ if (mDisplayManagerFlags.isDisplayOffloadEnabled()
&& displayOffloadSession != null) {
mAllowAutoBrightnessWhileDozing &= displayOffloadSession.allowAutoBrightnessInDoze();
}
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index e4b595ab7c55..c3057ded66eb 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -156,11 +156,6 @@ public class DisplayManagerFlags {
Flags.FLAG_DOZE_BRIGHTNESS_FLOAT,
Flags::dozeBrightnessFloat);
- private final FlagState mOffloadControlsDozeAutoBrightness = new FlagState(
- Flags.FLAG_OFFLOAD_CONTROLS_DOZE_AUTO_BRIGHTNESS,
- Flags::offloadControlsDozeAutoBrightness
- );
-
private final FlagState mPeakRefreshRatePhysicalLimit = new FlagState(
Flags.FLAG_ENABLE_PEAK_REFRESH_RATE_PHYSICAL_LIMIT,
Flags::enablePeakRefreshRatePhysicalLimit
@@ -440,13 +435,6 @@ public class DisplayManagerFlags {
return mDozeBrightnessFloat.isEnabled();
}
- /**
- * @return Whether DisplayOffload should control auto-brightness in doze
- */
- public boolean offloadControlsDozeAutoBrightness() {
- return mOffloadControlsDozeAutoBrightness.isEnabled();
- }
-
public boolean isPeakRefreshRatePhysicalLimitEnabled() {
return mPeakRefreshRatePhysicalLimit.isEnabled();
}
@@ -647,7 +635,6 @@ public class DisplayManagerFlags {
pw.println(" " + mResolutionBackupRestore);
pw.println(" " + mUseFusionProxSensor);
pw.println(" " + mDozeBrightnessFloat);
- pw.println(" " + mOffloadControlsDozeAutoBrightness);
pw.println(" " + mPeakRefreshRatePhysicalLimit);
pw.println(" " + mIgnoreAppPreferredRefreshRate);
pw.println(" " + mSynthetic60hzModes);
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index acdc0e0cf891..f5451307afb7 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -255,17 +255,6 @@ flag {
}
flag {
- name: "offload_controls_doze_auto_brightness"
- namespace: "display_manager"
- description: "Allows the registered DisplayOffloader to control if auto-brightness is used in doze"
- bug: "327392714"
- is_fixed_read_only: true
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "enable_peak_refresh_rate_physical_limit"
namespace: "display_manager"
description: "Flag for adding physical refresh rate limit if smooth display setting is on "
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 7e8bb28b6a37..2af74f620c95 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -569,7 +569,8 @@ public final class DreamManagerService extends SystemService {
}
private void requestDreamInternal() {
- if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()) {
+ if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()
+ && !isDozingInternal()) {
return;
}
diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java
index 977c029f3a29..d71c8a1056d9 100644
--- a/services/core/java/com/android/server/input/InputGestureManager.java
+++ b/services/core/java/com/android/server/input/InputGestureManager.java
@@ -146,11 +146,6 @@ final class InputGestureManager {
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
),
createKeyGesture(
- KeyEvent.KEYCODE_N,
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES
- ),
- createKeyGesture(
KeyEvent.KEYCODE_S,
KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
index bb487fb52c9f..ebf7e6bed064 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -1,4 +1,3 @@
aseemk@google.com
bozhu@google.com
dementyev@google.com
-robertberry@google.com
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 44d787f790cf..c31c287017c3 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -82,12 +82,10 @@ import android.util.LongSparseLongArray;
import android.util.Slog;
import android.util.SparseBooleanArray;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.infra.AndroidFuture;
-import com.android.internal.policy.AttributeCache;
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
@@ -167,6 +165,7 @@ public final class PermissionPolicyService extends SystemService {
private Context mContext;
private PackageManagerInternal mPackageManagerInternal;
private PermissionManagerServiceInternal mPermissionManagerInternal;
+ private ActivityTaskManagerInternal mActivityTaskManagerInternal;
private NotificationManagerInternal mNotificationManager;
private TelephonyManager mTelephonyManager;
private final KeyguardManager mKeyguardManager;
@@ -189,6 +188,7 @@ public final class PermissionPolicyService extends SystemService {
PackageManagerInternal.class);
mPermissionManagerInternal = LocalServices.getService(
PermissionManagerServiceInternal.class);
+ mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -1154,7 +1154,7 @@ public final class PermissionPolicyService extends SystemService {
activityInfo.packageName, info.getCallingPackage(),
info.getIntent(), info.getCheckedOptions(), activityInfo.name,
true)
- || isNoDisplayActivity(activityInfo)) {
+ || isNoDisplayActivity(activityInfo, info.getUserId())) {
return;
}
UserHandle user = UserHandle.of(taskInfo.userId);
@@ -1170,9 +1170,7 @@ public final class PermissionPolicyService extends SystemService {
};
private void onActivityManagerReady() {
- ActivityTaskManagerInternal atm =
- LocalServices.getService(ActivityTaskManagerInternal.class);
- atm.registerActivityStartInterceptor(
+ mActivityTaskManagerInternal.registerActivityStartInterceptor(
ActivityInterceptorCallback.PERMISSION_POLICY_ORDERED_ID,
mActivityInterceptorCallback);
}
@@ -1227,20 +1225,14 @@ public final class PermissionPolicyService extends SystemService {
null, activityName, false);
}
- private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo) {
+ private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo, int userId) {
final int themeResource = aInfo.getThemeResource();
if (themeResource == Resources.ID_NULL) {
return false;
}
- boolean noDisplay = false;
- final AttributeCache.Entry ent = AttributeCache.instance()
- .get(aInfo.packageName, themeResource, R.styleable.Window, 0);
- if (ent != null) {
- noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
- }
-
- return noDisplay;
+ return mActivityTaskManagerInternal.isNoDisplay(aInfo.packageName, themeResource,
+ userId);
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 76c5240ab623..980fb155999e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1163,6 +1163,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ private boolean shouldShowHub() {
+ final boolean hubEnabled = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(), Settings.Secure.GLANCEABLE_HUB_ENABLED,
+ 1, mCurrentUserId) == 1;
+
+ return mUserManagerInternal != null && mUserManagerInternal.isUserUnlocked(mCurrentUserId)
+ && hubEnabled && mDreamManagerInternal.dreamConditionActive();
+ }
+
@VisibleForTesting
void powerPress(long eventTime, int count, int displayId) {
// SideFPS still needs to know about suppressed power buttons, in case it needs to block
@@ -1251,7 +1260,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mContext.getContentResolver(), Settings.Secure.GLANCEABLE_HUB_ENABLED,
1, mCurrentUserId) == 1;
- if (mDreamManagerInternal.isDreaming() || isKeyguardShowing()) {
+ if ((mDreamManagerInternal != null && mDreamManagerInternal.isDreaming())
+ || isKeyguardShowing()) {
// If the device is already dreaming or on keyguard, go to sleep.
sleepDefaultDisplayFromPowerButton(eventTime, 0);
break;
@@ -1261,9 +1271,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// show hub.
boolean keyguardAvailable = !mLockPatternUtils.isLockScreenDisabled(
mCurrentUserId);
- if (mUserManagerInternal.isUserUnlocked(mCurrentUserId) && hubEnabled
- && keyguardAvailable && mDreamManagerInternal.dreamConditionActive()) {
- // If the hub can be launched, send a message to keyguard.
+ if (shouldShowHub() && keyguardAvailable) {
+ // If the hub can be launched, send a message to keyguard. We do not know if
+ // the hub is already running or not, keyguard handles turning screen off if
+ // it is.
Bundle options = new Bundle();
options.putBoolean(EXTRA_TRIGGER_HUB, true);
lockNow(options);
@@ -1324,14 +1335,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* @param isScreenOn Whether the screen is currently on.
* @param noDreamAction The action to perform if dreaming is not possible.
*/
- private void attemptToDreamFromShortPowerButtonPress(
+ private boolean attemptToDreamFromShortPowerButtonPress(
boolean isScreenOn, Runnable noDreamAction) {
if (mShortPressOnPowerBehavior != SHORT_PRESS_POWER_DREAM_OR_SLEEP
&& mShortPressOnPowerBehavior != SHORT_PRESS_POWER_HUB_OR_DREAM_OR_SLEEP) {
// If the power button behavior isn't one that should be able to trigger the dream, give
// up.
noDreamAction.run();
- return;
+ return false;
}
final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal();
@@ -1339,7 +1350,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Slog.d(TAG, "Can't start dreaming when attempting to dream from short power"
+ " press (isScreenOn=" + isScreenOn + ")");
noDreamAction.run();
- return;
+ return false;
}
synchronized (mLock) {
@@ -1350,6 +1361,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
dreamManagerInternal.requestDream();
+
+ return true;
}
/**
@@ -2327,6 +2340,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowWakeUpPolicy getWindowWakeUpPolicy() {
return new WindowWakeUpPolicy(mContext);
}
+
+ DreamManagerInternal getDreamManagerInternal() {
+ return LocalServices.getService(DreamManagerInternal.class);
+ }
}
/** {@inheritDoc} */
@@ -2345,7 +2362,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mInputManager = mContext.getSystemService(InputManager.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
- mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+ mDreamManagerInternal = injector.getDreamManagerInternal();
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mSensorPrivacyManager = mContext.getSystemService(SensorPrivacyManager.class);
@@ -3701,15 +3718,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
break;
case KeyEvent.KEYCODE_N:
if (firstDown && event.isMetaPressed()) {
- if (event.isCtrlPressed()) {
- sendSystemKeyToStatusBarAsync(event);
- notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES);
- } else {
- toggleNotificationPanel();
- notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL);
- }
+ toggleNotificationPanel();
+ notifyKeyGestureCompleted(event,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL);
return true;
}
break;
@@ -6398,6 +6409,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
event.getDisplayId(), event.getKeyCode(), "wakeUpFromWakeKey")) {
return;
}
+
+ if (!shouldShowHub()
+ && mShortPressOnPowerBehavior == SHORT_PRESS_POWER_HUB_OR_DREAM_OR_SLEEP
+ && event.getKeyCode() == KEYCODE_POWER
+ && attemptToDreamFromShortPowerButtonPress(false, () -> {})) {
+ // In the case that we should wake to dream and successfully initiate dreaming, do not
+ // continue waking up. Doing so will exit the dream state and cause UI to react
+ // accordingly.
+ return;
+ }
+
wakeUpFromWakeKey(
event.getEventTime(),
event.getKeyCode(),
diff --git a/services/core/java/com/android/server/power/stats/format/ScreenPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/format/ScreenPowerStatsLayout.java
index 6f6a7ff5064a..ca2237562fe1 100644
--- a/services/core/java/com/android/server/power/stats/format/ScreenPowerStatsLayout.java
+++ b/services/core/java/com/android/server/power/stats/format/ScreenPowerStatsLayout.java
@@ -29,7 +29,8 @@ import com.android.internal.os.PowerStats;
public class ScreenPowerStatsLayout extends PowerStatsLayout {
private static final String EXTRA_DEVICE_SCREEN_COUNT = "dsc";
private static final String EXTRA_DEVICE_SCREEN_ON_DURATION_POSITION = "dsd";
- private static final String EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS = "dbd";
+ private static final String EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS = "dbds";
+ private static final String EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS_COMPAT = "dbd";
private static final String EXTRA_DEVICE_DOZE_DURATION_POSITION = "ddd";
private static final String EXTRA_DEVICE_DOZE_POWER_POSITION = "ddp";
private static final String EXTRA_UID_FOREGROUND_DURATION = "uf";
@@ -55,8 +56,14 @@ public class ScreenPowerStatsLayout extends PowerStatsLayout {
PersistableBundle extras = descriptor.extras;
mDisplayCount = extras.getInt(EXTRA_DEVICE_SCREEN_COUNT, 1);
mDeviceScreenOnDurationPosition = extras.getInt(EXTRA_DEVICE_SCREEN_ON_DURATION_POSITION);
- mDeviceBrightnessDurationPositions = extras.getIntArray(
+ mDeviceBrightnessDurationPositions = getIntArray(extras,
EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS);
+ if (mDeviceBrightnessDurationPositions == null) {
+ // We should never put arrays in PowerStats.Descriptor because of the performance of
+ // .equals
+ mDeviceBrightnessDurationPositions = extras.getIntArray(
+ EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS_COMPAT);
+ }
mDeviceScreenDozeDurationPosition = extras.getInt(EXTRA_DEVICE_DOZE_DURATION_POSITION);
mDeviceScreenDozePowerPosition = extras.getInt(EXTRA_DEVICE_DOZE_POWER_POSITION);
mUidTopActivityTimePosition = extras.getInt(EXTRA_UID_FOREGROUND_DURATION);
@@ -67,7 +74,7 @@ public class ScreenPowerStatsLayout extends PowerStatsLayout {
super.toExtras(extras);
extras.putInt(EXTRA_DEVICE_SCREEN_COUNT, mDisplayCount);
extras.putInt(EXTRA_DEVICE_SCREEN_ON_DURATION_POSITION, mDeviceScreenOnDurationPosition);
- extras.putIntArray(EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS,
+ putIntArray(extras, EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS,
mDeviceBrightnessDurationPositions);
extras.putInt(EXTRA_DEVICE_DOZE_DURATION_POSITION, mDeviceScreenDozeDurationPosition);
extras.putInt(EXTRA_DEVICE_DOZE_POWER_POSITION, mDeviceScreenDozePowerPosition);
diff --git a/services/core/java/com/android/server/power/stats/format/SensorPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/format/SensorPowerStatsLayout.java
index e8df3ddfe5e8..c382534ac433 100644
--- a/services/core/java/com/android/server/power/stats/format/SensorPowerStatsLayout.java
+++ b/services/core/java/com/android/server/power/stats/format/SensorPowerStatsLayout.java
@@ -27,8 +27,10 @@ import java.util.Map;
public class SensorPowerStatsLayout extends PowerStatsLayout {
private static final String TAG = "SensorPowerStatsLayout";
- private static final String EXTRA_DEVICE_SENSOR_HANDLES = "dsh";
+ private static final String EXTRA_DEVICE_SENSOR_HANDLES = "dshs";
+ private static final String EXTRA_DEVICE_SENSOR_HANDLES_COMPAT = "dsh";
private static final String EXTRA_UID_SENSOR_POSITIONS = "usp";
+ private static final String EXTRA_UID_SENSOR_POSITIONS_COMPAT = "usps";
private final SparseIntArray mSensorPositions = new SparseIntArray();
@@ -47,8 +49,14 @@ public class SensorPowerStatsLayout extends PowerStatsLayout {
super(descriptor);
PersistableBundle extras = descriptor.extras;
- int[] handlers = extras.getIntArray(EXTRA_DEVICE_SENSOR_HANDLES);
- int[] uidDurationPositions = extras.getIntArray(EXTRA_UID_SENSOR_POSITIONS);
+ int[] handlers = getIntArray(extras, EXTRA_DEVICE_SENSOR_HANDLES);
+ if (handlers == null) {
+ handlers = extras.getIntArray(EXTRA_DEVICE_SENSOR_HANDLES_COMPAT);
+ }
+ int[] uidDurationPositions = getIntArray(extras, EXTRA_UID_SENSOR_POSITIONS);
+ if (uidDurationPositions == null) {
+ uidDurationPositions = extras.getIntArray(EXTRA_UID_SENSOR_POSITIONS_COMPAT);
+ }
if (handlers != null && uidDurationPositions != null) {
for (int i = 0; i < handlers.length; i++) {
@@ -69,8 +77,8 @@ public class SensorPowerStatsLayout extends PowerStatsLayout {
uidDurationPositions[i] = mSensorPositions.valueAt(i);
}
- extras.putIntArray(EXTRA_DEVICE_SENSOR_HANDLES, handlers);
- extras.putIntArray(EXTRA_UID_SENSOR_POSITIONS, uidDurationPositions);
+ putIntArray(extras, EXTRA_DEVICE_SENSOR_HANDLES, handlers);
+ putIntArray(extras, EXTRA_UID_SENSOR_POSITIONS, uidDurationPositions);
}
private void addUidSensorSection(int handle, String label) {
diff --git a/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java
index a783d543559f..53894a196d24 100644
--- a/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java
+++ b/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java
@@ -25,6 +25,7 @@ import android.os.PersistableBundle;
import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.IndentingPrintWriter;
+import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -347,7 +348,10 @@ class AggregatedPowerStats {
Set<Integer> uids = new HashSet<>();
for (int i = 0; i < mPowerComponentStats.size(); i++) {
- mPowerComponentStats.valueAt(i).collectUids(uids);
+ IntArray activeUids = mPowerComponentStats.valueAt(i).getActiveUids();
+ for (int j = activeUids.size() - 1; j >= 0; j--) {
+ uids.add(activeUids.get(j));
+ }
}
Integer[] allUids = uids.toArray(new Integer[uids.size()]);
diff --git a/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java
index d24ea83540cb..1d359335c6d8 100644
--- a/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java
@@ -24,13 +24,12 @@ import static com.android.server.power.stats.processor.AggregatedPowerStatsConfi
import android.os.BatteryConsumer;
import android.os.PersistableBundle;
+import android.util.IntArray;
import com.android.internal.os.PowerStats;
import com.android.server.power.stats.format.BasePowerStatsLayout;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.function.DoubleSupplier;
class BasePowerStatsProcessor extends PowerStatsProcessor {
@@ -125,11 +124,12 @@ class BasePowerStatsProcessor extends PowerStatsProcessor {
mCumulativeDischargeUah = 0;
mCumulativeDischargeDurationMs = 0;
- List<Integer> uids = new ArrayList<>();
- stats.collectUids(uids);
-
- long durationMs = timestampMs - mStartTimestamp;
- if (!uids.isEmpty()) {
+ // Note that we are calling `getUids` rather than `getActiveUids`, because this Processor
+ // deals with duration rather than power estimation, so it needs to process *all* known
+ // UIDs, not just the ones that contributed PowerStats
+ IntArray uids = stats.getUids();
+ if (uids.size() != 0) {
+ long durationMs = timestampMs - mStartTimestamp;
for (int i = uids.size() - 1; i >= 0; i--) {
long[] uidStats = new long[sStatsLayout.getUidStatsArrayLength()];
sStatsLayout.setUidUsageDuration(uidStats, durationMs);
diff --git a/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java
index 9fe7f3e7a542..c89dddf45609 100644
--- a/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.os.BatteryStats;
import android.os.PersistableBundle;
import android.os.Process;
+import android.util.IntArray;
import com.android.internal.os.PowerStats;
import com.android.server.power.stats.UsageBasedPowerEstimator;
@@ -27,7 +28,6 @@ import com.android.server.power.stats.format.BinaryStatePowerStatsLayout;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -190,13 +190,13 @@ abstract class BinaryStatePowerStatsProcessor extends PowerStatsProcessor {
}
computeDevicePowerEstimates(stats, mPlan, mEnergyConsumerSupported);
- combineDevicePowerEstimates(stats);
- List<Integer> uids = new ArrayList<>();
- stats.collectUids(uids);
-
- computeUidActivityTotals(stats, uids);
- computeUidPowerEstimates(stats, uids);
+ IntArray uids = stats.getActiveUids();
+ if (uids.size() != 0) {
+ combineDevicePowerEstimates(stats);
+ computeUidActivityTotals(stats, uids);
+ computeUidPowerEstimates(stats, uids);
+ }
}
protected void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats,
@@ -239,8 +239,7 @@ abstract class BinaryStatePowerStatsProcessor extends PowerStatsProcessor {
}
}
- private void computeUidActivityTotals(PowerComponentAggregatedPowerStats stats,
- List<Integer> uids) {
+ private void computeUidActivityTotals(PowerComponentAggregatedPowerStats stats, IntArray uids) {
for (int i = mPlan.uidStateEstimates.size() - 1; i >= 0; i--) {
UidStateEstimate uidStateEstimate = mPlan.uidStateEstimates.get(i);
Intermediates intermediates =
@@ -259,8 +258,7 @@ abstract class BinaryStatePowerStatsProcessor extends PowerStatsProcessor {
}
}
- private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats,
- List<Integer> uids) {
+ private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats, IntArray uids) {
for (int i = mPlan.uidStateEstimates.size() - 1; i >= 0; i--) {
UidStateEstimate uidStateEstimate = mPlan.uidStateEstimates.get(i);
Intermediates intermediates =
@@ -276,12 +274,13 @@ abstract class BinaryStatePowerStatsProcessor extends PowerStatsProcessor {
int uid = uids.get(k);
if (stats.getUidStats(mTmpUidStatsArray, uid,
proportionalEstimate.stateValues)) {
- double power = intermediates.power
- * mStatsLayout.getUidUsageDuration(mTmpUidStatsArray)
- / intermediates.duration;
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues,
- mTmpUidStatsArray);
+ long duration = mStatsLayout.getUidUsageDuration(mTmpUidStatsArray);
+ if (duration != 0) {
+ double power = intermediates.power * duration / intermediates.duration;
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues,
+ mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java
index 4c1a0db02273..c1cd3acf1656 100644
--- a/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java
@@ -16,12 +16,13 @@
package com.android.server.power.stats.processor;
+import android.util.IntArray;
+
import com.android.internal.os.PowerProfile;
import com.android.internal.os.PowerStats;
import com.android.server.power.stats.UsageBasedPowerEstimator;
import com.android.server.power.stats.format.BluetoothPowerStatsLayout;
-import java.util.ArrayList;
import java.util.List;
class BluetoothPowerStatsProcessor extends PowerStatsProcessor {
@@ -118,18 +119,19 @@ class BluetoothPowerStatsProcessor extends PowerStatsProcessor {
combineDeviceStateEstimates();
- ArrayList<Integer> uids = new ArrayList<>();
- stats.collectUids(uids);
- if (!uids.isEmpty()) {
- for (int uid : uids) {
- for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) {
- computeUidActivityTotals(stats, uid, mPlan.uidStateEstimates.get(i));
+ IntArray uids = stats.getActiveUids();
+ if (uids.size() != 0) {
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ int uid = uids.get(i);
+ for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) {
+ computeUidActivityTotals(stats, uid, mPlan.uidStateEstimates.get(j));
}
}
- for (int uid : uids) {
- for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) {
- computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(i));
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ int uid = uids.get(i);
+ for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) {
+ computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(j));
}
}
}
@@ -297,8 +299,10 @@ class BluetoothPowerStatsProcessor extends PowerStatsProcessor {
/ intermediates.txBytes;
}
}
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ if (power != 0) {
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java
index 17ceca6e3dc1..6ce2cf738192 100644
--- a/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java
@@ -19,6 +19,7 @@ package com.android.server.power.stats.processor;
import android.annotation.Nullable;
import android.os.BatteryConsumer;
import android.util.ArraySet;
+import android.util.IntArray;
import android.util.Log;
import com.android.internal.os.CpuScalingPolicies;
@@ -27,7 +28,6 @@ import com.android.internal.os.PowerStats;
import com.android.server.power.stats.format.CpuPowerStatsLayout;
import com.android.server.power.stats.format.WakelockPowerStatsLayout;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -189,12 +189,12 @@ class CpuPowerStatsProcessor extends PowerStatsProcessor {
estimatePowerByDeviceState(stats, intermediates, wakelockStats);
combineDeviceStateEstimates();
- ArrayList<Integer> uids = new ArrayList<>();
- stats.collectUids(uids);
- if (!uids.isEmpty()) {
- for (int uid : uids) {
- for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) {
- estimateUidPowerConsumption(stats, uid, mPlan.uidStateEstimates.get(i),
+ IntArray uids = stats.getActiveUids();
+ if (uids.size() != 0) {
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ int uid = uids.get(i);
+ for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) {
+ estimateUidPowerConsumption(stats, uid, mPlan.uidStateEstimates.get(j),
wakelockStats);
}
}
@@ -545,8 +545,10 @@ class CpuPowerStatsProcessor extends PowerStatsProcessor {
power = Math.max(0, power - wakelockPowerEstimate);
}
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ if (power != 0) {
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java
index 76adc47cc165..76ea7e841106 100644
--- a/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java
@@ -16,10 +16,11 @@
package com.android.server.power.stats.processor;
+import android.util.IntArray;
+
import com.android.internal.os.PowerStats;
import com.android.server.power.stats.format.EnergyConsumerPowerStatsLayout;
-import java.util.ArrayList;
import java.util.List;
class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor {
@@ -40,10 +41,8 @@ class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor {
computeDevicePowerEstimates(stats);
- List<Integer> uids = new ArrayList<>();
- stats.collectUids(uids);
-
- if (!uids.isEmpty()) {
+ IntArray uids = stats.getActiveUids();
+ if (uids.size() != 0) {
computeUidPowerEstimates(stats, uids);
}
}
@@ -62,7 +61,7 @@ class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor {
}
private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats,
- List<Integer> uids) {
+ IntArray uids) {
for (int i = mPlan.uidStateEstimates.size() - 1; i >= 0; i--) {
UidStateEstimate uidStateEstimate = mPlan.uidStateEstimates.get(i);
List<UidStateProportionalEstimate> proportionalEstimates =
@@ -73,9 +72,12 @@ class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor {
int uid = uids.get(k);
if (stats.getUidStats(mTmpUidStatsArray, uid,
proportionalEstimate.stateValues)) {
- sLayout.setUidPowerEstimate(mTmpUidStatsArray,
- uCtoMah(sLayout.getUidConsumedEnergy(mTmpUidStatsArray, 0)));
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ double power = uCtoMah(sLayout.getUidConsumedEnergy(mTmpUidStatsArray, 0));
+ if (power != 0) {
+ sLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues,
+ mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java
index b4c40de862b4..a544daad82f1 100644
--- a/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java
@@ -19,6 +19,7 @@ import android.os.BatteryStats;
import android.telephony.CellSignalStrength;
import android.telephony.ModemActivityInfo;
import android.telephony.ServiceState;
+import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -29,7 +30,6 @@ import com.android.internal.power.ModemPowerProfile;
import com.android.server.power.stats.UsageBasedPowerEstimator;
import com.android.server.power.stats.format.MobileRadioPowerStatsLayout;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -198,18 +198,19 @@ class MobileRadioPowerStatsProcessor extends PowerStatsProcessor {
combineDeviceStateEstimates();
- ArrayList<Integer> uids = new ArrayList<>();
- stats.collectUids(uids);
- if (!uids.isEmpty()) {
- for (int uid : uids) {
- for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) {
- computeUidRxTxTotals(stats, uid, mPlan.uidStateEstimates.get(i));
+ IntArray uids = stats.getActiveUids();
+ if (uids.size() != 0) {
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ int uid = uids.get(i);
+ for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) {
+ computeUidRxTxTotals(stats, uid, mPlan.uidStateEstimates.get(j));
}
}
- for (int uid : uids) {
- for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) {
- computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(i));
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ int uid = uids.get(i);
+ for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) {
+ computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(j));
}
}
}
@@ -382,8 +383,10 @@ class MobileRadioPowerStatsProcessor extends PowerStatsProcessor {
/ intermediates.txPackets;
}
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ if (power != 0) {
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
if (DEBUG) {
Slog.d(TAG, "UID: " + uid
diff --git a/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java b/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java
index 28474a554b38..69325757c79d 100644
--- a/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java
+++ b/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java
@@ -16,6 +16,7 @@
package com.android.server.power.stats.processor;
+import android.annotation.Nullable;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -333,9 +334,9 @@ class MultiStateStats {
/**
* Adds the delta to the metrics. The number of values must correspond to the dimension count
- * supplied to the Factory constructor
+ * supplied to the Factory constructor. Null values is equivalent to an array of zeros.
*/
- void increment(long[] values, long timestampMs) {
+ void increment(@Nullable long[] values, long timestampMs) {
mCounter.incrementValues(values, timestampMs);
mTracking = true;
}
diff --git a/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java
index d4f8fd92fc6c..f9b9da9171cb 100644
--- a/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java
+++ b/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.os.BatteryStats;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
+import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -34,7 +35,6 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Arrays;
-import java.util.Collection;
import java.util.function.IntConsumer;
/**
@@ -72,11 +72,11 @@ class PowerComponentAggregatedPowerStats {
private MultiStateStats mDeviceStats;
private final SparseArray<MultiStateStats> mStateStats = new SparseArray<>();
private final SparseArray<UidStats> mUidStats = new SparseArray<>();
- private long[] mZeroArray;
private static class UidStats {
public int[] states;
public MultiStateStats stats;
+ public boolean hasPowerStats;
public boolean updated;
}
@@ -200,6 +200,7 @@ class PowerComponentAggregatedPowerStats {
if (uidStats.stats == null) {
createUidStats(uidStats, mPowerStatsTimestamp);
}
+ uidStats.hasPowerStats = true;
uidStats.stats.setStats(states, values);
}
@@ -240,6 +241,7 @@ class PowerComponentAggregatedPowerStats {
}
uidStats.stats.increment(powerStats.uidStats.valueAt(i), timestampMs);
uidStats.updated = true;
+ uidStats.hasPowerStats = true;
}
// For UIDs not mentioned in the PowerStats object, we must assume a 0 increment.
@@ -248,11 +250,8 @@ class PowerComponentAggregatedPowerStats {
for (int i = mUidStats.size() - 1; i >= 0; i--) {
PowerComponentAggregatedPowerStats.UidStats uidStats = mUidStats.valueAt(i);
if (!uidStats.updated && uidStats.stats != null) {
- if (mZeroArray == null
- || mZeroArray.length != mPowerStatsDescriptor.uidStatsArrayLength) {
- mZeroArray = new long[mPowerStatsDescriptor.uidStatsArrayLength];
- }
- uidStats.stats.increment(mZeroArray, timestampMs);
+ // Null stands for an array of zeros
+ uidStats.stats.increment(null, timestampMs);
}
uidStats.updated = false;
}
@@ -267,6 +266,7 @@ class PowerComponentAggregatedPowerStats {
mStateStats.clear();
for (int i = mUidStats.size() - 1; i >= 0; i--) {
mUidStats.valueAt(i).stats = null;
+ mUidStats.valueAt(i).hasPowerStats = false;
}
}
@@ -290,12 +290,26 @@ class PowerComponentAggregatedPowerStats {
return uidStats;
}
- void collectUids(Collection<Integer> uids) {
+ IntArray getUids() {
+ IntArray uids = new IntArray(mUidStats.size());
+ for (int i = mUidStats.size() - 1; i >= 0; i--) {
+ UidStats uidStats = mUidStats.valueAt(i);
+ if (uidStats.stats != null) {
+ uids.add(mUidStats.keyAt(i));
+ }
+ }
+ return uids;
+ }
+
+ IntArray getActiveUids() {
+ IntArray uids = new IntArray(mUidStats.size());
for (int i = mUidStats.size() - 1; i >= 0; i--) {
- if (mUidStats.valueAt(i).stats != null) {
+ UidStats uidStats = mUidStats.valueAt(i);
+ if (uidStats.hasPowerStats) {
uids.add(mUidStats.keyAt(i));
}
}
+ return uids;
}
boolean getDeviceStats(long[] outValues, int[] deviceStates) {
@@ -516,6 +530,7 @@ class PowerComponentAggregatedPowerStats {
if (uidStats.stats == null) {
createUidStats(uidStats, UNKNOWN);
}
+ uidStats.hasPowerStats = true;
if (!uidStats.stats.readFromXml(parser)) {
return false;
}
diff --git a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java
index 177d12988a27..634415ece806 100644
--- a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java
+++ b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java
@@ -21,6 +21,7 @@ import android.os.AggregateBatteryConsumer;
import android.os.BatteryConsumer;
import android.os.BatteryUsageStats;
import android.os.UidBatteryConsumer;
+import android.util.IntArray;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -31,7 +32,6 @@ import com.android.server.power.stats.PowerStatsStore;
import com.android.server.power.stats.format.BasePowerStatsLayout;
import com.android.server.power.stats.format.PowerStatsLayout;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -180,8 +180,7 @@ class PowerStatsExporter {
}
}
if (layout.isUidPowerAttributionSupported()) {
- populateBatteryConsumers(batteryUsageStatsBuilder,
- powerComponentStats, layout);
+ populateBatteryConsumers(batteryUsageStatsBuilder, powerComponentStats, layout);
}
populateBatteryLevelInfo(batteryUsageStatsBuilder, batteryLevelInfo);
@@ -258,6 +257,11 @@ class PowerStatsExporter {
BatteryUsageStats.Builder batteryUsageStatsBuilder,
PowerComponentAggregatedPowerStats powerComponentStats,
PowerStatsLayout layout) {
+ IntArray uids = powerComponentStats.getUids();
+ if (uids.size() == 0) {
+ return;
+ }
+
AggregatedPowerStatsConfig.PowerComponent powerComponent = powerComponentStats.getConfig();
PowerStats.Descriptor descriptor = powerComponentStats.getPowerStatsDescriptor();
long[] uidStats = new long[descriptor.uidStatsArrayLength];
@@ -273,8 +277,6 @@ class PowerStatsExporter {
breakDownByProcState = false;
}
- ArrayList<Integer> uids = new ArrayList<>();
- powerComponentStats.collectUids(uids);
for (int screenState = 0; screenState < BatteryConsumer.SCREEN_STATE_COUNT; screenState++) {
if (batteryUsageStatsBuilder.isScreenStateDataNeeded()) {
if (screenState == BatteryConsumer.SCREEN_STATE_UNSPECIFIED) {
@@ -303,7 +305,7 @@ class PowerStatsExporter {
private void populateUidBatteryConsumers(
BatteryUsageStats.Builder batteryUsageStatsBuilder,
PowerComponentAggregatedPowerStats powerComponentStats, PowerStatsLayout layout,
- List<Integer> uids, AggregatedPowerStatsConfig.PowerComponent powerComponent,
+ IntArray uids, AggregatedPowerStatsConfig.PowerComponent powerComponent,
long[] uidStats, boolean breakDownByProcState,
@BatteryConsumer.ScreenState int screenState,
@BatteryConsumer.PowerState int powerState) {
@@ -319,7 +321,8 @@ class PowerStatsExporter {
long[] durationByProcState =
new long[breakDownByProcState ? BatteryConsumer.PROCESS_STATE_COUNT : 1];
double powerAllApps = 0;
- for (int uid : uids) {
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ int uid = uids.get(i);
UidBatteryConsumer.Builder builder =
batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid);
diff --git a/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java
index 8e7498f38fcb..9df3d7eea27b 100644
--- a/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java
@@ -27,6 +27,7 @@ import static com.android.server.power.stats.processor.AggregatedPowerStatsConfi
import static com.android.server.power.stats.processor.AggregatedPowerStatsConfig.STATE_SCREEN;
import android.os.BatteryStats;
+import android.util.IntArray;
import android.util.Slog;
import com.android.internal.os.PowerProfile;
@@ -34,7 +35,6 @@ import com.android.internal.os.PowerStats;
import com.android.server.power.stats.UsageBasedPowerEstimator;
import com.android.server.power.stats.format.ScreenPowerStatsLayout;
-import java.util.ArrayList;
import java.util.List;
class ScreenPowerStatsProcessor extends PowerStatsProcessor {
@@ -116,10 +116,8 @@ class ScreenPowerStatsProcessor extends PowerStatsProcessor {
computeDevicePowerEstimates(stats);
combineDeviceStateEstimates();
- List<Integer> uids = new ArrayList<>();
- stats.collectUids(uids);
-
- if (!uids.isEmpty()) {
+ IntArray uids = stats.getActiveUids();
+ if (uids.size() != 0) {
computeUidPowerEstimates(stats, uids);
}
mPlan.resetIntermediates();
@@ -197,7 +195,7 @@ class ScreenPowerStatsProcessor extends PowerStatsProcessor {
}
private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats,
- List<Integer> uids) {
+ IntArray uids) {
int[] uidStateValues = new int[stats.getConfig().getUidStateConfig().length];
uidStateValues[STATE_SCREEN] = SCREEN_STATE_ON;
uidStateValues[STATE_PROCESS_STATE] = PROCESS_STATE_UNSPECIFIED;
@@ -232,9 +230,11 @@ class ScreenPowerStatsProcessor extends PowerStatsProcessor {
int uid = uids.get(j);
if (stats.getUidStats(mTmpUidStatsArray, uid, uidStateValues)) {
long duration = mStatsLayout.getUidTopActivityDuration(mTmpUidStatsArray);
- double power = intermediates.power * duration / totalTopActivityDuration;
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, uidStateValues, mTmpUidStatsArray);
+ if (duration != 0) {
+ double power = intermediates.power * duration / totalTopActivityDuration;
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, uidStateValues, mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/SensorPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/SensorPowerStatsProcessor.java
index 0bb028bce5af..ba728d36d561 100644
--- a/services/core/java/com/android/server/power/stats/processor/SensorPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/SensorPowerStatsProcessor.java
@@ -21,6 +21,7 @@ import android.hardware.SensorManager;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.PersistableBundle;
+import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -28,7 +29,6 @@ import com.android.internal.os.PowerStats;
import com.android.server.power.stats.format.PowerStatsLayout;
import com.android.server.power.stats.format.SensorPowerStatsLayout;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
@@ -207,11 +207,11 @@ class SensorPowerStatsProcessor extends PowerStatsProcessor {
mPlan = new PowerEstimationPlan(stats.getConfig());
}
- List<Integer> uids = new ArrayList<>();
- stats.collectUids(uids);
-
- computeUidPowerEstimates(stats, uids);
- computeDevicePowerEstimates(stats);
+ IntArray uids = stats.getActiveUids();
+ if (uids.size() != 0) {
+ computeUidPowerEstimates(stats, uids);
+ computeDevicePowerEstimates(stats);
+ }
mPlan.resetIntermediates();
}
@@ -239,9 +239,7 @@ class SensorPowerStatsProcessor extends PowerStatsProcessor {
mLastUpdateTimestamp = timestamp;
}
- private void computeUidPowerEstimates(
- PowerComponentAggregatedPowerStats stats,
- List<Integer> uids) {
+ private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats, IntArray uids) {
List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
int[] uidSensorDurationPositions = new int[sensorList.size()];
double[] sensorPower = new double[sensorList.size()];
@@ -292,8 +290,7 @@ class SensorPowerStatsProcessor extends PowerStatsProcessor {
}
}
- private void computeDevicePowerEstimates(
- PowerComponentAggregatedPowerStats stats) {
+ private void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats) {
for (int i = mPlan.combinedDeviceStateEstimations.size() - 1; i >= 0; i--) {
CombinedDeviceStateEstimate estimation =
mPlan.combinedDeviceStateEstimations.get(i);
diff --git a/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java
index 0df01cf7e5d1..8cc0b6eb6150 100644
--- a/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java
@@ -16,6 +16,7 @@
package com.android.server.power.stats.processor;
+import android.util.IntArray;
import android.util.Slog;
import com.android.internal.os.PowerProfile;
@@ -23,7 +24,6 @@ import com.android.internal.os.PowerStats;
import com.android.server.power.stats.UsageBasedPowerEstimator;
import com.android.server.power.stats.format.WifiPowerStatsLayout;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -148,18 +148,19 @@ class WifiPowerStatsProcessor extends PowerStatsProcessor {
combineDeviceStateEstimates();
- ArrayList<Integer> uids = new ArrayList<>();
- stats.collectUids(uids);
- if (!uids.isEmpty()) {
- for (int uid : uids) {
- for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) {
- computeUidActivityTotals(stats, uid, mPlan.uidStateEstimates.get(i));
+ IntArray uids = stats.getActiveUids();
+ if (uids.size() != 0) {
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ int uid = uids.get(i);
+ for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) {
+ computeUidActivityTotals(stats, uid, mPlan.uidStateEstimates.get(j));
}
}
- for (int uid : uids) {
- for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) {
- computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(i));
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ int uid = uids.get(i);
+ for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) {
+ computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(j));
}
}
}
@@ -374,8 +375,10 @@ class WifiPowerStatsProcessor extends PowerStatsProcessor {
/ intermediates.batchedScanDuration;
}
}
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ if (power != 0) {
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
if (DEBUG) {
Slog.d(TAG, "UID: " + uid
diff --git a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
index 1b6ce9dacfa9..64b52b175252 100644
--- a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
+++ b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
@@ -176,14 +176,14 @@ final class VendorVibrationSession extends IVibrationSession.Stub
@Override
public void onCancel() {
- Slog.d(TAG, "Cancellation signal received, cancelling vibration session...");
+ Slog.d(TAG, "Session cancellation signal received, aborting vibration session...");
requestEndSession(Status.CANCELLED_BY_USER, /* shouldAbort= */ true,
/* isVendorRequest= */ true);
}
@Override
public void binderDied() {
- Slog.d(TAG, "Binder died, cancelling vibration session...");
+ Slog.d(TAG, "Session binder died, aborting vibration session...");
requestEndSession(Status.CANCELLED_BINDER_DIED, /* shouldAbort= */ true,
/* isVendorRequest= */ false);
}
@@ -219,18 +219,20 @@ final class VendorVibrationSession extends IVibrationSession.Stub
@Override
public void notifyVibratorCallback(int vibratorId, long vibrationId) {
- // Ignore it, the session vibration playback doesn't depend on HAL timings
+ Slog.d(TAG, "Vibration callback received for vibration " + vibrationId
+ + " on vibrator " + vibratorId + ", ignoring...");
}
@Override
public void notifySyncedVibratorsCallback(long vibrationId) {
- // Ignore it, the session vibration playback doesn't depend on HAL timings
+ Slog.d(TAG, "Synced vibration callback received for vibration " + vibrationId
+ + ", ignoring...");
}
@Override
public void notifySessionCallback() {
+ Slog.d(TAG, "Session callback received, ending vibration session...");
synchronized (mLock) {
- Slog.d(TAG, "Session callback received, ending vibration session...");
// If end was not requested then the HAL has cancelled the session.
maybeSetEndRequestLocked(Status.CANCELLED_BY_UNKNOWN_REASON,
/* isVendorRequest= */ false);
@@ -307,7 +309,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub
}
}
if (isAlreadyEnded) {
- // Session already ended, make sure we end it in the HAL.
+ Slog.d(TAG, "Session already ended after starting the HAL, aborting...");
mHandler.post(() -> mManagerHooks.endSession(mSessionId, /* shouldAbort= */ true));
}
}
@@ -335,8 +337,8 @@ final class VendorVibrationSession extends IVibrationSession.Stub
public boolean maybeSetVibrationConductor(VibrationStepConductor conductor) {
synchronized (mLock) {
if (mConductor != null) {
- Slog.d(TAG, "Vibration session still dispatching previous vibration,"
- + " new vibration ignored");
+ Slog.d(TAG, "Session still dispatching previous vibration, new vibration "
+ + conductor.getVibration().id + " ignored");
return false;
}
mConductor = conductor;
@@ -345,19 +347,22 @@ final class VendorVibrationSession extends IVibrationSession.Stub
}
private void requestEndSession(Status status, boolean shouldAbort, boolean isVendorRequest) {
+ Slog.d(TAG, "Session end request received with status " + status);
boolean shouldTriggerSessionHook = false;
synchronized (mLock) {
maybeSetEndRequestLocked(status, isVendorRequest);
- if (isStarted()) {
- // Always trigger session hook after it has started, in case new request aborts an
- // already finishing session. Wait for HAL callback before actually ending here.
+ if (!isEnded() && isStarted()) {
+ // Trigger session hook even if it was already triggered, in case a second request
+ // is aborting the ongoing/ending session. This might cause it to end right away.
+ // Wait for HAL callback before setting the end status.
shouldTriggerSessionHook = true;
} else {
- // Session did not start in the HAL, end it right away.
+ // Session not active in the HAL, set end status right away.
maybeSetStatusToRequestedLocked();
}
}
if (shouldTriggerSessionHook) {
+ Slog.d(TAG, "Requesting HAL session end with abort=" + shouldAbort);
mHandler.post(() -> mManagerHooks.endSession(mSessionId, shouldAbort));
}
}
@@ -368,6 +373,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub
// End already requested, keep first requested status and time.
return;
}
+ Slog.d(TAG, "Session end request accepted for status " + status);
mEndStatusRequest = status;
mEndedByVendor = isVendorRequest;
mEndTime = System.currentTimeMillis();
@@ -400,6 +406,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub
// No end status was requested, nothing to set.
return;
}
+ Slog.d(TAG, "Session end request applied for status " + mEndStatusRequest);
mStatus = mEndStatusRequest;
// Run client callback in separate thread.
final Status endStatus = mStatus;
@@ -407,7 +414,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub
try {
mCallback.onFinished(toSessionStatus(endStatus));
} catch (RemoteException e) {
- Slog.e(TAG, "Error notifying vendor session is finishing", e);
+ Slog.e(TAG, "Error notifying vendor session finished", e);
}
});
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 9de46c878194..75b1b202bcfd 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -61,6 +61,7 @@ import android.os.VibratorInfo;
import android.os.vibrator.Flags;
import android.os.vibrator.IVibrationSessionCallback;
import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
import android.os.vibrator.VibrationConfig;
import android.os.vibrator.VibrationEffectSegment;
import android.os.vibrator.VibratorInfoFactory;
@@ -786,7 +787,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "Starting session " + session.getSessionId());
+ Slog.d(TAG, "Starting vendor session " + session.getSessionId());
}
Status ignoreStatus = null;
@@ -864,13 +865,16 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
// Session already ended, possibly cancelled by app cancellation signal.
return session.getStatus();
}
- int mode = startAppOpModeLocked(session.getCallerInfo());
+ CallerInfo callerInfo = session.getCallerInfo();
+ int mode = startAppOpModeLocked(callerInfo);
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
Trace.asyncTraceBegin(TRACE_TAG_VIBRATOR, "vibration", 0);
// Make sure mCurrentVibration is set while triggering the HAL.
mCurrentSession = session;
if (!session.linkToDeath()) {
+ // Shouldn't happen. The method call already logs.
+ finishAppOpModeLocked(callerInfo);
mCurrentSession = null;
return Status.IGNORED_ERROR_TOKEN;
}
@@ -878,14 +882,14 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
Slog.e(TAG, "Error starting session " + sessionId + " on vibrators "
+ Arrays.toString(session.getVibratorIds()));
session.unlinkToDeath();
+ finishAppOpModeLocked(callerInfo);
mCurrentSession = null;
return Status.IGNORED_UNSUPPORTED;
}
session.notifyStart();
return null;
case AppOpsManager.MODE_ERRORED:
- Slog.w(TAG, "Start AppOpsManager operation errored for uid "
- + session.getCallerInfo().uid);
+ Slog.w(TAG, "Start AppOpsManager operation errored for uid " + callerInfo.uid);
return Status.IGNORED_ERROR_APP_OPS;
default:
return Status.IGNORED_APP_OPS;
@@ -1081,11 +1085,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
@Nullable
private Status startVibrationOnThreadLocked(SingleVibrationSession session) {
if (DEBUG) {
- Slog.d(TAG, "Starting vibration " + session.getVibration().id + " on thread");
+ Slog.d(TAG, "Starting vibration " + session.getVibration().id + " on thread");
}
VibrationStepConductor conductor = createVibrationStepConductor(session.getVibration());
session.setVibrationConductor(conductor);
- int mode = startAppOpModeLocked(session.getCallerInfo());
+ CallerInfo callerInfo = session.getCallerInfo();
+ int mode = startAppOpModeLocked(callerInfo);
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
Trace.asyncTraceBegin(TRACE_TAG_VIBRATOR, "vibration", 0);
@@ -1093,19 +1098,21 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
mCurrentSession = session;
if (!mCurrentSession.linkToDeath()) {
// Shouldn't happen. The method call already logs.
+ finishAppOpModeLocked(callerInfo);
mCurrentSession = null; // Aborted.
return Status.IGNORED_ERROR_TOKEN;
}
if (!mVibrationThread.runVibrationOnVibrationThread(conductor)) {
// Shouldn't happen. The method call already logs.
session.setVibrationConductor(null); // Rejected by thread, clear it in session.
+ mCurrentSession.unlinkToDeath();
+ finishAppOpModeLocked(callerInfo);
mCurrentSession = null; // Aborted.
return Status.IGNORED_ERROR_SCHEDULING;
}
return null;
case AppOpsManager.MODE_ERRORED:
- Slog.w(TAG, "Start AppOpsManager operation errored for uid "
- + session.getCallerInfo().uid);
+ Slog.w(TAG, "Start AppOpsManager operation errored for uid " + callerInfo.uid);
return Status.IGNORED_ERROR_APP_OPS;
default:
return Status.IGNORED_APP_OPS;
@@ -1494,6 +1501,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
private int checkAppOpModeLocked(CallerInfo callerInfo) {
int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
callerInfo.attrs.getAudioUsage(), callerInfo.uid, callerInfo.opPkg);
+ if (DEBUG) {
+ int opMode = mAppOps.checkOpNoThrow(AppOpsManager.OP_VIBRATE, callerInfo.uid,
+ callerInfo.opPkg);
+ Slog.d(TAG, "Check AppOp mode VIBRATE for uid " + callerInfo.uid + " and package "
+ + callerInfo.opPkg + " returned audio=" + AppOpsManager.MODE_NAMES[mode]
+ + ", op=" + AppOpsManager.MODE_NAMES[opMode]);
+ }
int fixedMode = fixupAppOpModeLocked(mode, callerInfo.attrs);
if (mode != fixedMode && fixedMode == AppOpsManager.MODE_ALLOWED) {
// If we're just ignoring the vibration op then this is set by DND and we should ignore
@@ -1507,9 +1521,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
/** Start an operation in {@link AppOpsManager}, if allowed. */
@GuardedBy("mLock")
private int startAppOpModeLocked(CallerInfo callerInfo) {
- return fixupAppOpModeLocked(
- mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, callerInfo.uid, callerInfo.opPkg),
- callerInfo.attrs);
+ int mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, callerInfo.uid,
+ callerInfo.opPkg);
+ if (DEBUG) {
+ Slog.d(TAG, "Start AppOp mode VIBRATE for uid " + callerInfo.uid + " and package "
+ + callerInfo.opPkg + " returned " + AppOpsManager.MODE_NAMES[mode]);
+ }
+ return fixupAppOpModeLocked(mode, callerInfo.attrs);
}
/**
@@ -1518,6 +1536,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
*/
@GuardedBy("mLock")
private void finishAppOpModeLocked(CallerInfo callerInfo) {
+ if (DEBUG) {
+ Slog.d(TAG, "Finish AppOp mode VIBRATE for uid " + callerInfo.uid + " and package "
+ + callerInfo.opPkg);
+ }
mAppOps.finishOp(AppOpsManager.OP_VIBRATE, callerInfo.uid, callerInfo.opPkg);
}
@@ -2651,7 +2673,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
CombinedVibration.ParallelCombination combination =
CombinedVibration.startParallel();
while ("-v".equals(getNextOption())) {
- int vibratorId = Integer.parseInt(getNextArgRequired());
+ int vibratorId = parseInt(getNextArgRequired(), "Expected vibrator id after -v");
combination.addVibrator(vibratorId, nextEffect());
}
runVibrate(commonOptions, combination.combine());
@@ -2663,7 +2685,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
CombinedVibration.SequentialCombination combination =
CombinedVibration.startSequential();
while ("-v".equals(getNextOption())) {
- int vibratorId = Integer.parseInt(getNextArgRequired());
+ int vibratorId = parseInt(getNextArgRequired(), "Expected vibrator id after -v");
combination.addNext(vibratorId, nextEffect());
}
runVibrate(commonOptions, combination.combine());
@@ -2688,7 +2710,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
private int runHapticFeedback() {
CommonOptions commonOptions = new CommonOptions();
- int constant = Integer.parseInt(getNextArgRequired());
+ int constant = parseInt(getNextArgRequired(), "Expected haptic feedback constant id");
IBinder deathBinder = commonOptions.background ? VibratorManagerService.this
: mShellCallbacksToken;
@@ -2736,12 +2758,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
if ("-a".equals(nextOption)) {
hasAmplitude = true;
} else if ("-w".equals(nextOption)) {
- delay = Integer.parseInt(getNextArgRequired());
+ delay = parseInt(getNextArgRequired(), "Expected delay millis after -w");
}
}
- long duration = Long.parseLong(getNextArgRequired());
- int amplitude = hasAmplitude ? Integer.parseInt(getNextArgRequired())
+ long duration = parseInt(getNextArgRequired(), "Expected one-shot duration millis");
+ int amplitude = hasAmplitude
+ ? parseInt(getNextArgRequired(), "Expected one-shot amplitude")
: VibrationEffect.DEFAULT_AMPLITUDE;
composition.addOffDuration(Duration.ofMillis(delay));
composition.addEffect(VibrationEffect.createOneShot(duration, amplitude));
@@ -2816,8 +2839,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
while ((nextOption = getNextOption()) != null) {
switch (nextOption) {
case "-a" -> isAdvanced = true;
- case "-i" -> initialSharpness = Float.parseFloat(getNextArgRequired());
- case "-r" -> repeat = Integer.parseInt(getNextArgRequired());
+ case "-i" -> initialSharpness = parseFloat(getNextArgRequired(),
+ "Expected initial sharpness after -i");
+ case "-r" -> repeat = parseInt(getNextArgRequired(),
+ "Expected repeat index after -r");
}
}
@@ -2843,8 +2868,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
// nextArg is not a duration, finish reading.
break;
}
- intensity = Float.parseFloat(getNextArgRequired());
- sharpness = Float.parseFloat(getNextArgRequired());
+ intensity = parseFloat(getNextArgRequired(), "Expected envelope intensity");
+ sharpness = parseFloat(getNextArgRequired(), "Expected envelope sharpness");
builder.addControlPoint(intensity, sharpness, duration);
pos++;
}
@@ -2872,16 +2897,14 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
getNextArgRequired(); // consume "waveform"
String nextOption;
while ((nextOption = getNextOption()) != null) {
- if ("-a".equals(nextOption)) {
- hasAmplitudes = true;
- } else if ("-r".equals(nextOption)) {
- repeat = Integer.parseInt(getNextArgRequired());
- } else if ("-w".equals(nextOption)) {
- delay = Integer.parseInt(getNextArgRequired());
- } else if ("-f".equals(nextOption)) {
- hasFrequencies = true;
- } else if ("-c".equals(nextOption)) {
- isContinuous = true;
+ switch (nextOption) {
+ case "-a" -> hasAmplitudes = true;
+ case "-f" -> hasFrequencies = true;
+ case "-c" -> isContinuous = true;
+ case "-r" -> repeat = parseInt(getNextArgRequired(),
+ "Expected repeat index after -r");
+ case "-w" -> delay = parseInt(getNextArgRequired(),
+ "Expected delay millis after -w");
}
}
List<Integer> durations = new ArrayList<>();
@@ -2899,14 +2922,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
break;
}
if (hasAmplitudes) {
- amplitudes.add(
- Float.parseFloat(getNextArgRequired()) / VibrationEffect.MAX_AMPLITUDE);
+ int amplitude = parseInt(getNextArgRequired(), "Expected waveform amplitude");
+ amplitudes.add((float) amplitude / VibrationEffect.MAX_AMPLITUDE);
} else {
amplitudes.add(nextAmplitude);
nextAmplitude = 1 - nextAmplitude;
}
if (hasFrequencies) {
- frequencies.add(Float.parseFloat(getNextArgRequired()));
+ frequencies.add(
+ parseFloat(getNextArgRequired(), "Expected waveform frequency"));
}
}
@@ -2965,27 +2989,37 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
if ("-b".equals(nextOption)) {
shouldFallback = true;
} else if ("-w".equals(nextOption)) {
- delay = Integer.parseInt(getNextArgRequired());
+ delay = parseInt(getNextArgRequired(), "Expected delay millis after -w");
}
}
- int effectId = Integer.parseInt(getNextArgRequired());
+ int effectId = parseInt(getNextArgRequired(), "Expected prebaked effect id");
composition.addOffDuration(Duration.ofMillis(delay));
composition.addEffect(VibrationEffect.get(effectId, shouldFallback));
}
private void addPrimitivesToComposition(VibrationEffect.Composition composition) {
getNextArgRequired(); // consume "primitives"
- String nextArg;
- while ((nextArg = peekNextArg()) != null) {
+ while (peekNextArg() != null) {
int delay = 0;
- if ("-w".equals(nextArg)) {
- getNextArgRequired(); // consume "-w"
- delay = Integer.parseInt(getNextArgRequired());
- nextArg = peekNextArg();
+ float scale = 1f;
+ int delayType = PrimitiveSegment.DEFAULT_DELAY_TYPE;
+
+ String nextOption;
+ while ((nextOption = getNextOption()) != null) {
+ if ("-s".equals(nextOption)) {
+ scale = parseFloat(getNextArgRequired(), "Expected scale after -s");
+ } else if ("-o".equals(nextOption)) {
+ delayType = VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
+ delay = parseInt(getNextArgRequired(), "Expected offset millis after -o");
+ } else if ("-w".equals(nextOption)) {
+ delayType = PrimitiveSegment.DEFAULT_DELAY_TYPE;
+ delay = parseInt(getNextArgRequired(), "Expected delay millis after -w");
+ }
}
try {
- composition.addPrimitive(Integer.parseInt(nextArg), /* scale= */ 1, delay);
+ String nextArg = peekNextArg(); // Just in case this is not a primitive.
+ composition.addPrimitive(Integer.parseInt(nextArg), scale, delay, delayType);
getNextArgRequired(); // consume the primitive id
} catch (NumberFormatException | NullPointerException e) {
// nextArg is not describing a primitive, leave it to be consumed by outer loops
@@ -3011,17 +3045,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
VibrationXmlParser.parseDocument(new StringReader(xml));
VibratorInfo combinedVibratorInfo = getCombinedVibratorInfo();
if (combinedVibratorInfo == null) {
- throw new IllegalStateException(
- "No combined vibrator info to parse vibration XML " + xml);
+ throw new IllegalStateException("No vibrator info available to parse XML");
}
VibrationEffect effect = parsedVibration.resolve(combinedVibratorInfo);
if (effect == null) {
- throw new IllegalArgumentException(
- "Parsed vibration cannot be resolved for vibration XML " + xml);
+ throw new IllegalArgumentException("Parsed XML cannot be resolved: " + xml);
}
return CombinedVibration.createParallel(effect);
} catch (IOException e) {
- throw new RuntimeException("Error parsing vibration XML " + xml, e);
+ throw new RuntimeException("Error parsing XML: " + xml, e);
}
}
@@ -3039,16 +3071,30 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
}
+ private static int parseInt(String text, String errorMessage) {
+ try {
+ return Integer.parseInt(text);
+ } catch (NumberFormatException | NullPointerException e) {
+ throw new IllegalArgumentException(errorMessage, e);
+ }
+ }
+
+ private static float parseFloat(String text, String errorMessage) {
+ try {
+ return Float.parseFloat(text);
+ } catch (NumberFormatException | NullPointerException e) {
+ throw new IllegalArgumentException(errorMessage, e);
+ }
+ }
+
@Override
public void onHelp() {
try (PrintWriter pw = getOutPrintWriter();) {
pw.println("Vibrator Manager commands:");
pw.println(" help");
pw.println(" Prints this help text.");
- pw.println("");
pw.println(" list");
- pw.println(" Prints the id of device vibrators. This does not include any ");
- pw.println(" connected input device.");
+ pw.println(" Prints device vibrator ids; does not include input devices.");
pw.println(" synced [options] <effect>...");
pw.println(" Vibrates effect on all vibrators in sync.");
pw.println(" combined [options] (-v <vibrator-id> <effect>...)...");
@@ -3058,51 +3104,41 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
pw.println(" xml [options] <xml>");
pw.println(" Vibrates using combined vibration described in given XML string");
pw.println(" on all vibrators in sync. The XML could be:");
- pw.println(" XML containing a single effect, or");
- pw.println(" A vibration select XML containing multiple effects.");
- pw.println(" Vibrates using combined vibration described in given XML string.");
- pw.println(" XML containing a single effect it runs on all vibrators in sync.");
+ pw.println(" A single <vibration-effect>, or");
+ pw.println(" A <vibration-select> containing multiple effects.");
+ pw.println(" feedback [options] <constant>");
+ pw.println(" Performs a haptic feedback with the given constant.");
pw.println(" cancel");
pw.println(" Cancels any active vibration");
- pw.println(" feedback [-f] [-d <description>] <constant>");
- pw.println(" Performs a haptic feedback with the given constant.");
- pw.println(" The force (-f) option enables the `always` configuration, which");
- pw.println(" plays the haptic irrespective of the vibration intensity settings");
pw.println("");
pw.println("Effect commands:");
pw.println(" oneshot [-w delay] [-a] <duration> [<amplitude>]");
- pw.println(" Vibrates for duration milliseconds; ignored when device is on ");
- pw.println(" DND (Do Not Disturb) mode; touch feedback strength user setting ");
- pw.println(" will be used to scale amplitude.");
+ pw.println(" Vibrates for duration milliseconds.");
pw.println(" If -w is provided, the effect will be played after the specified");
pw.println(" wait time in milliseconds.");
pw.println(" If -a is provided, the command accepts a second argument for ");
pw.println(" amplitude, in a scale of 1-255.");
pw.print(" waveform [-w delay] [-r index] [-a] [-f] [-c] ");
pw.println("(<duration> [<amplitude>] [<frequency>])...");
- pw.println(" Vibrates for durations and amplitudes in list; ignored when ");
- pw.println(" device is on DND (Do Not Disturb) mode; touch feedback strength ");
- pw.println(" user setting will be used to scale amplitude.");
+ pw.println(" Vibrates for durations and amplitudes in list.");
pw.println(" If -w is provided, the effect will be played after the specified");
pw.println(" wait time in milliseconds.");
pw.println(" If -r is provided, the waveform loops back to the specified");
- pw.println(" index (e.g. 0 loops from the beginning)");
+ pw.println(" index (e.g. 0 loops from the beginning).");
pw.println(" If -a is provided, the command expects amplitude to follow each");
pw.println(" duration; otherwise, it accepts durations only and alternates");
- pw.println(" off/on");
+ pw.println(" off/on.");
pw.println(" If -f is provided, the command expects frequency to follow each");
- pw.println(" amplitude or duration; otherwise, it uses resonant frequency");
+ pw.println(" amplitude or duration; otherwise, it uses resonant frequency.");
pw.println(" If -c is provided, the waveform is continuous and will ramp");
pw.println(" between values; otherwise each entry is a fixed step.");
pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255;");
- pw.println(" frequency is an absolute value in hertz;");
+ pw.println(" frequency is an absolute value in hertz.");
pw.print(" envelope [-a] [-i initial sharpness] [-r index] ");
pw.println("[<duration1> <intensity1> <sharpness1>]...");
pw.println(" Generates a vibration pattern based on a series of duration, ");
pw.println(" intensity, and sharpness values. The total vibration time is ");
- pw.println(" the sum of all durations; Ignored when device is on ");
- pw.println(" DND (Do Not Disturb) mode; touch feedback strength user setting ");
- pw.println(" will be used to scale amplitude.");
+ pw.println(" the sum of all durations.");
pw.println(" If -a is provided, the waveform will use the advanced APIs to ");
pw.println(" generate the vibration pattern and the input parameters ");
pw.println(" become [<duration1> <amplitude1> <frequency1>].");
@@ -3111,19 +3147,20 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
pw.println(" If -r is provided, the waveform loops back to the specified index");
pw.println(" (e.g. 0 loops from the beginning).");
pw.println(" prebaked [-w delay] [-b] <effect-id>");
- pw.println(" Vibrates with prebaked effect; ignored when device is on DND ");
- pw.println(" (Do Not Disturb) mode; touch feedback strength user setting ");
- pw.println(" will be used to scale amplitude.");
+ pw.println(" Vibrates with prebaked effect.");
pw.println(" If -w is provided, the effect will be played after the specified");
pw.println(" wait time in milliseconds.");
pw.println(" If -b is provided, the prebaked fallback effect will be played if");
pw.println(" the device doesn't support the given effect-id.");
- pw.println(" primitives ([-w delay] <primitive-id>)...");
- pw.println(" Vibrates with a composed effect; ignored when device is on DND ");
- pw.println(" (Do Not Disturb) mode; touch feedback strength user setting ");
- pw.println(" will be used to scale primitive intensities.");
+ pw.print(" primitives ([-w delay] [-o time] [-s scale]");
+ pw.println("<primitive-id> [<scale>])...");
+ pw.println(" Vibrates with a composed effect.");
pw.println(" If -w is provided, the next primitive will be played after the ");
pw.println(" specified wait time in milliseconds.");
+ pw.println(" If -o is provided, the next primitive will be played at the ");
+ pw.println(" specified start offset time in milliseconds.");
+ pw.println(" If -s is provided, the next primitive will be played with the");
+ pw.println(" specified amplitude scale, in a scale of [0,1].");
pw.println("");
pw.println("Common Options:");
pw.println(" -f");
@@ -3134,6 +3171,11 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
pw.println(" -d <description>");
pw.println(" Add description to the vibration.");
pw.println("");
+ pw.println("Notes");
+ pw.println(" Vibrations triggered by these commands will be ignored when");
+ pw.println(" device is on DND (Do Not Disturb) mode; notification strength");
+ pw.println(" user settings will be applied for scale.");
+ pw.println("");
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0a57cb50d681..c243cdc23137 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -617,6 +617,9 @@ public abstract class ActivityTaskManagerInternal {
*/
public abstract boolean isBaseOfLockedTask(String packageName);
+ /** Returns the value of {@link android.R.attr#windowNoDisplay} from the given theme. */
+ public abstract boolean isNoDisplay(String packageName, int theme, int userId);
+
/**
* Creates an interface to update configuration for the calling application.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 4e2fade599ba..37783781a901 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -7448,6 +7448,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
+ public boolean isNoDisplay(String packageName, int theme, int userId) {
+ if (!com.android.window.flags.Flags.cacheWindowStyle()) {
+ final AttributeCache.Entry ent = AttributeCache.instance()
+ .get(packageName, theme, R.styleable.Window, userId);
+ return ent != null
+ && ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
+ }
+ final ActivityRecord.WindowStyle style = getWindowStyle(packageName, theme, userId);
+ return style != null && style.noDisplay();
+ }
+
+ @Override
public PackageConfigurationUpdater createPackageConfigurationUpdater() {
return new PackageConfigurationUpdaterImpl(Binder.getCallingPid(),
ActivityTaskManagerService.this);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fd322a5c6345..e30c24d87d20 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -162,6 +162,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.content.ComponentCallbacks;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -456,6 +457,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
private DisplayInfo mLastDisplayInfoOverride;
private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ @NonNull
private final DisplayPolicy mDisplayPolicy;
private final DisplayRotation mDisplayRotation;
@@ -542,6 +544,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/** Remove this display when animation on it has completed. */
private boolean mDeferredRemoval;
+ @NonNull
final PinnedTaskController mPinnedTaskController;
private final LinkedList<ActivityRecord> mTmpUpdateAllDrawn = new LinkedList();
@@ -1102,6 +1105,29 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
};
/**
+ * Called to update fields retrieve from {@link #getDisplayUiContext()} resources when
+ * there's a configuration update on {@link #getDisplayUiContext()}.
+ */
+ @NonNull
+ private final ComponentCallbacks mSysUiContextConfigCallback = new ComponentCallbacks() {
+
+ @Override
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ synchronized (mWmService.mGlobalLock) {
+ if (mDisplayReady) {
+ mDisplayPolicy.onConfigurationChanged();
+ mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
+ }
+ }
+ }
+
+ @Override
+ public void onLowMemory() {
+ // Do nothing.
+ }
+ };
+
+ /**
* Create new {@link DisplayContent} instance, add itself to the root window container and
* initialize direct children.
* @param display May not be null.
@@ -2797,11 +2823,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final int lastOrientation = getConfiguration().orientation;
final int lastWindowingMode = getWindowingMode();
super.onConfigurationChanged(newParentConfig);
- if (mDisplayPolicy != null) {
- mDisplayPolicy.onConfigurationChanged();
- mPinnedTaskController.onPostDisplayConfigurationChanged();
- mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
+ if (!Flags.trackSystemUiContextBeforeWms()) {
+ mSysUiContextConfigCallback.onConfigurationChanged(newParentConfig);
}
+ mPinnedTaskController.onPostDisplayConfigurationChanged();
// Update IME parent if needed.
updateImeParent();
@@ -3381,6 +3406,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
.getKeyguardController().onDisplayRemoved(mDisplayId);
mWallpaperController.resetLargestDisplay(mDisplay);
mWmService.mDisplayWindowSettings.onDisplayRemoved(this);
+ if (Flags.trackSystemUiContextBeforeWms()) {
+ getDisplayUiContext().unregisterComponentCallbacks(mSysUiContextConfigCallback);
+ }
} finally {
mDisplayReady = false;
}
@@ -3817,7 +3845,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (mTmpWindow == null) {
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows, display=%d",
getDisplayId());
- return null;
}
return mTmpWindow;
}
@@ -5429,7 +5456,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
reconfigureDisplayLocked();
onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
- // Attach the SystemUiContext to this DisplayContent the get latest configuration.
+ // Attach the SystemUiContext to this DisplayContent to get latest configuration.
// Note that the SystemUiContext will be removed automatically if this DisplayContent
// is detached.
registerSystemUiContext();
@@ -5437,11 +5464,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
private void registerSystemUiContext() {
+ final Context systemUiContext = getDisplayUiContext();
final WindowProcessController wpc = mAtmService.getProcessController(
- getDisplayUiContext().getIApplicationThread());
+ systemUiContext.getIApplicationThread());
mWmService.mWindowContextListenerController.registerWindowContainerListener(
- wpc, getDisplayUiContext().getWindowContextToken(), this,
+ wpc, systemUiContext.getWindowContextToken(), this,
INVALID_WINDOW_TYPE, null /* options */);
+ if (Flags.trackSystemUiContextBeforeWms()) {
+ systemUiContext.registerComponentCallbacks(mSysUiContextConfigCallback);
+ }
}
@Override
@@ -6620,6 +6651,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
forAllTasks((t) -> { t.getRootTask().removeChild(t, "removeAllTasks"); });
}
+ @NonNull
Context getDisplayUiContext() {
return mDisplayPolicy.getSystemUiContext();
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 10f591cfd379..fbe850198c50 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1865,6 +1865,7 @@ public class DisplayPolicy {
return mContext;
}
+ @NonNull
Context getSystemUiContext() {
return mUiContext;
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index a698a9e82929..bbda849262b2 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1910,7 +1910,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (!hasDirectChildActivities()) {
return false;
}
- if (mResumedActivity != null && mTransitionController.isTransientLaunch(mResumedActivity)) {
+ if (mResumedActivity != null && !mResumedActivity.finishing
+ && mTransitionController.isTransientLaunch(mResumedActivity)) {
// Even if the transient activity is occluded, defer pausing (addToStopping will still
// be called) it until the transient transition is done. So the current resuming
// activity won't need to wait for additional pause complete.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d699a689459e..0b20911bcab2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1820,125 +1820,138 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean hideSystemAlertWindows = shouldHideNonSystemOverlayWindow(win);
win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
- boolean imMayMove = true;
-
- win.mToken.addWindow(win);
- displayPolicy.addWindowLw(win, attrs);
- displayPolicy.setDropInputModePolicy(win, win.mAttrs);
- if (type == TYPE_APPLICATION_STARTING && activity != null) {
- activity.attachStartingWindow(win);
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
- activity, win);
- } else if (type == TYPE_INPUT_METHOD
- // IME window is always touchable.
- // Ignore non-touchable windows e.g. Stylus InkWindow.java.
- && (win.getAttrs().flags & FLAG_NOT_TOUCHABLE) == 0) {
- displayContent.setInputMethodWindowLocked(win);
- imMayMove = false;
- } else if (type == TYPE_INPUT_METHOD_DIALOG) {
- displayContent.computeImeTarget(true /* updateImeTarget */);
- imMayMove = false;
- } else {
- if (type == TYPE_WALLPAPER) {
- displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- } else if (win.hasWallpaper()) {
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
- // If there is currently a wallpaper being shown, and
- // the base layer of the new window is below the current
- // layer of the target window, then adjust the wallpaper.
- // This is to avoid a new window being placed between the
- // wallpaper and its target.
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- }
- }
+ res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState,
+ outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs);
+ }
- final WindowStateAnimator winAnimator = win.mWinAnimator;
- winAnimator.mEnterAnimationPending = true;
- winAnimator.mEnteringAnimation = true;
+ Binder.restoreCallingIdentity(origId);
- if (displayPolicy.areSystemBarsForcedConsumedLw()) {
- res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
- }
- if (displayContent.isInTouchMode()) {
- res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
- }
- if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) {
- res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
+ return res;
+ }
+
+ private int addWindowInner(@NonNull WindowState win, @NonNull DisplayPolicy displayPolicy,
+ @NonNull ActivityRecord activity, @NonNull DisplayContent displayContent,
+ @NonNull InsetsState outInsetsState, @NonNull Rect outAttachedFrame,
+ @NonNull InsetsSourceControl.Array outActiveControls, @NonNull IWindow client,
+ @NonNull float[] outSizeCompatScale, @NonNull LayoutParams attrs) {
+ int res = 0;
+ final int type = attrs.type;
+ boolean imMayMove = true;
+
+ win.mToken.addWindow(win);
+ displayPolicy.addWindowLw(win, attrs);
+ displayPolicy.setDropInputModePolicy(win, win.mAttrs);
+ if (type == TYPE_APPLICATION_STARTING && activity != null) {
+ activity.attachStartingWindow(win);
+ ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
+ activity, win);
+ } else if (type == TYPE_INPUT_METHOD
+ // IME window is always touchable.
+ // Ignore non-touchable windows e.g. Stylus InkWindow.java.
+ && (win.getAttrs().flags & FLAG_NOT_TOUCHABLE) == 0) {
+ displayContent.setInputMethodWindowLocked(win);
+ imMayMove = false;
+ } else if (type == TYPE_INPUT_METHOD_DIALOG) {
+ displayContent.computeImeTarget(true /* updateImeTarget */);
+ imMayMove = false;
+ } else {
+ if (type == TYPE_WALLPAPER) {
+ displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
+ displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ } else if (win.hasWallpaper()) {
+ displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
+ // If there is currently a wallpaper being shown, and
+ // the base layer of the new window is below the current
+ // layer of the target window, then adjust the wallpaper.
+ // This is to avoid a new window being placed between the
+ // wallpaper and its target.
+ displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
+ }
- displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
+ final WindowStateAnimator winAnimator = win.mWinAnimator;
+ winAnimator.mEnterAnimationPending = true;
+ winAnimator.mEnteringAnimation = true;
- boolean focusChanged = false;
- if (win.canReceiveKeys()) {
- focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
- false /*updateInputWindows*/);
- if (focusChanged) {
- imMayMove = false;
- }
- }
+ if (displayPolicy.areSystemBarsForcedConsumedLw()) {
+ res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
+ }
+ if (displayContent.isInTouchMode()) {
+ res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
+ }
+ if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) {
+ res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
+ }
- if (imMayMove) {
- displayContent.computeImeTarget(true /* updateImeTarget */);
- if (win.isImeOverlayLayeringTarget()) {
- dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), win.mAttrs.type,
- win.isVisibleRequestedOrAdding(), false /* removed */,
- displayContent.getDisplayId());
- }
- }
+ displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
- // Don't do layout here, the window must call
- // relayout to be displayed, so we'll do it there.
- if (win.mActivityRecord != null && win.mActivityRecord.isEmbedded()) {
- // Assign child layers from the parent Task if the Activity is embedded.
- win.getTask().assignChildLayers();
- } else {
- win.getParent().assignChildLayers();
+ boolean focusChanged = false;
+ if (win.canReceiveKeys()) {
+ focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
+ false /*updateInputWindows*/);
+ if (focusChanged) {
+ imMayMove = false;
}
+ }
- if (focusChanged) {
- displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
- false /*updateInputWindows*/);
+ if (imMayMove) {
+ displayContent.computeImeTarget(true /* updateImeTarget */);
+ if (win.isImeOverlayLayeringTarget()) {
+ dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), win.mAttrs.type,
+ win.isVisibleRequestedOrAdding(), false /* removed */,
+ displayContent.getDisplayId());
}
- displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
+ }
- ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
- + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
+ // Don't do layout here, the window must call
+ // relayout to be displayed, so we'll do it there.
+ if (win.mActivityRecord != null && win.mActivityRecord.isEmbedded()) {
+ // Assign child layers from the parent Task if the Activity is embedded.
+ win.getTask().assignChildLayers();
+ } else {
+ win.getParent().assignChildLayers();
+ }
- boolean needToSendNewConfiguration =
- win.isVisibleRequestedOrAdding() && displayContent.updateOrientation();
- if (win.providesDisplayDecorInsets()) {
- needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo();
- }
- if (needToSendNewConfiguration) {
- displayContent.sendNewConfiguration();
- }
+ if (focusChanged) {
+ displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
+ false /*updateInputWindows*/);
+ }
+ displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
- // This window doesn't have a frame yet. Don't let this window cause the insets change.
- displayContent.getInsetsStateController().updateAboveInsetsState(
- false /* notifyInsetsChanged */);
+ ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
+ + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
- win.fillInsetsState(outInsetsState, true /* copySources */);
- getInsetsSourceControls(win, outActiveControls);
+ boolean needToSendNewConfiguration =
+ win.isVisibleRequestedOrAdding() && displayContent.updateOrientation();
+ if (win.providesDisplayDecorInsets()) {
+ needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo();
+ }
+ if (needToSendNewConfiguration) {
+ displayContent.sendNewConfiguration();
+ }
- if (win.mLayoutAttached) {
- outAttachedFrame.set(win.getParentWindow().getFrame());
- if (win.mInvGlobalScale != 1f) {
- outAttachedFrame.scale(win.mInvGlobalScale);
- }
- } else {
- // Make this invalid which indicates a null attached frame.
- outAttachedFrame.set(0, 0, -1, -1);
- }
- outSizeCompatScale[0] = win.getCompatScaleForClient();
+ // This window doesn't have a frame yet. Don't let this window cause the insets change.
+ displayContent.getInsetsStateController().updateAboveInsetsState(
+ false /* notifyInsetsChanged */);
+
+ win.fillInsetsState(outInsetsState, true /* copySources */);
+ getInsetsSourceControls(win, outActiveControls);
- if (res >= ADD_OKAY && win.isPresentation()) {
- mPresentationController.onPresentationAdded(win);
+ if (win.mLayoutAttached) {
+ outAttachedFrame.set(win.getParentWindow().getFrame());
+ if (win.mInvGlobalScale != 1f) {
+ outAttachedFrame.scale(win.mInvGlobalScale);
}
+ } else {
+ // Make this invalid which indicates a null attached frame.
+ outAttachedFrame.set(0, 0, -1, -1);
}
+ outSizeCompatScale[0] = win.getCompatScaleForClient();
- Binder.restoreCallingIdentity(origId);
+ if (res >= ADD_OKAY && win.isPresentation()) {
+ mPresentationController.onPresentationAdded(win);
+ }
return res;
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 2d3f7231cc5c..ae5e85163e9a 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -866,6 +866,9 @@ public class InputMethodServiceTest {
() -> mActivity.showImeWithWindowInsetsController(),
EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ eventually(() -> assertWithMessage("IME navigation bar is shown")
+ .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue());
+
final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
verifyInputViewStatus(
() -> {
@@ -892,6 +895,9 @@ public class InputMethodServiceTest {
() -> mActivity.showImeWithWindowInsetsController(),
EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ eventually(() -> assertWithMessage("IME navigation bar is shown")
+ .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue());
+
final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
verifyInputViewStatus(
() -> {
@@ -927,6 +933,9 @@ public class InputMethodServiceTest {
},
EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ eventually(() -> assertWithMessage("IME navigation bar is shown")
+ .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue());
+
final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
imeSwitcherButton.click();
mInstrumentation.waitForIdleSync();
@@ -965,6 +974,9 @@ public class InputMethodServiceTest {
},
EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ eventually(() -> assertWithMessage("IME navigation bar is shown")
+ .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue());
+
final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
imeSwitcherButton.longClick();
mInstrumentation.waitForIdleSync();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 7d25acd7f5e7..a42116351c2d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -152,7 +152,7 @@ public class AutomaticBrightnessControllerTest {
}
@Override
- AutomaticBrightnessController.Clock createClock(boolean isEnabled) {
+ AutomaticBrightnessController.Clock createClock() {
return new AutomaticBrightnessController.Clock() {
@Override
public long uptimeMillis() {
@@ -618,39 +618,46 @@ public class AutomaticBrightnessControllerTest {
long increment = 500;
// set autobrightness to low
// t = 0
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
// t = 500
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
// t = 1000
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
// t = 1500
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
// t = 2000
// ensure that our reading is at 0.
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
// t = 2500
// first 10000 lux sensor event reading
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertTrue(mController.getAmbientLux() > 0.0f);
assertTrue(mController.getAmbientLux() < 10000.0f);
// t = 3000
// lux reading should still not yet be 10000.
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertTrue(mController.getAmbientLux() > 0.0f);
assertTrue(mController.getAmbientLux() < 10000.0f);
@@ -659,45 +666,53 @@ public class AutomaticBrightnessControllerTest {
// lux has been high (10000) for 1000ms.
// lux reading should be 10000
// short horizon (ambient lux) is high, long horizon is still not high
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(10000.0f, mController.getAmbientLux(), EPSILON);
// t = 4000
// stay high
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(10000.0f, mController.getAmbientLux(), EPSILON);
// t = 4500
Mockito.clearInvocations(mBrightnessMappingStrategy);
mClock.fastForward(increment);
// short horizon is high, long horizon is high too
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
verify(mBrightnessMappingStrategy, times(1)).getBrightness(10000, null, -1);
assertEquals(10000.0f, mController.getAmbientLux(), EPSILON);
// t = 5000
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertTrue(mController.getAmbientLux() > 0.0f);
assertTrue(mController.getAmbientLux() < 10000.0f);
// t = 5500
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertTrue(mController.getAmbientLux() > 0.0f);
assertTrue(mController.getAmbientLux() < 10000.0f);
// t = 6000
mClock.fastForward(increment);
// ambient lux goes to 0
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
// only the values within the horizon should be kept
assertArrayEquals(new float[] {10000, 10000, 0, 0, 0}, mController.getLastSensorValues(),
EPSILON);
- assertArrayEquals(new long[] {4000, 4500, 5000, 5500, 6000},
+ assertArrayEquals(new long[]{4000 + ANDROID_SLEEP_TIME, 4500 + ANDROID_SLEEP_TIME,
+ 5000 + ANDROID_SLEEP_TIME, 5500 + ANDROID_SLEEP_TIME,
+ 6000 + ANDROID_SLEEP_TIME},
mController.getLastSensorTimestamps());
}
@@ -793,7 +808,8 @@ public class AutomaticBrightnessControllerTest {
for (int i = 0; i < 1000; i++) {
lux += increment;
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
}
int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment + 1);
@@ -807,17 +823,17 @@ public class AutomaticBrightnessControllerTest {
long sensorTimestamp = mClock.now();
for (int i = valuesCount - 1; i >= 1; i--) {
assertEquals(lux, sensorValues[i], EPSILON);
- assertEquals(sensorTimestamp, sensorTimestamps[i]);
+ assertEquals(sensorTimestamp + ANDROID_SLEEP_TIME, sensorTimestamps[i]);
lux -= increment;
sensorTimestamp -= increment;
}
assertEquals(lux, sensorValues[0], EPSILON);
- assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]);
+ assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG + ANDROID_SLEEP_TIME,
+ sensorTimestamps[0]);
}
@Test
public void testAmbientLuxBuffers_prunedBeyondLongHorizonExceptLatestValue() throws Exception {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
ArgumentCaptor<SensorEventListener> listenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
@@ -867,7 +883,8 @@ public class AutomaticBrightnessControllerTest {
for (int i = 0; i < 20; i++) {
lux += increment1;
mClock.fastForward(increment1);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
}
int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment1 + 1);
@@ -877,7 +894,8 @@ public class AutomaticBrightnessControllerTest {
for (int i = 0; i < initialCapacity - valuesCount; i++) {
lux += increment2;
mClock.fastForward(increment2);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
}
float[] sensorValues = mController.getLastSensorValues();
@@ -890,7 +908,7 @@ public class AutomaticBrightnessControllerTest {
long sensorTimestamp = mClock.now();
for (int i = initialCapacity - 1; i >= 1; i--) {
assertEquals(lux, sensorValues[i], EPSILON);
- assertEquals(sensorTimestamp, sensorTimestamps[i]);
+ assertEquals(sensorTimestamp + ANDROID_SLEEP_TIME, sensorTimestamps[i]);
if (i >= valuesCount) {
lux -= increment2;
@@ -901,7 +919,8 @@ public class AutomaticBrightnessControllerTest {
}
}
assertEquals(lux, sensorValues[0], EPSILON);
- assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]);
+ assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG + ANDROID_SLEEP_TIME,
+ sensorTimestamps[0]);
}
@Test
@@ -951,25 +970,29 @@ public class AutomaticBrightnessControllerTest {
// t = 0
// Initial lux
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 1000
// Lux isn't steady yet
mClock.fastForward(1000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 1500
// Lux isn't steady yet
mClock.fastForward(500);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 2500
// Lux is steady now
mClock.fastForward(1000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
}
@@ -992,25 +1015,29 @@ public class AutomaticBrightnessControllerTest {
// t = 0
// Initial lux
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 2000
// Lux isn't steady yet
mClock.fastForward(2000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 2500
// Lux isn't steady yet
mClock.fastForward(500);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 4500
// Lux is steady now
mClock.fastForward(2000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
}
@@ -1031,19 +1058,22 @@ public class AutomaticBrightnessControllerTest {
// t = 0
// Initial lux
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 500
// Lux isn't steady yet
mClock.fastForward(500);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 1500
// Lux is steady now
mClock.fastForward(1000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
}
@@ -1068,19 +1098,22 @@ public class AutomaticBrightnessControllerTest {
// t = 0
// Initial lux
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 1000
// Lux isn't steady yet
mClock.fastForward(1000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 2500
// Lux is steady now
mClock.fastForward(1500);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index aed1f9858660..db94958f769e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1066,7 +1066,6 @@ public final class DisplayPowerControllerTest {
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
- when(mDisplayManagerFlagsMock.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
@@ -1172,7 +1171,6 @@ public final class DisplayPowerControllerTest {
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
- when(mDisplayManagerFlagsMock.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(false);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
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 2ebb6c2a3ce4..ef39167dbabc 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
@@ -240,7 +240,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void selectStrategyDoesNotSelectDozeStrategyWhenOffloadSessionAutoBrightnessIsEnabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -378,7 +377,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void selectStrategy_selectsAutomaticStrategyWhenValid() {
when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -409,7 +407,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void selectStrategy_doesNotSelectAutomaticStrategyWhenStylusInUse() {
when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -536,7 +533,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void setAllowAutoBrightnessWhileDozing_enabledWhenConfigAndOffloadSessionAreEnabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -550,7 +546,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void setAllowAutoBrightnessWhileDozing_disabledWhenOffloadSessionFlagIsDisabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(false);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -564,7 +559,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void setAllowAutoBrightnessWhileDozing_disabledWhenABWhileDozingConfigIsDisabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -588,7 +582,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void setAllowAutoBrightnessWhileDozing_EnabledWhenFlagsAreDisabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
true);
mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
@@ -600,11 +593,5 @@ public final class DisplayBrightnessStrategySelectorTest {
mDisplayBrightnessStrategySelector
.setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession);
assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing());
-
- when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(false);
- mDisplayBrightnessStrategySelector
- .setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession);
- assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing());
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index fa5847560782..4b53f1309337 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -23,18 +23,11 @@ import static com.android.server.am.ActivityManagerService.Injector;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.FrozenProcessListener;
import android.content.ComponentName;
import android.content.Context;
@@ -44,14 +37,12 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.MessageQueue;
import android.os.Process;
-import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.annotations.GuardedBy;
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.modules.utils.testing.TestableDeviceConfig;
import com.android.server.LocalServices;
@@ -68,11 +59,9 @@ import org.mockito.Mock;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
@@ -164,7 +153,7 @@ public final class CachedAppOptimizerTest {
app.info.uid = packageUid;
// Exact value does not mater, it can be any state for which compaction is allowed.
app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
- app.mState.setSetAdj(899);
+ app.mState.setSetAdj(940);
app.mState.setCurAdj(940);
return app;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobServiceContextTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobServiceContextTest.java
index 904545bd3cc3..b4e845171a0b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobServiceContextTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobServiceContextTest.java
@@ -276,6 +276,7 @@ public class JobServiceContextTest {
final int jobId = 123;
mJobServiceContext.setRunningJobLockedForTest(mMockJobStatus);
mJobServiceContext.setRunningCallbackLockedForTest(mMockJobCallback);
+ mJobServiceContext.mVerb = JobServiceContext.VERB_EXECUTING;
doReturn(jobId).when(mMockJobStatus).getJobId();
mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId);
@@ -296,7 +297,25 @@ public class JobServiceContextTest {
mJobServiceContext.setRunningCallbackLockedForTest(mMockJobCallback);
mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId);
+ verify(mMockJobStatus, never()).setAbandoned(true);
+
+ mJobServiceContext.setRunningJobLockedForTest(mMockJobStatus);
+ doReturn(jobId).when(mMockJobStatus).getJobId();
+
+ mJobServiceContext.mVerb = JobServiceContext.VERB_BINDING;
+ mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId);
+ verify(mMockJobStatus, never()).setAbandoned(true);
+ mJobServiceContext.mVerb = JobServiceContext.VERB_STARTING;
+ mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId);
+ verify(mMockJobStatus, never()).setAbandoned(true);
+
+ mJobServiceContext.mVerb = JobServiceContext.VERB_STOPPING;
+ mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId);
+ verify(mMockJobStatus, never()).setAbandoned(true);
+
+ mJobServiceContext.mVerb = JobServiceContext.VERB_FINISHED;
+ mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId);
verify(mMockJobStatus, never()).setAbandoned(true);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index c6870adb8464..4e4b3df3c935 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -295,15 +295,15 @@ public class QuotaControllerTest {
}
private void setCharging() {
- doReturn(true).when(mJobSchedulerService).isBatteryCharging();
synchronized (mQuotaController.mLock) {
+ doReturn(true).when(mJobSchedulerService).isBatteryCharging();
mQuotaController.onBatteryStateChangedLocked();
}
}
private void setDischarging() {
- doReturn(false).when(mJobSchedulerService).isBatteryCharging();
synchronized (mQuotaController.mLock) {
+ doReturn(false).when(mJobSchedulerService).isBatteryCharging();
mQuotaController.onBatteryStateChangedLocked();
}
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java
index 8fc8c9f677a6..6be9c6d4b80c 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java
@@ -48,6 +48,7 @@ import org.junit.runner.RunWith;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
@@ -121,7 +122,7 @@ public class BatteryUsageStatsProviderPerfTest {
}
@Test
- public void getBatteryUsageStats_accumulated() {
+ public void getBatteryUsageStats_accumulated() throws IOException {
BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
.setMaxStatsAgeMs(0)
.includePowerStateData()
@@ -155,6 +156,8 @@ public class BatteryUsageStatsProviderPerfTest {
// Verify that all iterations produce the same result
assertThat(cpuConsumedPower).isEqualTo(expectedCpuPower);
}
+ stats.close();
+
state.resumeTiming();
}
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/CpuPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/CpuPowerStatsProcessorTest.java
index cb9d9b12a2fc..dcddf06f01fb 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/CpuPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/CpuPowerStatsProcessorTest.java
@@ -34,6 +34,7 @@ import static org.junit.Assert.fail;
import android.os.BatteryConsumer;
import android.os.PersistableBundle;
import android.platform.test.ravenwood.RavenwoodRule;
+import android.util.IntArray;
import android.util.LongArray;
import androidx.test.filters.SmallTest;
@@ -51,7 +52,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -315,8 +315,12 @@ public class CpuPowerStatsProcessorTest {
}
@Override
- void collectUids(Collection<Integer> uids) {
- uids.addAll(mUids);
+ IntArray getActiveUids() {
+ IntArray uids = new IntArray();
+ for (Integer uid : mUids) {
+ uids.add(uid);
+ }
+ return uids;
}
void verifyPowerEstimates() {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java
index a232c0c7aec9..3b614bdb38ed 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java
@@ -143,6 +143,8 @@ public class MultiStateStatsTest {
multiStateStats.increment(new long[]{200, 200}, 5000);
+ multiStateStats.increment(null, 6000); // No-op
+
long[] stats = new long[DIMENSION_COUNT];
multiStateStats.getStats(stats, new int[]{0, BatteryConsumer.PROCESS_STATE_FOREGROUND, 0});
// (400 - 100) * 0.5 + (600 - 400) * 0.5
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index d702cae248a9..009ce88cfd6c 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -33,6 +33,9 @@ android_test {
"test-apps/DisplayManagerTestApp/src/**/*.java",
],
+ kotlincflags: [
+ "-Werror",
+ ],
static_libs: [
"a11ychecker",
"aatf",
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 834fea46e505..4531b3948495 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -199,6 +199,10 @@
<service android:name="com.android.server.job.MockBiasJobService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
+ <activity
+ android:name="android.app.Activity"
+ android:exported="false" />
+
<activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity"/>
<activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity2"/>
<activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3"/>
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e0023e59af50..30aa8cebdff6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1768,7 +1768,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
- @Ignore // b/396073342
public void testCertificateDisclosure() throws Exception {
final int userId = CALLER_USER_HANDLE;
final UserHandle user = UserHandle.of(userId);
@@ -4613,7 +4612,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
- @Ignore // b/396073342
public void testGetLastBugReportRequestTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -4661,7 +4659,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
- @Ignore // b/396073342
public void testGetLastNetworkLogRetrievalTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -6444,7 +6441,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
- @Ignore // b/396073342
public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception {
mServiceContext.packageName = mRealTestContext.getPackageName();
mServiceContext.applicationInfo = new ApplicationInfo();
@@ -6456,7 +6452,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
- @Ignore // b/396073342
public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception {
mServiceContext.packageName = mRealTestContext.getPackageName();
mServiceContext.applicationInfo = new ApplicationInfo();
@@ -6469,7 +6464,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
- @Ignore // b/396073342
public void testGetOwnerInstalledCaCertsForDelegate() throws Exception {
mServiceContext.packageName = mRealTestContext.getPackageName();
mServiceContext.applicationInfo = new ApplicationInfo();
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 87c9db2fe565..acbce36c3d7f 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -354,14 +354,20 @@ public abstract class BaseLockSettingsServiceTests {
@After
public void tearDown_baseServices() throws Exception {
- mStorage.closeDatabase();
+ if (mStorage != null) {
+ mStorage.closeDatabase();
+ }
File db = InstrumentationRegistry.getContext().getDatabasePath("locksettings.db");
assertTrue(!db.exists() || db.delete());
- File storageDir = mStorage.mStorageDir;
- assertTrue(FileUtils.deleteContents(storageDir));
+ if (mStorage != null) {
+ File storageDir = mStorage.mStorageDir;
+ assertTrue(FileUtils.deleteContents(storageDir));
+ }
- mPasswordSlotManager.cleanup();
+ if (mPasswordSlotManager != null) {
+ mPasswordSlotManager.cleanup();
+ }
}
protected void flushHandlerTasks() {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index 02b86db6ab6f..387b89a41eba 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -124,7 +124,9 @@ public class LockSettingsStorageTests {
@After
public void tearDown() throws Exception {
- mStorage.closeDatabase();
+ if (mStorage != null) {
+ mStorage.closeDatabase();
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java
index 2faf6a2b29d1..2c2b9374fdf9 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java
@@ -49,7 +49,9 @@ public class PasswordSlotManagerTests {
@After
public void tearDown() throws Exception {
- mManager.cleanup();
+ if (mManager != null) {
+ mManager.cleanup();
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 1514de04fb08..5add74e5b69e 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -156,9 +156,12 @@ public class KeySyncTaskTest {
@After
public void tearDown() {
- mRecoverableKeyStoreDb.close();
- mDatabaseFile.delete();
-
+ if (mRecoverableKeyStoreDb != null) {
+ mRecoverableKeyStoreDb.close();
+ }
+ if (mDatabaseFile != null) {
+ mDatabaseFile.delete();
+ }
File file = new File(InstrumentationRegistry.getTargetContext().getFilesDir(),
SNAPSHOT_TOP_LEVEL_DIRECTORY);
FileUtils.deleteContentsAndDir(file);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index c09e09c8404f..46eaba7dace6 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -117,8 +117,12 @@ public class PlatformKeyManagerTest {
@After
public void tearDown() {
- mRecoverableKeyStoreDb.close();
- mDatabaseFile.delete();
+ if (mRecoverableKeyStoreDb != null) {
+ mRecoverableKeyStoreDb.close();
+ }
+ if (mDatabaseFile != null) {
+ mDatabaseFile.delete();
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
index 64130266b2c4..e6a6e36e75d6 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
@@ -89,8 +89,12 @@ public class RecoverableKeyGeneratorTest {
keyStore.load(/*param=*/ null);
keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
- mRecoverableKeyStoreDb.close();
- mDatabaseFile.delete();
+ if (mRecoverableKeyStoreDb != null) {
+ mRecoverableKeyStoreDb.close();
+ }
+ if (mDatabaseFile != null) {
+ mDatabaseFile.delete();
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 7641fb957cc8..878c838e734b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -230,9 +230,15 @@ public class RecoverableKeyStoreManagerTest {
@After
public void tearDown() {
- mRemoteLockscreenValidationSessionStorage.finishSession(mUserId);
- mRecoverableKeyStoreDb.close();
- mDatabaseFile.delete();
+ if (mRemoteLockscreenValidationSessionStorage != null) {
+ mRemoteLockscreenValidationSessionStorage.finishSession(mUserId);
+ }
+ if (mRecoverableKeyStoreDb != null) {
+ mRecoverableKeyStoreDb.close();
+ }
+ if (mDatabaseFile != null) {
+ mDatabaseFile.delete();
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
index bbd9223718ae..fb98fab52ca0 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
@@ -18,6 +18,8 @@ package com.android.server.locksettings.recoverablekeystore.storage;
import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
@@ -36,8 +38,6 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class RecoverableKeyStoreDbHelperTest {
@@ -110,7 +110,9 @@ public class RecoverableKeyStoreDbHelperTest {
@After
public void tearDown() throws Exception {
- mDatabase.close();
+ if (mDatabase != null) {
+ mDatabase.close();
+ }
}
private void createV2Tables() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index 8bc14fc54ae1..a77d8bcd3875 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -72,8 +72,12 @@ public class RecoverableKeyStoreDbTest {
@After
public void tearDown() {
- mRecoverableKeyStoreDb.close();
- mDatabaseFile.delete();
+ if (mRecoverableKeyStoreDb != null) {
+ mRecoverableKeyStoreDb.close();
+ }
+ if (mDatabaseFile != null) {
+ mDatabaseFile.delete();
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayConstraintsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayConstraintsTests.java
index b2e296a36b93..2912a0762761 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayConstraintsTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayConstraintsTests.java
@@ -19,6 +19,7 @@ package com.android.server.om;
import static android.content.Context.DEVICE_ID_DEFAULT;
import static android.content.om.OverlayConstraint.TYPE_DEVICE_ID;
import static android.content.om.OverlayConstraint.TYPE_DISPLAY_ID;
+import static android.util.TypedValue.TYPE_STRING;
import static android.view.Display.DEFAULT_DISPLAY;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
@@ -28,6 +29,9 @@ import static junit.framework.Assert.assertNotNull;
import static org.testng.Assert.assertThrows;
+import android.app.Activity;
+import android.companion.virtual.VirtualDeviceManager;
+import android.content.Context;
import android.content.om.FabricatedOverlay;
import android.content.om.OverlayConstraint;
import android.content.om.OverlayIdentifier;
@@ -35,12 +39,12 @@ import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.content.om.OverlayManagerTransaction;
import android.content.res.Flags;
+import android.content.res.Resources;
import android.os.UserHandle;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.util.TypedValue;
+import android.view.Display;
+import android.virtualdevice.cts.common.VirtualDeviceRule;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
@@ -53,20 +57,28 @@ import org.junit.runner.RunWith;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeoutException;
@RunWith(JUnitParamsRunner.class)
public class OverlayConstraintsTests {
+ private static final String RESOURCE_NAME = "string/module_2_name";
+ private static final String RESOURCE_DEFAULT_VALUE = "module_2_name";
+ private static final String RESOURCE_OVERLAID_VALUE = "hello";
+ private static final long TIMEOUT_MILLIS = 2000L;
@Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ public final VirtualDeviceRule mVirtualDeviceRule = VirtualDeviceRule.createDefault();
private OverlayManager mOverlayManager;
private UserHandle mUserHandle;
private OverlayIdentifier mOverlayIdentifier = null;
+ private final String mPackageName = getApplicationContext().getPackageName();
@Before
public void setUp() throws Exception {
- mOverlayManager = getApplicationContext().getSystemService(OverlayManager.class);
+ final Context context = getApplicationContext();
+ mOverlayManager = context.getSystemService(OverlayManager.class);
mUserHandle = UserHandle.of(UserHandle.myUserId());
}
@@ -79,6 +91,7 @@ public class OverlayConstraintsTests {
.build();
mOverlayManager.commit(transaction);
mOverlayIdentifier = null;
+ waitForResourceValue(RESOURCE_DEFAULT_VALUE, getApplicationContext());
}
}
@@ -161,13 +174,161 @@ public class OverlayConstraintsTests {
List.of(new OverlayConstraint(TYPE_DISPLAY_ID, DEFAULT_DISPLAY))));
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS)
+ public void enableOverlayWithoutConstraints_appliesOverlayWithoutConstraints()
+ throws Exception {
+ enableOverlay(Collections.emptyList());
+
+ // Assert than the overlay is applied for both default device context and virtual
+ // device context.
+ final Context context = getApplicationContext();
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, context);
+ VirtualDeviceManager.VirtualDevice virtualDevice =
+ mVirtualDeviceRule.createManagedVirtualDevice();
+ final Context deviceContext = context.createDeviceContext(virtualDevice.getDeviceId());
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, deviceContext);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS)
+ public void enableOverlayWithConstraints_withTypeDeviceId_appliesOverlayWithConstraints()
+ throws Exception {
+ final int deviceId1 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId();
+ final int deviceId2 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId();
+ enableOverlay(List.of(new OverlayConstraint(TYPE_DEVICE_ID, deviceId1),
+ new OverlayConstraint(TYPE_DEVICE_ID, deviceId2)));
+
+ // Assert than the overlay is not applied for contexts not associated with the above
+ // devices.
+ final Context context = getApplicationContext();
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context);
+ final int deviceId3 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId();
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context.createDeviceContext(deviceId3));
+
+ // Assert than the overlay is applied for contexts associated with the above devices.
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDeviceContext(deviceId1));
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDeviceContext(deviceId2));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS)
+ public void enableOverlayWithConstraints_withTypeDisplayId_appliesOverlayWithConstraints()
+ throws Exception {
+ final Display display1 =
+ mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay();
+ final Display display2 =
+ mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay();
+ enableOverlay(List.of(new OverlayConstraint(TYPE_DISPLAY_ID, display1.getDisplayId()),
+ new OverlayConstraint(TYPE_DISPLAY_ID, display2.getDisplayId())));
+
+ // Assert than the overlay is not applied for contexts not associated with the above
+ // displays.
+ final Context context = getApplicationContext();
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context);
+ final Display display3 =
+ mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay();
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context.createDisplayContext(display3));
+
+ // Assert than the overlay is applied for contexts associated with the above displays.
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDisplayContext(display1));
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDisplayContext(display2));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS)
+ public void enableOverlayWithConstraints_withTypesDisplayIdAndDeviceId_appliesOverlayWithConstraints()
+ throws Exception {
+ final Display display1 =
+ mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay();
+ final int deviceId1 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId();
+ enableOverlay(List.of(new OverlayConstraint(TYPE_DISPLAY_ID, display1.getDisplayId()),
+ new OverlayConstraint(TYPE_DEVICE_ID, deviceId1)));
+
+ // Assert than the overlay is not applied for contexts not associated with the above
+ // display or device.
+ final Context context = getApplicationContext();
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context);
+ final Display display2 =
+ mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay();
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context.createDisplayContext(display2));
+ final int deviceId2 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId();
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context.createDeviceContext(deviceId2));
+
+ // Assert than the overlay is applied for contexts associated with the above display or
+ // device.
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDisplayContext(display1));
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDeviceContext(deviceId1));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS)
+ public void enableOverlayWithConstraints_withTypeDisplayId_appliesForActivityOnDisplay()
+ throws Exception {
+ final Display display =
+ mVirtualDeviceRule.createManagedUnownedVirtualDisplay(
+ VirtualDeviceRule.createTrustedVirtualDisplayConfigBuilder())
+ .getDisplay();
+ final Activity activityOnDefaultDisplay = mVirtualDeviceRule.startActivityOnDisplaySync(
+ DEFAULT_DISPLAY, Activity.class);
+ final Activity activityOnVirtualDisplay = mVirtualDeviceRule.startActivityOnDisplaySync(
+ display.getDisplayId(), Activity.class);
+
+ enableOverlay(List.of(new OverlayConstraint(TYPE_DISPLAY_ID, display.getDisplayId())));
+
+ // Assert than the overlay is not applied for any existing activity on the default display.
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, activityOnDefaultDisplay);
+ // Assert than the overlay is applied for any existing activity on the virtual display.
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, activityOnVirtualDisplay);
+
+ // Assert than the overlay is not applied for any new activity on the default display.
+ final Activity newActivityOnDefaultDisplay = mVirtualDeviceRule.startActivityOnDisplaySync(
+ DEFAULT_DISPLAY, Activity.class);
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, newActivityOnDefaultDisplay);
+ // Assert than the overlay is applied for any new activity on the virtual display.
+ final Activity newActivityOnVirtualDisplay = mVirtualDeviceRule.startActivityOnDisplaySync(
+ display.getDisplayId(), Activity.class);
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, newActivityOnVirtualDisplay);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS)
+ public void enableOverlayWithConstraints_withTypeDeviceId_appliesForActivityOnDevice()
+ throws Exception {
+ final VirtualDeviceManager.VirtualDevice device =
+ mVirtualDeviceRule.createManagedVirtualDevice();
+ final Display display =
+ mVirtualDeviceRule.createManagedVirtualDisplay(device,
+ VirtualDeviceRule.createTrustedVirtualDisplayConfigBuilder())
+ .getDisplay();
+ final Activity activityOnDefaultDevice = mVirtualDeviceRule.startActivityOnDisplaySync(
+ DEFAULT_DISPLAY, Activity.class);
+ final Activity activityOnVirtualDevice = mVirtualDeviceRule.startActivityOnDisplaySync(
+ display.getDisplayId(), Activity.class);
+
+ enableOverlay(List.of(new OverlayConstraint(TYPE_DEVICE_ID, device.getDeviceId())));
+
+ // Assert than the overlay is not applied for any existing activity on the default device.
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, activityOnDefaultDevice);
+ // Assert than the overlay is applied for any existing activity on the virtual device.
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, activityOnVirtualDevice);
+
+ // Assert than the overlay is not applied for any new activity on the default device.
+ final Activity newActivityOnDefaultDevice = mVirtualDeviceRule.startActivityOnDisplaySync(
+ DEFAULT_DISPLAY, Activity.class);
+ ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, newActivityOnDefaultDevice);
+ // Assert than the overlay is applied for any new activity on the virtual device.
+ final Activity newActivityOnVirtualDevice = mVirtualDeviceRule.startActivityOnDisplaySync(
+ display.getDisplayId(), Activity.class);
+ waitForResourceValue(RESOURCE_OVERLAID_VALUE, newActivityOnVirtualDevice);
+ }
+
private FabricatedOverlay createFabricatedOverlay() {
- String packageName = getApplicationContext().getPackageName();
FabricatedOverlay fabricatedOverlay = new FabricatedOverlay.Builder(
- packageName, "testOverlay" /* name */, packageName)
+ mPackageName, "testOverlay" /* name */, mPackageName)
.build();
- fabricatedOverlay.setResourceValue("string/module_2_name" /* resourceName */,
- TypedValue.TYPE_STRING, "hello" /* value */, null /* configuration */);
+ fabricatedOverlay.setResourceValue(RESOURCE_NAME, TYPE_STRING, RESOURCE_OVERLAID_VALUE,
+ null /* configuration */);
return fabricatedOverlay;
}
@@ -183,6 +344,37 @@ public class OverlayConstraintsTests {
mOverlayIdentifier = fabricatedOverlay.getIdentifier();
}
+ private static void waitForResourceValue(final String expectedValue, Context context)
+ throws TimeoutException {
+ final long endTime = System.currentTimeMillis() + TIMEOUT_MILLIS;
+ final Resources resources = context.getResources();
+ final int resourceId = getResourceId(context);
+ String resourceValue = null;
+ while (System.currentTimeMillis() < endTime) {
+ resourceValue = resources.getString(resourceId);
+ if (Objects.equals(resourceValue, expectedValue)) {
+ return;
+ }
+ }
+ throw new TimeoutException("Timed out waiting for '" + RESOURCE_NAME + "' value to equal '"
+ + expectedValue + "': current value is '" + resourceValue + "'");
+ }
+
+ private static void ensureResourceValueStaysAt(final String expectedValue, Context context) {
+ final long endTime = System.currentTimeMillis() + TIMEOUT_MILLIS;
+ final Resources resources = context.getResources();
+ final int resourceId = getResourceId(context);
+ String resourceValue;
+ while (System.currentTimeMillis() < endTime) {
+ resourceValue = resources.getString(resourceId);
+ assertEquals(expectedValue, resourceValue);
+ }
+ }
+
+ private static int getResourceId(Context context) {
+ return context.getResources().getIdentifier(RESOURCE_NAME, "", context.getPackageName());
+ }
+
private static List<OverlayConstraint>[] getAllConstraintLists() {
return new List[]{
Collections.emptyList(),
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
index 8e2cea7a8c78..6d8a48799112 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -244,9 +244,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
{"Meta + L -> Lock Homescreen", new int[]{META_KEY, KeyEvent.KEYCODE_L},
KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN, KeyEvent.KEYCODE_L,
META_ON},
- {"Meta + Ctrl + N -> Open Notes", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_N},
- KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES, KeyEvent.KEYCODE_N,
- META_ON | CTRL_ON},
{"Meta + Ctrl + DPAD_DOWN -> Enter desktop mode",
new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_DOWN},
KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE,
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
index 32a3b7f2c9cc..22c86eb3a9b8 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
@@ -272,6 +272,19 @@ public class PhoneWindowManagerTests {
}
@Test
+ public void powerPress_withoutDreamManagerInternal_doesNotCrash() {
+ when(mDisplayPolicy.isAwake()).thenReturn(true);
+ mDreamManagerInternal = null;
+ initPhoneWindowManager();
+
+ // Power button pressed.
+ int eventTime = 0;
+ mPhoneWindowManager.powerPress(eventTime, 1, 0);
+
+ // verify no crash
+ }
+
+ @Test
public void powerPress_hubOrDreamOrSleep_hubAvailableLocks() {
when(mDisplayPolicy.isAwake()).thenReturn(true);
mContext.getTestablePermissions().setPermission(android.Manifest.permission.DEVICE_POWER,
@@ -352,5 +365,10 @@ public class PhoneWindowManagerTests {
WindowWakeUpPolicy getWindowWakeUpPolicy() {
return mock(WindowWakeUpPolicy.class);
}
+
+ @Override
+ DreamManagerInternal getDreamManagerInternal() {
+ return mDreamManagerInternal;
+ }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 6923deec1ebb..d53ba1d24d8c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1009,6 +1009,8 @@ public class ActivityRecordTests extends WindowTestsBase {
assertTrue(style.disablePreview());
assertTrue(style.optOutEdgeToEdge());
assertEquals(1 /* icon_preferred */, style.mSplashScreenBehavior);
+ assertEquals(style.noDisplay(), mAtm.mInternal.isNoDisplay(activity.packageName,
+ activity.info.theme, activity.mUserId));
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 59335d3bb135..9406779c929d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -98,6 +98,7 @@ import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.testutils.StubTransaction;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.window.flags.Flags;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -657,6 +658,13 @@ public class SystemServicesTestRule implements TestRule {
AppWarnings appWarnings = getAppWarningsLocked();
spyOn(appWarnings);
doNothing().when(appWarnings).onStartActivity(any());
+
+ if (Flags.trackSystemUiContextBeforeWms()) {
+ final Context uiContext = getUiContext();
+ spyOn(uiContext);
+ doNothing().when(uiContext).registerComponentCallbacks(any());
+ doNothing().when(uiContext).unregisterComponentCallbacks(any());
+ }
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index ccce57a81e41..b1525cf00dc6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -30,6 +30,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -39,6 +40,7 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+import com.android.window.flags.Flags;
class TestDisplayContent extends DisplayContent {
@@ -79,6 +81,13 @@ class TestDisplayContent extends DisplayContent {
WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getPermanentControlTarget());
WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getTransientControlTarget());
+ if (Flags.trackSystemUiContextBeforeWms()) {
+ final Context uiContext = getDisplayUiContext();
+ spyOn(uiContext);
+ doNothing().when(uiContext).registerComponentCallbacks(any());
+ doNothing().when(uiContext).unregisterComponentCallbacks(any());
+ }
+
// For devices that set the sysprop ro.bootanim.set_orientation_<display_id>
// See DisplayRotation#readDefaultDisplayRotation for context.
// Without that, meaning of height and width in context of the tests can be swapped if
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 7f9e591ca5e3..97c6ac6854c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -861,11 +861,9 @@ public class WindowTestsBase extends SystemServiceTestsBase {
/** Creates a {@link DisplayContent} and adds it to the system. */
private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy,
@Nullable SettingsEntry overrideSettings) {
- final DisplayContent display =
- new TestDisplayContent.Builder(mAtm, info)
- .setOverrideSettings(overrideSettings)
- .build();
- final DisplayContent dc = display.mDisplayContent;
+ final DisplayContent dc = new TestDisplayContent.Builder(mAtm, info)
+ .setOverrideSettings(overrideSettings)
+ .build();
// this display can show IME.
dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy);
return dc;
diff --git a/startop/OWNERS b/startop/OWNERS
index 11d5ad0f000a..3414a7469ac2 100644
--- a/startop/OWNERS
+++ b/startop/OWNERS
@@ -1,2 +1 @@
include platform/art:/OWNERS
-keunyoung@google.com
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 1f0bd61b5c3f..168141bf6e7d 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -19,6 +19,9 @@ android_test {
"src/**/*.kt",
],
asset_dirs: ["assets"],
+ kotlincflags: [
+ "-Werror",
+ ],
platform_apis: true,
certificate: "platform",
static_libs: [
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 99c5bad7b2b9..c666fb7e05f1 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -371,18 +371,6 @@ class KeyGestureControllerTests {
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "META + CTRL + N -> Open Notes",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_CTRL_LEFT,
- KeyEvent.KEYCODE_N
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES,
- intArrayOf(KeyEvent.KEYCODE_N),
- KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
"META + S -> Take Screenshot",
intArrayOf(
KeyEvent.KEYCODE_META_LEFT,
diff --git a/tests/SoundTriggerTestApp/OWNERS b/tests/SoundTriggerTestApp/OWNERS
index a0fcfc52704d..1e41886fe716 100644
--- a/tests/SoundTriggerTestApp/OWNERS
+++ b/tests/SoundTriggerTestApp/OWNERS
@@ -1,2 +1 @@
include /media/java/android/media/soundtrigger/OWNERS
-mdooley@google.com
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
index be0c7daebb57..e62a89b17927 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
@@ -19,6 +19,7 @@ package com.android.internal.protolog;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.endsWith;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.times;
@@ -157,13 +158,15 @@ public class ProtoLogCommandHandlerTest {
cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP" });
- Mockito.verify(mProtoLogConfigurationService).enableProtoLogToLogcat("MY_GROUP");
+ Mockito.verify(mProtoLogConfigurationService)
+ .enableProtoLogToLogcat(Mockito.any(), eq("MY_GROUP"));
cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err,
new String[] { "logcat", "enable", "MY_GROUP", "MY_OTHER_GROUP" });
Mockito.verify(mProtoLogConfigurationService)
- .enableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP");
+ .enableProtoLogToLogcat(Mockito.any(),
+ eq("MY_GROUP"), eq("MY_OTHER_GROUP"));
}
@Test
@@ -173,13 +176,15 @@ public class ProtoLogCommandHandlerTest {
cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP" });
- Mockito.verify(mProtoLogConfigurationService).disableProtoLogToLogcat("MY_GROUP");
+ Mockito.verify(mProtoLogConfigurationService)
+ .disableProtoLogToLogcat(Mockito.any(), eq("MY_GROUP"));
cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err,
new String[] { "logcat", "disable", "MY_GROUP", "MY_OTHER_GROUP" });
Mockito.verify(mProtoLogConfigurationService)
- .disableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP");
+ .disableProtoLogToLogcat(Mockito.any(),
+ eq("MY_GROUP"), eq("MY_OTHER_GROUP"));
}
@Test
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
index 3be725101252..1f3f91ebf557 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
@@ -62,6 +62,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.List;
/**
@@ -234,7 +235,7 @@ public class ProtoLogConfigurationServiceTest {
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
- service.enableProtoLogToLogcat(TEST_GROUP);
+ service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
Mockito.verify(mMockClient).toggleLogcat(eq(true),
@@ -251,7 +252,7 @@ public class ProtoLogConfigurationServiceTest {
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
- service.disableProtoLogToLogcat(TEST_GROUP);
+ service.disableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
Mockito.verify(mMockClient).toggleLogcat(eq(false),
@@ -269,7 +270,7 @@ public class ProtoLogConfigurationServiceTest {
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
- service.enableProtoLogToLogcat(OTHER_TEST_GROUP);
+ service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), OTHER_TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
Mockito.verify(mMockClient, never()).toggleLogcat(anyBoolean(), any());
@@ -280,7 +281,7 @@ public class ProtoLogConfigurationServiceTest {
final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
Truth.assertThat(service.getGroups()).asList().doesNotContain(TEST_GROUP);
- service.enableProtoLogToLogcat(TEST_GROUP);
+ service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
final RegisterClientArgs args = new RegisterClientArgs();
diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java
index 1273826c8ef8..8cd89ce89e83 100644
--- a/tests/testables/src/android/testing/TestableLooper.java
+++ b/tests/testables/src/android/testing/TestableLooper.java
@@ -273,7 +273,7 @@ public class TestableLooper {
messages.add(message);
}
- // Repost all Messages back to the queuewith a new time.
+ // Repost all Messages back to the queue with a new time.
while (true) {
Message message = messages.poll();
if (message == null) {