summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--apex/jobscheduler/service/Android.bp4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java32
-rw-r--r--cmds/gpu_counter_producer/main.cpp6
-rw-r--r--core/api/current.txt30
-rw-r--r--core/api/test-current.txt4
-rw-r--r--core/java/Android.bp3
-rw-r--r--core/java/android/app/ActivityThread.java49
-rw-r--r--core/java/android/app/AutomaticZenRule.java338
-rw-r--r--core/java/android/app/LoadedApk.java13
-rw-r--r--core/java/android/app/time/TEST_MAPPING17
-rw-r--r--core/java/android/app/timedetector/TEST_MAPPING7
-rw-r--r--core/java/android/app/timezonedetector/TEST_MAPPING14
-rw-r--r--core/java/android/content/pm/multiuser.aconfig7
-rw-r--r--core/java/android/os/StrictMode.java4
-rw-r--r--core/java/android/provider/Telephony.java9
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java70
-rw-r--r--core/java/android/service/notification/ZenModeDiff.java19
-rw-r--r--core/java/android/service/timezone/TEST_MAPPING4
-rw-r--r--core/java/android/view/ViewRootImpl.java9
-rw-r--r--core/java/android/view/WindowManager.java5
-rw-r--r--core/java/android/view/flags/refresh_rate_flags.aconfig7
-rw-r--r--core/java/android/widget/OWNERS2
-rw-r--r--core/java/com/android/internal/util/FastXmlSerializer.java424
-rw-r--r--core/tests/coretests/src/android/app/AutomaticZenRuleTest.java4
-rw-r--r--core/tests/coretests/src/android/app/time/TEST_MAPPING13
-rw-r--r--core/tests/coretests/src/android/app/timedetector/OWNERS2
-rw-r--r--core/tests/coretests/src/android/app/timedetector/TEST_MAPPING13
-rw-r--r--core/tests/coretests/src/android/app/timezonedetector/OWNERS2
-rw-r--r--core/tests/coretests/src/android/app/timezonedetector/TEST_MAPPING13
-rw-r--r--core/tests/coretests/src/android/service/TEST_MAPPING1
-rw-r--r--core/tests/coretests/src/android/service/timezone/OWNERS2
-rw-r--r--core/tests/coretests/src/android/service/timezone/TEST_MAPPING13
-rw-r--r--core/tests/coretests/src/android/view/ViewRootImplTest.java10
-rw-r--r--core/tests/timetests/Android.bp25
-rw-r--r--core/tests/timetests/AndroidManifest.xml29
-rw-r--r--core/tests/timetests/AndroidTest.xml28
-rw-r--r--core/tests/timetests/OWNERS (renamed from core/tests/coretests/src/android/app/time/OWNERS)0
-rw-r--r--core/tests/timetests/TEST_MAPPING8
-rw-r--r--core/tests/timetests/src/android/app/time/DetectorStatusTypesTest.java (renamed from core/tests/coretests/src/android/app/time/DetectorStatusTypesTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/ExternalTimeSuggestionTest.java (renamed from core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java (renamed from core/tests/coretests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/ParcelableTestSupport.java (renamed from core/tests/coretests/src/android/app/time/ParcelableTestSupport.java)4
-rw-r--r--core/tests/timetests/src/android/app/time/TelephonyTimeZoneAlgorithmStatusTest.java (renamed from core/tests/coretests/src/android/app/time/TelephonyTimeZoneAlgorithmStatusTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/TimeCapabilitiesTest.java (renamed from core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/TimeManagerTest.java (renamed from core/tests/coretests/src/android/app/time/TimeManagerTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/TimeStateTest.java (renamed from core/tests/coretests/src/android/app/time/TimeStateTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/TimeZoneCapabilitiesTest.java (renamed from core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/TimeZoneConfigurationTest.java (renamed from core/tests/coretests/src/android/app/time/TimeZoneConfigurationTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/TimeZoneDetectorStatusTest.java (renamed from core/tests/coretests/src/android/app/time/TimeZoneDetectorStatusTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/TimeZoneStateTest.java (renamed from core/tests/coretests/src/android/app/time/TimeZoneStateTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/time/UnixEpochTimeTest.java (renamed from core/tests/coretests/src/android/app/time/UnixEpochTimeTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/timedetector/ManualTimeSuggestionTest.java (renamed from core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java (renamed from core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java (renamed from core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java)0
-rw-r--r--core/tests/timetests/src/android/app/timezonedetector/ShellCommandTestSupport.java (renamed from core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java)7
-rw-r--r--core/tests/timetests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java (renamed from core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java)0
-rw-r--r--core/tests/timetests/src/android/service/timezone/TimeZoneProviderEventTest.java (renamed from core/tests/coretests/src/android/service/timezone/TimeZoneProviderEventTest.java)0
-rw-r--r--core/tests/timetests/src/android/service/timezone/TimeZoneProviderStatusTest.java (renamed from core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java)7
-rw-r--r--core/tests/timetests/src/android/service/timezone/TimeZoneProviderSuggestionTest.java (renamed from core/tests/coretests/src/android/service/timezone/TimeZoneProviderSuggestionTest.java)0
-rw-r--r--graphics/java/android/graphics/ForceDarkType.java60
-rw-r--r--graphics/java/android/graphics/HardwareRenderer.java12
-rw-r--r--libs/WindowManager/Shell/aconfig/multitasking.aconfig7
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java1
-rw-r--r--libs/hwui/RenderNode.cpp14
-rw-r--r--libs/hwui/RenderNode.h1
-rw-r--r--libs/hwui/TreeInfo.cpp3
-rw-r--r--libs/hwui/TreeInfo.h2
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp11
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp1
-rw-r--r--libs/hwui/renderthread/CanvasContext.h9
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp4
-rw-r--r--libs/hwui/renderthread/RenderProxy.h3
-rw-r--r--libs/hwui/utils/ForceDark.h (renamed from packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/OnMainSwitchChangeListener.java)28
-rw-r--r--packages/CredentialManager/wear/Android.bp1
-rw-r--r--packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt54
-rw-r--r--packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt4
-rw-r--r--packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java30
-rw-r--r--packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java19
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt53
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt31
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt91
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt39
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt123
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java32
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java22
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt95
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt22
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java34
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt84
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java6
-rw-r--r--proto/src/criticalevents/critical_event_log.proto3
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java1
-rw-r--r--services/core/java/com/android/server/am/UserController.java15
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java76
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java239
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java14
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java60
-rw-r--r--services/core/java/com/android/server/audio/SpatializerHelper.java40
-rw-r--r--services/core/java/com/android/server/criticalevents/CriticalEventLog.java8
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java37
-rw-r--r--services/core/java/com/android/server/timedetector/TEST_MAPPING14
-rw-r--r--services/core/java/com/android/server/timezonedetector/TEST_MAPPING13
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java37
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java28
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java48
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java16
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java3
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/tests/servicestests/src/com/android/internal/location/timezone/OWNERS3
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/OWNERS2
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TEST_MAPPING13
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/OWNERS2
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TEST_MAPPING13
-rw-r--r--services/tests/timetests/Android.bp27
-rw-r--r--services/tests/timetests/AndroidManifest.xml32
-rw-r--r--services/tests/timetests/OWNERS (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS)0
-rw-r--r--services/tests/timetests/TEST_MAPPING8
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/ArrayMapWithHistoryTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/ArrayMapWithHistoryTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/ConfigurationInternalTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java)6
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/GnssTimeSuggestionTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/GnssTimeSuggestionTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/NetworkTimeSuggestionTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeSuggestionTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/TimeDetectorServiceTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java (renamed from services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java)6
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java)6
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java)2
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/GeolocationTimeZoneSuggestionTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/GeolocationTimeZoneSuggestionTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/LocationAlgorithmEventTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/LocationAlgorithmEventTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/ShellCommandTestSupport.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/ShellCommandTestSupport.java)7
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java)1
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TestCurrentUserIdentityInjector.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/TestCurrentUserIdentityInjector.java)1
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TestHandler.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/TestHandler.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TestState.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TestStateChangeListener.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/TestStateChangeListener.java)1
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneCanonicalizerTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneCanonicalizerTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java)6
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java)1
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/location/HandlerThreadingDomainTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/location/HandlerThreadingDomainTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/location/TestSupport.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/location/TestThreadingDomain.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/location/TestThreadingDomain.java)0
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java)0
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java133
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java5
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java87
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java15
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java47
-rw-r--r--tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp36
-rw-r--r--tests/inputmethod/ConcurrentMultiSessionImeTest/AndroidManifest.xml23
-rw-r--r--tests/inputmethod/ConcurrentMultiSessionImeTest/AndroidTest.xml43
-rw-r--r--tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java49
-rw-r--r--tests/inputmethod/OWNERS3
216 files changed, 2592 insertions, 1252 deletions
diff --git a/Android.bp b/Android.bp
index 49386d44ede3..895ef98c5537 100644
--- a/Android.bp
+++ b/Android.bp
@@ -399,6 +399,7 @@ java_defaults {
"soundtrigger_middleware-aidl-java",
"modules-utils-binary-xml",
"modules-utils-build",
+ "modules-utils-fastxmlserializer",
"modules-utils-preconditions",
"modules-utils-statemachine",
"modules-utils-synchronous-result-receiver",
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index 887f7fe3a0e2..6c83add3b8e3 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -30,6 +30,10 @@ java_library {
"unsupportedappusage",
],
+ static_libs: [
+ "modules-utils-fastxmlserializer",
+ ],
+
// Rename classes shared with the framework
jarjar_rules: "jarjar-rules.txt",
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 7d3837786be9..12f455ad0144 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2539,6 +2539,38 @@ public class AppStandbyController
pw.println("]");
pw.println();
+ pw.println("mActiveAdminApps=[");
+ synchronized (mActiveAdminApps) {
+ final int size = mActiveAdminApps.size();
+ for (int i = 0; i < size; ++i) {
+ final int userId = mActiveAdminApps.keyAt(i);
+ pw.print(" ");
+ pw.print(userId);
+ pw.print(": ");
+ pw.print(mActiveAdminApps.valueAt(i));
+ if (i != size - 1) pw.print(",");
+ pw.println();
+ }
+ }
+ pw.println("]");
+ pw.println();
+
+ pw.println("mAdminProtectedPackages=[");
+ synchronized (mAdminProtectedPackages) {
+ final int size = mAdminProtectedPackages.size();
+ for (int i = 0; i < size; ++i) {
+ final int userId = mAdminProtectedPackages.keyAt(i);
+ pw.print(" ");
+ pw.print(userId);
+ pw.print(": ");
+ pw.print(mAdminProtectedPackages.valueAt(i));
+ if (i != size - 1) pw.print(",");
+ pw.println();
+ }
+ }
+ pw.println("]");
+ pw.println();
+
mInjector.dump(pw);
}
diff --git a/cmds/gpu_counter_producer/main.cpp b/cmds/gpu_counter_producer/main.cpp
index 1054cba74a6b..4616638379e2 100644
--- a/cmds/gpu_counter_producer/main.cpp
+++ b/cmds/gpu_counter_producer/main.cpp
@@ -133,6 +133,12 @@ int main(int argc, char** argv) {
daemon(0, 0);
}
+ if (getenv("LD_LIBRARY_PATH") == nullptr) {
+ setenv("LD_LIBRARY_PATH", "/vendor/lib64:/vendor/lib", 0 /*override*/);
+ LOG_INFO("execv with: LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
+ execvpe(pname, argv, environ);
+ }
+
if (!writeToPidFile()) {
LOG_ERR("Could not open %s", kPidFileName);
return 1;
diff --git a/core/api/current.txt b/core/api/current.txt
index 87f5b3c1cb3b..14869dba9646 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5315,11 +5315,15 @@ package android.app {
method public android.net.Uri getConditionId();
method @Nullable public android.content.ComponentName getConfigurationActivity();
method public long getCreationTime();
+ method @FlaggedApi("android.app.modes_api") @DrawableRes public int getIconResId();
method public int getInterruptionFilter();
method public String getName();
method public android.content.ComponentName getOwner();
+ method @FlaggedApi("android.app.modes_api") @Nullable public String getTriggerDescription();
+ method @FlaggedApi("android.app.modes_api") public int getType();
method public android.service.notification.ZenPolicy getZenPolicy();
method public boolean isEnabled();
+ method @FlaggedApi("android.app.modes_api") public boolean isManualInvocationAllowed();
method public void setConditionId(android.net.Uri);
method public void setConfigurationActivity(@Nullable android.content.ComponentName);
method public void setEnabled(boolean);
@@ -5328,6 +5332,32 @@ package android.app {
method public void setZenPolicy(android.service.notification.ZenPolicy);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
+ field @FlaggedApi("android.app.modes_api") public static final int TYPE_BEDTIME = 3; // 0x3
+ field @FlaggedApi("android.app.modes_api") public static final int TYPE_DRIVING = 4; // 0x4
+ field @FlaggedApi("android.app.modes_api") public static final int TYPE_IMMERSIVE = 5; // 0x5
+ field @FlaggedApi("android.app.modes_api") public static final int TYPE_MANAGED = 7; // 0x7
+ field @FlaggedApi("android.app.modes_api") public static final int TYPE_OTHER = 0; // 0x0
+ field @FlaggedApi("android.app.modes_api") public static final int TYPE_SCHEDULE_CALENDAR = 2; // 0x2
+ field @FlaggedApi("android.app.modes_api") public static final int TYPE_SCHEDULE_TIME = 1; // 0x1
+ field @FlaggedApi("android.app.modes_api") public static final int TYPE_THEATER = 6; // 0x6
+ field @FlaggedApi("android.app.modes_api") public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ }
+
+ @FlaggedApi("android.app.modes_api") public static final class AutomaticZenRule.Builder {
+ ctor public AutomaticZenRule.Builder(@NonNull android.app.AutomaticZenRule);
+ ctor public AutomaticZenRule.Builder(@NonNull String, @NonNull android.net.Uri);
+ method @NonNull public android.app.AutomaticZenRule build();
+ method @NonNull public android.app.AutomaticZenRule.Builder setConditionId(@NonNull android.net.Uri);
+ method @NonNull public android.app.AutomaticZenRule.Builder setConfigurationActivity(@Nullable android.content.ComponentName);
+ method @NonNull public android.app.AutomaticZenRule.Builder setEnabled(boolean);
+ method @NonNull public android.app.AutomaticZenRule.Builder setIconResId(@DrawableRes int);
+ method @NonNull public android.app.AutomaticZenRule.Builder setInterruptionFilter(int);
+ method @NonNull public android.app.AutomaticZenRule.Builder setManualInvocationAllowed(boolean);
+ method @NonNull public android.app.AutomaticZenRule.Builder setName(@NonNull String);
+ method @NonNull public android.app.AutomaticZenRule.Builder setOwner(@Nullable android.content.ComponentName);
+ method @NonNull public android.app.AutomaticZenRule.Builder setTriggerDescription(@Nullable String);
+ method @NonNull public android.app.AutomaticZenRule.Builder setType(int);
+ method @NonNull public android.app.AutomaticZenRule.Builder setZenPolicy(@Nullable android.service.notification.ZenPolicy);
}
public final class BackgroundServiceStartNotAllowedException extends android.app.ServiceStartNotAllowedException implements android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index b2bfda1daf41..8b20720418b6 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3592,8 +3592,8 @@ package android.view {
field public static final int ACCESSIBILITY_TITLE_CHANGED = 33554432; // 0x2000000
field public static final int FLAG_SLIPPERY = 536870912; // 0x20000000
field public CharSequence accessibilityTitle;
- field @FlaggedApi("android.view.flags.wm_display_refresh_rate_test") public float preferredMaxDisplayRefreshRate;
- field @FlaggedApi("android.view.flags.wm_display_refresh_rate_test") public float preferredMinDisplayRefreshRate;
+ field public float preferredMaxDisplayRefreshRate;
+ field public float preferredMinDisplayRefreshRate;
field public int privateFlags;
}
diff --git a/core/java/Android.bp b/core/java/Android.bp
index ddb221f422d9..48cafc596d87 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -226,7 +226,6 @@ filegroup {
"com/android/internal/util/ConcurrentUtils.java",
"com/android/internal/util/DumpUtils.java",
"com/android/internal/util/FastPrintWriter.java",
- "com/android/internal/util/FastXmlSerializer.java",
"com/android/internal/util/FunctionalUtils.java",
"com/android/internal/util/ParseUtils.java",
"com/android/internal/util/RingBufferIndices.java",
@@ -465,7 +464,6 @@ filegroup {
"com/android/internal/util/AsyncChannel.java",
"com/android/internal/util/AsyncService.java",
"com/android/internal/util/BitwiseInputStream.java",
- "com/android/internal/util/FastXmlSerializer.java",
"com/android/internal/util/HexDump.java",
"com/android/internal/util/IndentingPrintWriter.java",
"com/android/internal/util/UserIcons.java",
@@ -515,7 +513,6 @@ filegroup {
"android/net/InterfaceConfiguration.java",
"android/util/BackupUtils.java",
"android/util/Rational.java",
- "com/android/internal/util/FastXmlSerializer.java",
"com/android/internal/util/HexDump.java",
"com/android/internal/util/MessageUtils.java",
"com/android/internal/util/WakeupMessage.java",
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3b6ea14ab0b6..c136db68fd25 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -378,6 +378,15 @@ public final class ActivityThread extends ClientTransactionHandler
/** Maps from activity token to the pending override configuration. */
@GuardedBy("mPendingOverrideConfigs")
private final ArrayMap<IBinder, Configuration> mPendingOverrideConfigs = new ArrayMap<>();
+
+ /**
+ * A queue of pending ApplicationInfo updates. In case when we get a concurrent update
+ * this queue allows us to only apply the latest object, and it can be applied on demand
+ * instead of waiting for the handler thread to reach the scheduled callback.
+ */
+ @GuardedBy("mResourcesManager")
+ private final ArrayMap<String, ApplicationInfo> mPendingAppInfoUpdates = new ArrayMap<>();
+
/** The activities to be truly destroyed (not include relaunch). */
final Map<IBinder, DestroyActivityItem> mActivitiesToBeDestroyed =
Collections.synchronizedMap(new ArrayMap<>());
@@ -1326,9 +1335,19 @@ public final class ActivityThread extends ClientTransactionHandler
}
public void scheduleApplicationInfoChanged(ApplicationInfo ai) {
+ synchronized (mResourcesManager) {
+ var oldAi = mPendingAppInfoUpdates.put(ai.packageName, ai);
+ if (oldAi != null && oldAi.createTimestamp > ai.createTimestamp) {
+ Slog.w(TAG, "Skipping application info changed for obsolete AI with TS "
+ + ai.createTimestamp + " < already pending TS "
+ + oldAi.createTimestamp);
+ mPendingAppInfoUpdates.put(ai.packageName, oldAi);
+ return;
+ }
+ }
mResourcesManager.appendPendingAppInfoUpdate(new String[]{ai.sourceDir}, ai);
- mH.removeMessages(H.APPLICATION_INFO_CHANGED, ai);
- sendMessage(H.APPLICATION_INFO_CHANGED, ai);
+ mH.removeMessages(H.APPLICATION_INFO_CHANGED, ai.packageName);
+ sendMessage(H.APPLICATION_INFO_CHANGED, ai.packageName);
}
public void updateTimeZone() {
@@ -2507,7 +2526,7 @@ public final class ActivityThread extends ClientTransactionHandler
break;
}
case APPLICATION_INFO_CHANGED:
- handleApplicationInfoChanged((ApplicationInfo) msg.obj);
+ applyPendingApplicationInfoChanges((String) msg.obj);
break;
case RUN_ISOLATED_ENTRY_POINT:
handleRunIsolatedEntryPoint((String) ((SomeArgs) msg.obj).arg1,
@@ -4070,7 +4089,8 @@ public final class ActivityThread extends ClientTransactionHandler
mProfiler.startProfiling();
}
- // Make sure we are running with the most recent config.
+ // Make sure we are running with the most recent config and resource paths.
+ applyPendingApplicationInfoChanges(r.activityInfo.packageName);
mConfigurationController.handleConfigurationChanged(null, null);
updateDeviceIdForNonUIContexts(deviceId);
@@ -6438,6 +6458,17 @@ public final class ActivityThread extends ClientTransactionHandler
r.mLastReportedWindowingMode = newWindowingMode;
}
+ private void applyPendingApplicationInfoChanges(String packageName) {
+ final ApplicationInfo ai;
+ synchronized (mResourcesManager) {
+ ai = mPendingAppInfoUpdates.remove(packageName);
+ }
+ if (ai == null) {
+ return;
+ }
+ handleApplicationInfoChanged(ai);
+ }
+
/**
* Updates the application info.
*
@@ -6463,6 +6494,16 @@ public final class ActivityThread extends ClientTransactionHandler
apk = ref != null ? ref.get() : null;
ref = mResourcePackages.get(ai.packageName);
resApk = ref != null ? ref.get() : null;
+ for (ActivityClientRecord ar : mActivities.values()) {
+ if (ar.activityInfo.applicationInfo.packageName.equals(ai.packageName)) {
+ ar.activityInfo.applicationInfo = ai;
+ if (apk != null || resApk != null) {
+ ar.packageInfo = apk != null ? apk : resApk;
+ } else {
+ apk = ar.packageInfo;
+ }
+ }
+ }
}
if (apk != null) {
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 7bfb1b5c1ba6..919e084002ea 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -16,16 +16,23 @@
package android.app;
+import android.annotation.DrawableRes;
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.NotificationManager.InterruptionFilter;
+import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.notification.Condition;
import android.service.notification.ZenPolicy;
+import android.view.WindowInsetsController;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
@@ -36,7 +43,67 @@ public final class AutomaticZenRule implements Parcelable {
private static final int ENABLED = 1;
/* @hide */
private static final int DISABLED = 0;
- private boolean enabled = false;
+
+ /**
+ * Rule is of an unknown type. This is the default value if not provided by the owning app.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final int TYPE_UNKNOWN = -1;
+ /**
+ * Rule is of a known type, but not one of the specific types.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final int TYPE_OTHER = 0;
+ /**
+ * The type for rules triggered according to a time-based schedule.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final int TYPE_SCHEDULE_TIME = 1;
+ /**
+ * The type for rules triggered by calendar events.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final int TYPE_SCHEDULE_CALENDAR = 2;
+ /**
+ * The type for rules triggered by bedtime/sleeping, like time of day, or snore detection.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final int TYPE_BEDTIME = 3;
+ /**
+ * The type for rules triggered by driving detection, like Bluetooth connections or vehicle
+ * sounds.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final int TYPE_DRIVING = 4;
+ /**
+ * The type for rules triggered by the user entering an immersive activity, like opening an app
+ * using {@link WindowInsetsController#hide(int)}.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final int TYPE_IMMERSIVE = 5;
+ /**
+ * The type for rules that have a {@link ZenPolicy} that implies that the
+ * device should not make sound and potentially hide some visual effects; may be triggered
+ * when entering a location where silence is requested, like a theater.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final int TYPE_THEATER = 6;
+ /**
+ * The type for rules created and managed by a device owner. These rules may not be fully
+ * editable by the device user.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final int TYPE_MANAGED = 7;
+
+ /** @hide */
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_UNKNOWN, TYPE_OTHER, TYPE_SCHEDULE_TIME, TYPE_SCHEDULE_CALENDAR, TYPE_BEDTIME,
+ TYPE_DRIVING, TYPE_IMMERSIVE, TYPE_THEATER, TYPE_MANAGED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ private boolean enabled;
private String name;
private @InterruptionFilter int interruptionFilter;
private Uri conditionId;
@@ -46,6 +113,10 @@ public final class AutomaticZenRule implements Parcelable {
private ZenPolicy mZenPolicy;
private boolean mModified = false;
private String mPkg;
+ private int mType = TYPE_UNKNOWN;
+ private int mIconResId;
+ private String mTriggerDescription;
+ private boolean mAllowManualInvocation;
/**
* The maximum string length for any string contained in this automatic zen rule. This pertains
@@ -55,6 +126,12 @@ public final class AutomaticZenRule implements Parcelable {
public static final int MAX_STRING_LENGTH = 1000;
/**
+ * The maximum string length for the trigger description rule, given UI constraints.
+ * @hide
+ */
+ public static final int MAX_DESC_LENGTH = 150;
+
+ /**
* Creates an automatic zen rule.
*
* @param name The name of the rule.
@@ -97,6 +174,7 @@ public final class AutomaticZenRule implements Parcelable {
* action ({@link Condition#STATE_TRUE}).
* @param enabled Whether the rule is enabled.
*/
+ // TODO (b/309088420): deprecate this constructor in favor of the builder
public AutomaticZenRule(@NonNull String name, @Nullable ComponentName owner,
@Nullable ComponentName configurationActivity, @NonNull Uri conditionId,
@Nullable ZenPolicy policy, int interruptionFilter, boolean enabled) {
@@ -134,6 +212,12 @@ public final class AutomaticZenRule implements Parcelable {
mZenPolicy = source.readParcelable(null, android.service.notification.ZenPolicy.class);
mModified = source.readInt() == ENABLED;
mPkg = source.readString();
+ if (Flags.modesApi()) {
+ mAllowManualInvocation = source.readBoolean();
+ mIconResId = source.readInt();
+ mTriggerDescription = getTrimmedString(source.readString(), MAX_DESC_LENGTH);
+ mType = source.readInt();
+ }
}
/**
@@ -269,6 +353,81 @@ public final class AutomaticZenRule implements Parcelable {
return mPkg;
}
+ /**
+ * Gets the type of the rule.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * Sets the type of the rule.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public void setType(@Type int type) {
+ mType = type;
+ }
+
+ /**
+ * Gets the user visible description of when this rule is active
+ * (see {@link Condition#STATE_TRUE}).
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public @Nullable String getTriggerDescription() {
+ return mTriggerDescription;
+ }
+
+ /**
+ * Sets a user visible description of when this rule will be active
+ * (see {@link Condition#STATE_TRUE}).
+ *
+ * A description should be a (localized) string like "Mon-Fri, 9pm-7am" or
+ * "When connected to [Car Name]".
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public void setTriggerDescription(@Nullable String triggerDescription) {
+ mTriggerDescription = triggerDescription;
+ }
+
+ /**
+ * Gets the resource id of the drawable icon for this rule.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public @DrawableRes int getIconResId() {
+ return mIconResId;
+ }
+
+ /**
+ * Sets a resource id of a tintable vector drawable representing the rule in image form.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public void setIconResId(int iconResId) {
+ mIconResId = iconResId;
+ }
+
+ /**
+ * Gets whether this rule can be manually activated by the user even when the triggering
+ * condition for the rule is not met.
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public boolean isManualInvocationAllowed() {
+ return mAllowManualInvocation;
+ }
+
+ /**
+ * Sets whether this rule can be manually activated by the user even when the triggering
+ * condition for the rule is not met.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public void setManualInvocationAllowed(boolean allowManualInvocation) {
+ mAllowManualInvocation = allowManualInvocation;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -291,11 +450,17 @@ public final class AutomaticZenRule implements Parcelable {
dest.writeParcelable(mZenPolicy, 0);
dest.writeInt(mModified ? ENABLED : DISABLED);
dest.writeString(mPkg);
+ if (Flags.modesApi()) {
+ dest.writeBoolean(mAllowManualInvocation);
+ dest.writeInt(mIconResId);
+ dest.writeString(mTriggerDescription);
+ dest.writeInt(mType);
+ }
}
@Override
public String toString() {
- return new StringBuilder(AutomaticZenRule.class.getSimpleName()).append('[')
+ StringBuilder sb = new StringBuilder(AutomaticZenRule.class.getSimpleName()).append('[')
.append("enabled=").append(enabled)
.append(",name=").append(name)
.append(",interruptionFilter=").append(interruptionFilter)
@@ -304,8 +469,16 @@ public final class AutomaticZenRule implements Parcelable {
.append(",owner=").append(owner)
.append(",configActivity=").append(configurationActivity)
.append(",creationTime=").append(creationTime)
- .append(",mZenPolicy=").append(mZenPolicy)
- .append(']').toString();
+ .append(",mZenPolicy=").append(mZenPolicy);
+
+ if (Flags.modesApi()) {
+ sb.append(",allowManualInvocation=").append(mAllowManualInvocation)
+ .append(",iconResId=").append(mIconResId)
+ .append(",triggerDescription=").append(mTriggerDescription)
+ .append(",type=").append(mType);
+ }
+
+ return sb.append(']').toString();
}
@Override
@@ -313,7 +486,7 @@ public final class AutomaticZenRule implements Parcelable {
if (!(o instanceof AutomaticZenRule)) return false;
if (o == this) return true;
final AutomaticZenRule other = (AutomaticZenRule) o;
- return other.enabled == enabled
+ boolean finalEquals = other.enabled == enabled
&& other.mModified == mModified
&& Objects.equals(other.name, name)
&& other.interruptionFilter == interruptionFilter
@@ -323,10 +496,23 @@ public final class AutomaticZenRule implements Parcelable {
&& Objects.equals(other.configurationActivity, configurationActivity)
&& Objects.equals(other.mPkg, mPkg)
&& other.creationTime == creationTime;
+ if (Flags.modesApi()) {
+ return finalEquals
+ && other.mAllowManualInvocation == mAllowManualInvocation
+ && other.mIconResId == mIconResId
+ && Objects.equals(other.mTriggerDescription, mTriggerDescription)
+ && other.mType == mType;
+ }
+ return finalEquals;
}
@Override
public int hashCode() {
+ if (Flags.modesApi()) {
+ return Objects.hash(enabled, name, interruptionFilter, conditionId, owner,
+ configurationActivity, mZenPolicy, mModified, creationTime, mPkg,
+ mAllowManualInvocation, mIconResId, mTriggerDescription, mType);
+ }
return Objects.hash(enabled, name, interruptionFilter, conditionId, owner,
configurationActivity, mZenPolicy, mModified, creationTime, mPkg);
}
@@ -357,8 +543,12 @@ public final class AutomaticZenRule implements Parcelable {
* Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH.
*/
private static String getTrimmedString(String input) {
- if (input != null && input.length() > MAX_STRING_LENGTH) {
- return input.substring(0, MAX_STRING_LENGTH);
+ return getTrimmedString(input, MAX_STRING_LENGTH);
+ }
+
+ private static String getTrimmedString(String input, int length) {
+ if (input != null && input.length() > length) {
+ return input.substring(0, length);
}
return input;
}
@@ -373,4 +563,138 @@ public final class AutomaticZenRule implements Parcelable {
}
return input;
}
+
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public static final class Builder {
+ private String mName;
+ private ComponentName mOwner;
+ private Uri mConditionId;
+ private int mInterruptionFilter;
+ private boolean mEnabled;
+ private ComponentName mConfigurationActivity = null;
+ private ZenPolicy mPolicy = null;
+ private int mType;
+ private String mDescription;
+ private int mIconResId;
+ private boolean mAllowManualInvocation;
+ private long mCreationTime;
+ private String mPkg;
+
+ public Builder(@NonNull AutomaticZenRule rule) {
+ mName = rule.getName();
+ mOwner = rule.getOwner();
+ mConditionId = rule.getConditionId();
+ mInterruptionFilter = rule.getInterruptionFilter();
+ mEnabled = rule.isEnabled();
+ mConfigurationActivity = rule.getConfigurationActivity();
+ mPolicy = rule.getZenPolicy();
+ mType = rule.getType();
+ mDescription = rule.getTriggerDescription();
+ mIconResId = rule.getIconResId();
+ mAllowManualInvocation = rule.isManualInvocationAllowed();
+ mCreationTime = rule.getCreationTime();
+ mPkg = rule.getPackageName();
+ }
+
+ public Builder(@NonNull String name, @NonNull Uri conditionId) {
+ mName = name;
+ mConditionId = conditionId;
+ }
+
+ public @NonNull Builder setName(@NonNull String name) {
+ mName = name;
+ return this;
+ }
+
+ public @NonNull Builder setOwner(@Nullable ComponentName owner) {
+ mOwner = owner;
+ return this;
+ }
+
+ public @NonNull Builder setConditionId(@NonNull Uri conditionId) {
+ mConditionId = conditionId;
+ return this;
+ }
+
+ public @NonNull Builder setInterruptionFilter(
+ @InterruptionFilter int interruptionFilter) {
+ mInterruptionFilter = interruptionFilter;
+ return this;
+ }
+
+ public @NonNull Builder setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ return this;
+ }
+
+ public @NonNull Builder setConfigurationActivity(
+ @Nullable ComponentName configurationActivity) {
+ mConfigurationActivity = configurationActivity;
+ return this;
+ }
+
+ public @NonNull Builder setZenPolicy(@Nullable ZenPolicy policy) {
+ mPolicy = policy;
+ return this;
+ }
+
+ /**
+ * Sets the type of the rule
+ */
+ public @NonNull Builder setType(@Type int type) {
+ mType = type;
+ return this;
+ }
+
+ /**
+ * Sets a user visible description of when this rule will be active
+ * (see {@link Condition#STATE_TRUE}).
+ *
+ * A description should be a (localized) string like "Mon-Fri, 9pm-7am" or
+ * "When connected to [Car Name]".
+ */
+ public @NonNull Builder setTriggerDescription(@Nullable String description) {
+ mDescription = description;
+ return this;
+ }
+
+ /**
+ * Sets a resource id of a tintable vector drawable representing the rule in image form.
+ */
+ public @NonNull Builder setIconResId(@DrawableRes int iconResId) {
+ mIconResId = iconResId;
+ return this;
+ }
+
+ /**
+ * Sets whether this rule can be manually activated by the user even when the triggering
+ * condition for the rule is not met.
+ */
+ public @NonNull Builder setManualInvocationAllowed(boolean allowManualInvocation) {
+ mAllowManualInvocation = allowManualInvocation;
+ return this;
+ }
+
+ /**
+ * Sets the time at which this rule was created, in milliseconds since epoch
+ * @hide
+ */
+ public @NonNull Builder setCreationTime(long creationTime) {
+ mCreationTime = creationTime;
+ return this;
+ }
+
+ public @NonNull AutomaticZenRule build() {
+ AutomaticZenRule rule = new AutomaticZenRule(mName, mOwner, mConfigurationActivity,
+ mConditionId, mPolicy, mInterruptionFilter, mEnabled);
+ rule.creationTime = mCreationTime;
+ rule.mType = mType;
+ rule.mTriggerDescription = mDescription;
+ rule.mIconResId = mIconResId;
+ rule.mAllowManualInvocation = mAllowManualInvocation;
+ rule.setPackageName(mPkg);
+
+ return rule;
+ }
+ }
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ebf183ff18c3..f1e44cc267d6 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -342,7 +342,9 @@ public final class LoadedApk {
*/
public void updateApplicationInfo(@NonNull ApplicationInfo aInfo,
@Nullable List<String> oldPaths) {
- setApplicationInfo(aInfo);
+ if (!setApplicationInfo(aInfo)) {
+ return;
+ }
final List<String> newPaths = new ArrayList<>();
makePaths(mActivityThread, aInfo, newPaths);
@@ -387,7 +389,13 @@ public final class LoadedApk {
mAppComponentFactory = createAppFactory(aInfo, mDefaultClassLoader);
}
- private void setApplicationInfo(ApplicationInfo aInfo) {
+ private boolean setApplicationInfo(ApplicationInfo aInfo) {
+ if (mApplicationInfo != null && mApplicationInfo.createTimestamp > aInfo.createTimestamp) {
+ Slog.w(TAG, "New application info for package " + aInfo.packageName
+ + " is out of date with TS " + aInfo.createTimestamp + " < the current TS "
+ + mApplicationInfo.createTimestamp);
+ return false;
+ }
final int myUid = Process.myUid();
aInfo = adjustNativeLibraryPaths(aInfo);
mApplicationInfo = aInfo;
@@ -410,6 +418,7 @@ public final class LoadedApk {
if (aInfo.requestsIsolatedSplitLoading() && !ArrayUtils.isEmpty(mSplitNames)) {
mSplitLoader = new SplitDependencyLoaderImpl(aInfo.splitDependencies);
}
+ return true;
}
void setSdkSandboxStorage(@Nullable String sdkSandboxClientAppVolumeUuid,
diff --git a/core/java/android/app/time/TEST_MAPPING b/core/java/android/app/time/TEST_MAPPING
index 780904861f0c..49a4467b1f67 100644
--- a/core/java/android/app/time/TEST_MAPPING
+++ b/core/java/android/app/time/TEST_MAPPING
@@ -1,24 +1,11 @@
{
- "presubmit": [
- {
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.app.time."
- }
- ]
- }
- ],
// TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
"postsubmit": [
{
- "name": "FrameworksCoreTests",
+ "name": "FrameworksTimeCoreTests",
"options": [
{
- "include-filter": "android.app.timedetector."
- },
- {
- "include-filter": "android.app.timezonedetector."
+ "include-filter": "android.app."
}
]
},
diff --git a/core/java/android/app/timedetector/TEST_MAPPING b/core/java/android/app/timedetector/TEST_MAPPING
index 53fd74bc3c3a..c050a55a3e18 100644
--- a/core/java/android/app/timedetector/TEST_MAPPING
+++ b/core/java/android/app/timedetector/TEST_MAPPING
@@ -2,13 +2,10 @@
// TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
"postsubmit": [
{
- "name": "FrameworksCoreTests",
+ "name": "FrameworksTimeCoreTests",
"options": [
{
- "include-filter": "android.app.time."
- },
- {
- "include-filter": "android.app.timedetector."
+ "include-filter": "android.app."
}
]
},
diff --git a/core/java/android/app/timezonedetector/TEST_MAPPING b/core/java/android/app/timezonedetector/TEST_MAPPING
index 5e64c83937f6..46656d125b70 100644
--- a/core/java/android/app/timezonedetector/TEST_MAPPING
+++ b/core/java/android/app/timezonedetector/TEST_MAPPING
@@ -1,21 +1,11 @@
{
- "presubmit": [
- {
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.app.timezonedetector."
- }
- ]
- }
- ],
// TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
"postsubmit": [
{
- "name": "FrameworksCoreTests",
+ "name": "FrameworksTimeCoreTests",
"options": [
{
- "include-filter": "android.app.time."
+ "include-filter": "android.app."
}
]
},
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 43cf97fd2090..9ec082ab8eea 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -35,3 +35,10 @@ flag {
description: "Further framework support for communal profile, beyond the basics, for later releases."
bug: "285426179"
}
+
+flag {
+ name: "use_all_cpus_during_user_switch"
+ namespace: "multiuser"
+ description: "Allow using all cpu cores during a user switch."
+ bug: "308105403"
+}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 47b6d8d6db30..94f90ccb2d9d 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -2018,9 +2018,13 @@ public final class StrictMode {
return;
}
+ // Temporarily disable checks so that explicit GC is allowed.
+ final int oldMask = getThreadPolicyMask();
+ setThreadPolicyMask(0);
System.gc();
System.runFinalization();
System.gc();
+ setThreadPolicyMask(oldMask);
// Note: classInstanceLimit is immutable, so this is lock-free
// Create the classes array.
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 27ad45de69e6..bcda25a1bf3b 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3206,6 +3206,15 @@ public final class Telephony {
public static final String INFRASTRUCTURE_BITMASK = "infrastructure_bitmask";
/**
+ * Indicating if the APN is used for eSIM bootsrap provisioning. The default value is 0 (Not
+ * used for eSIM bootstrap provisioning).
+ *
+ * <P>Type: INTEGER</P>
+ * @hide
+ */
+ public static final String ESIM_BOOTSTRAP_PROVISIONING = "esim_bootstrap_provisioning";
+
+ /**
* MVNO type:
* {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
* <P>Type: TEXT</P>
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 828c062d955d..ff4dfc7cc079 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -28,6 +28,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OF
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlarmManager;
+import android.app.AutomaticZenRule;
+import android.app.Flags;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.compat.annotation.UnsupportedAppUsage;
@@ -177,6 +179,10 @@ public class ZenModeConfig implements Parcelable {
private static final String RULE_ATT_CREATION_TIME = "creationTime";
private static final String RULE_ATT_ENABLER = "enabler";
private static final String RULE_ATT_MODIFIED = "modified";
+ private static final String RULE_ATT_ALLOW_MANUAL = "userInvokable";
+ private static final String RULE_ATT_TYPE = "type";
+ private static final String RULE_ATT_ICON = "rule_icon";
+ private static final String RULE_ATT_TRIGGER_DESC = "triggerDesc";
@UnsupportedAppUsage
public boolean allowAlarms = DEFAULT_ALLOW_ALARMS;
@@ -212,7 +218,7 @@ public class ZenModeConfig implements Parcelable {
allowCallsFrom = source.readInt();
allowMessagesFrom = source.readInt();
user = source.readInt();
- manualRule = source.readParcelable(null, android.service.notification.ZenModeConfig.ZenRule.class);
+ manualRule = source.readParcelable(null, ZenRule.class);
final int len = source.readInt();
if (len > 0) {
final String[] ids = new String[len];
@@ -622,6 +628,12 @@ public class ZenModeConfig implements Parcelable {
}
rt.modified = safeBoolean(parser, RULE_ATT_MODIFIED, false);
rt.zenPolicy = readZenPolicyXml(parser);
+ if (Flags.modesApi()) {
+ rt.allowManualInvocation = safeBoolean(parser, RULE_ATT_ALLOW_MANUAL, false);
+ rt.iconResId = safeInt(parser, RULE_ATT_ICON, 0);
+ rt.triggerDescription = parser.getAttributeValue(null, RULE_ATT_TRIGGER_DESC);
+ rt.type = safeInt(parser, RULE_ATT_TYPE, AutomaticZenRule.TYPE_UNKNOWN);
+ }
return rt;
}
@@ -655,6 +667,14 @@ public class ZenModeConfig implements Parcelable {
writeZenPolicyXml(rule.zenPolicy, out);
}
out.attributeBoolean(null, RULE_ATT_MODIFIED, rule.modified);
+ if (Flags.modesApi()) {
+ out.attributeBoolean(null, RULE_ATT_ALLOW_MANUAL, rule.allowManualInvocation);
+ out.attributeInt(null, RULE_ATT_ICON, rule.iconResId);
+ if (rule.triggerDescription != null) {
+ out.attribute(null, RULE_ATT_TRIGGER_DESC, rule.triggerDescription);
+ }
+ out.attributeInt(null, RULE_ATT_TYPE, rule.type);
+ }
}
public static Condition readConditionXml(TypedXmlPullParser parser) {
@@ -1726,6 +1746,11 @@ public class ZenModeConfig implements Parcelable {
public ZenPolicy zenPolicy;
public boolean modified; // rule has been modified from initial creation
public String pkg;
+ public int type = AutomaticZenRule.TYPE_UNKNOWN;
+ public String triggerDescription;
+ // TODO (b/308672670): switch to string res name
+ public int iconResId;
+ public boolean allowManualInvocation;
public ZenRule() { }
@@ -1750,6 +1775,12 @@ public class ZenModeConfig implements Parcelable {
zenPolicy = source.readParcelable(null, android.service.notification.ZenPolicy.class);
modified = source.readInt() == 1;
pkg = source.readString();
+ if (Flags.modesApi()) {
+ allowManualInvocation = source.readBoolean();
+ iconResId = source.readInt();
+ triggerDescription = source.readString();
+ type = source.readInt();
+ }
}
@Override
@@ -1788,11 +1819,17 @@ public class ZenModeConfig implements Parcelable {
dest.writeParcelable(zenPolicy, 0);
dest.writeInt(modified ? 1 : 0);
dest.writeString(pkg);
+ if (Flags.modesApi()) {
+ dest.writeBoolean(allowManualInvocation);
+ dest.writeInt(iconResId);
+ dest.writeString(triggerDescription);
+ dest.writeInt(type);
+ }
}
@Override
public String toString() {
- return new StringBuilder(ZenRule.class.getSimpleName()).append('[')
+ StringBuilder sb = new StringBuilder(ZenRule.class.getSimpleName()).append('[')
.append("id=").append(id)
.append(",state=").append(condition == null ? "STATE_FALSE"
: Condition.stateToString(condition.state))
@@ -1808,8 +1845,16 @@ public class ZenModeConfig implements Parcelable {
.append(",enabler=").append(enabler)
.append(",zenPolicy=").append(zenPolicy)
.append(",modified=").append(modified)
- .append(",condition=").append(condition)
- .append(']').toString();
+ .append(",condition=").append(condition);
+
+ if (Flags.modesApi()) {
+ sb.append(",allowManualInvocation=").append(allowManualInvocation)
+ .append(",iconResId=").append(iconResId)
+ .append(",triggerDescription=").append(triggerDescription)
+ .append(",type=").append(type);
+ }
+
+ return sb.append(']').toString();
}
/** @hide */
@@ -1845,7 +1890,7 @@ public class ZenModeConfig implements Parcelable {
if (!(o instanceof ZenRule)) return false;
if (o == this) return true;
final ZenRule other = (ZenRule) o;
- return other.enabled == enabled
+ boolean finalEquals = other.enabled == enabled
&& other.snoozing == snoozing
&& Objects.equals(other.name, name)
&& other.zenMode == zenMode
@@ -1858,10 +1903,25 @@ public class ZenModeConfig implements Parcelable {
&& Objects.equals(other.zenPolicy, zenPolicy)
&& Objects.equals(other.pkg, pkg)
&& other.modified == modified;
+
+ if (Flags.modesApi()) {
+ return finalEquals
+ && other.allowManualInvocation == allowManualInvocation
+ && other.iconResId == iconResId
+ && Objects.equals(other.triggerDescription, triggerDescription)
+ && other.type == type;
+ }
+
+ return finalEquals;
}
@Override
public int hashCode() {
+ if (Flags.modesApi()) {
+ return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
+ component, configurationActivity, pkg, id, enabler, zenPolicy, modified,
+ allowManualInvocation, iconResId, triggerDescription, type);
+ }
return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
component, configurationActivity, pkg, id, enabler, zenPolicy, modified);
}
diff --git a/core/java/android/service/notification/ZenModeDiff.java b/core/java/android/service/notification/ZenModeDiff.java
index a4f129ec247e..eb55e40f2c7b 100644
--- a/core/java/android/service/notification/ZenModeDiff.java
+++ b/core/java/android/service/notification/ZenModeDiff.java
@@ -454,6 +454,11 @@ public class ZenModeDiff {
public static final String FIELD_ZEN_POLICY = "zenPolicy";
public static final String FIELD_MODIFIED = "modified";
public static final String FIELD_PKG = "pkg";
+ public static final String FIELD_ALLOW_MANUAL = "allowManualInvocation";
+ public static final String FIELD_ICON_RES = "iconResId";
+ public static final String FIELD_TRIGGER = "triggerDescription";
+ public static final String FIELD_TYPE = "type";
+ // NOTE: new field strings must match the variable names in ZenModeConfig.ZenRule
// Special field to track whether this rule became active or inactive
FieldDiff<Boolean> mActiveDiff;
@@ -529,6 +534,20 @@ public class ZenModeDiff {
if (!Objects.equals(from.pkg, to.pkg)) {
addField(FIELD_PKG, new FieldDiff<>(from.pkg, to.pkg));
}
+ if (!Objects.equals(from.triggerDescription, to.triggerDescription)) {
+ addField(FIELD_TRIGGER,
+ new FieldDiff<>(from.triggerDescription, to.triggerDescription));
+ }
+ if (from.type != to.type) {
+ addField(FIELD_TYPE, new FieldDiff<>(from.type, to.type));
+ }
+ if (from.allowManualInvocation != to.allowManualInvocation) {
+ addField(FIELD_ALLOW_MANUAL,
+ new FieldDiff<>(from.allowManualInvocation, to.allowManualInvocation));
+ }
+ if (!Objects.equals(from.iconResId, to.iconResId)) {
+ addField(FIELD_ICON_RES, new FieldDiff(from.iconResId, to.iconResId));
+ }
}
/**
diff --git a/core/java/android/service/timezone/TEST_MAPPING b/core/java/android/service/timezone/TEST_MAPPING
index b0ce1dba3509..21a8eab19837 100644
--- a/core/java/android/service/timezone/TEST_MAPPING
+++ b/core/java/android/service/timezone/TEST_MAPPING
@@ -2,10 +2,10 @@
// TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
"postsubmit": [
{
- "name": "FrameworksCoreTests",
+ "name": "FrameworksTimeCoreTests",
"options": [
{
- "include-filter": "android.service.timezone."
+ "include-filter": "android.service."
}
]
},
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c9c1f20d2f37..d97dfb0f9c94 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -123,6 +123,7 @@ import android.content.res.TypedArray;
import android.graphics.BLASTBufferQueue;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ForceDarkType;
import android.graphics.FrameInfo;
import android.graphics.HardwareRenderer;
import android.graphics.HardwareRenderer.FrameDrawingCallback;
@@ -1796,7 +1797,7 @@ public final class ViewRootImpl implements ViewParent,
/** Returns true if force dark should be enabled according to various settings */
@VisibleForTesting
- public boolean isForceDarkEnabled() {
+ public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() {
if (forceInvertColor()) {
boolean isForceInvertEnabled = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
@@ -1808,7 +1809,7 @@ public final class ViewRootImpl implements ViewParent,
// 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 true;
+ return ForceDarkType.FORCE_INVERT_COLOR_DARK;
}
}
@@ -1822,12 +1823,12 @@ public final class ViewRootImpl implements ViewParent,
&& a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);
a.recycle();
}
- return useAutoDark;
+ return useAutoDark ? ForceDarkType.FORCE_DARK : ForceDarkType.NONE;
}
private void updateForceDarkMode() {
if (mAttachInfo.mThreadedRenderer == null) return;
- if (mAttachInfo.mThreadedRenderer.setForceDark(isForceDarkEnabled())) {
+ if (mAttachInfo.mThreadedRenderer.setForceDark(determineForceDarkType())) {
// TODO: Don't require regenerating all display lists to apply this setting
invalidateWorld(mView);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index cfec08120776..c73514250e3b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -17,7 +17,6 @@
package android.view;
import static android.content.pm.ActivityInfo.COLOR_MODE_DEFAULT;
-import static android.view.flags.Flags.FLAG_WM_DISPLAY_REFRESH_RATE_TEST;
import static android.view.View.STATUS_BAR_DISABLE_BACK;
import static android.view.View.STATUS_BAR_DISABLE_CLOCK;
import static android.view.View.STATUS_BAR_DISABLE_EXPAND;
@@ -3907,7 +3906,7 @@ public interface WindowManager extends ViewManager {
* This value is ignored if {@link #preferredDisplayModeId} is set.
* @hide
*/
- @FlaggedApi(FLAG_WM_DISPLAY_REFRESH_RATE_TEST)
+ @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
@TestApi
public float preferredMinDisplayRefreshRate;
@@ -3917,7 +3916,7 @@ public interface WindowManager extends ViewManager {
* This value is ignored if {@link #preferredDisplayModeId} is set.
* @hide
*/
- @FlaggedApi(FLAG_WM_DISPLAY_REFRESH_RATE_TEST)
+ @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
@TestApi
public float preferredMaxDisplayRefreshRate;
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index cc951cf46870..a467afe5d06a 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -42,11 +42,4 @@ flag {
namespace: "core_graphics"
description: "Enable the `setFrameRate` callback"
bug: "299946220"
-}
-
-flag {
- name: "wm_display_refresh_rate_test"
- namespace: "core_graphics"
- description: "Adds WindowManager display refresh rate fields to test API"
- bug: "304475199"
} \ No newline at end of file
diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS
index 7f0a651c6420..e20357fa2dd9 100644
--- a/core/java/android/widget/OWNERS
+++ b/core/java/android/widget/OWNERS
@@ -12,6 +12,6 @@ per-file TextView*,Edit*,Selection* = file:../text/OWNERS
per-file SpellChecker.java = file:../view/inputmethod/OWNERS
-per-file RemoteViews* = file:../appwidget/OWNERS
+per-file Remote* = file:../appwidget/OWNERS
per-file Toast.java = juliacr@google.com, jeffdq@google.com
diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
deleted file mode 100644
index 929c9e8bb8c1..000000000000
--- a/core/java/com/android/internal/util/FastXmlSerializer.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import android.compat.annotation.UnsupportedAppUsage;
-
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
-
-/**
- * This is a quick and dirty implementation of XmlSerializer that isn't horribly
- * painfully slow like the normal one. It only does what is needed for the
- * specific XML files being written with it.
- */
-public class FastXmlSerializer implements XmlSerializer {
- private static final String ESCAPE_TABLE[] = new String[] {
- "&#0;", "&#1;", "&#2;", "&#3;", "&#4;", "&#5;", "&#6;", "&#7;", // 0-7
- "&#8;", "&#9;", "&#10;", "&#11;", "&#12;", "&#13;", "&#14;", "&#15;", // 8-15
- "&#16;", "&#17;", "&#18;", "&#19;", "&#20;", "&#21;", "&#22;", "&#23;", // 16-23
- "&#24;", "&#25;", "&#26;", "&#27;", "&#28;", "&#29;", "&#30;", "&#31;", // 24-31
- null, null, "&quot;", null, null, null, "&amp;", null, // 32-39
- null, null, null, null, null, null, null, null, // 40-47
- null, null, null, null, null, null, null, null, // 48-55
- null, null, null, null, "&lt;", null, "&gt;", null, // 56-63
- };
-
- private static final int DEFAULT_BUFFER_LEN = 32*1024;
-
- private static String sSpace = " ";
-
- private final int mBufferLen;
- private final char[] mText;
- private int mPos;
-
- private Writer mWriter;
-
- private OutputStream mOutputStream;
- private CharsetEncoder mCharset;
- private ByteBuffer mBytes;
-
- private boolean mIndent = false;
- private boolean mInTag;
-
- private int mNesting = 0;
- private boolean mLineStart = true;
-
- @UnsupportedAppUsage
- public FastXmlSerializer() {
- this(DEFAULT_BUFFER_LEN);
- }
-
- /**
- * Allocate a FastXmlSerializer with the given internal output buffer size. If the
- * size is zero or negative, then the default buffer size will be used.
- *
- * @param bufferSize Size in bytes of the in-memory output buffer that the writer will use.
- */
- public FastXmlSerializer(int bufferSize) {
- mBufferLen = (bufferSize > 0) ? bufferSize : DEFAULT_BUFFER_LEN;
- mText = new char[mBufferLen];
- mBytes = ByteBuffer.allocate(mBufferLen);
- }
-
- private void append(char c) throws IOException {
- int pos = mPos;
- if (pos >= (mBufferLen-1)) {
- flush();
- pos = mPos;
- }
- mText[pos] = c;
- mPos = pos+1;
- }
-
- private void append(String str, int i, final int length) throws IOException {
- if (length > mBufferLen) {
- final int end = i + length;
- while (i < end) {
- int next = i + mBufferLen;
- append(str, i, next<end ? mBufferLen : (end-i));
- i = next;
- }
- return;
- }
- int pos = mPos;
- if ((pos+length) > mBufferLen) {
- flush();
- pos = mPos;
- }
- str.getChars(i, i+length, mText, pos);
- mPos = pos + length;
- }
-
- private void append(char[] buf, int i, final int length) throws IOException {
- if (length > mBufferLen) {
- final int end = i + length;
- while (i < end) {
- int next = i + mBufferLen;
- append(buf, i, next<end ? mBufferLen : (end-i));
- i = next;
- }
- return;
- }
- int pos = mPos;
- if ((pos+length) > mBufferLen) {
- flush();
- pos = mPos;
- }
- System.arraycopy(buf, i, mText, pos, length);
- mPos = pos + length;
- }
-
- private void append(String str) throws IOException {
- append(str, 0, str.length());
- }
-
- private void appendIndent(int indent) throws IOException {
- indent *= 4;
- if (indent > sSpace.length()) {
- indent = sSpace.length();
- }
- append(sSpace, 0, indent);
- }
-
- private void escapeAndAppendString(final String string) throws IOException {
- final int N = string.length();
- final char NE = (char)ESCAPE_TABLE.length;
- final String[] escapes = ESCAPE_TABLE;
- int lastPos = 0;
- int pos;
- for (pos=0; pos<N; pos++) {
- char c = string.charAt(pos);
- if (c >= NE) continue;
- String escape = escapes[c];
- if (escape == null) continue;
- if (lastPos < pos) append(string, lastPos, pos-lastPos);
- lastPos = pos + 1;
- append(escape);
- }
- if (lastPos < pos) append(string, lastPos, pos-lastPos);
- }
-
- private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {
- final char NE = (char)ESCAPE_TABLE.length;
- final String[] escapes = ESCAPE_TABLE;
- int end = start+len;
- int lastPos = start;
- int pos;
- for (pos=start; pos<end; pos++) {
- char c = buf[pos];
- if (c >= NE) continue;
- String escape = escapes[c];
- if (escape == null) continue;
- if (lastPos < pos) append(buf, lastPos, pos-lastPos);
- lastPos = pos + 1;
- append(escape);
- }
- if (lastPos < pos) append(buf, lastPos, pos-lastPos);
- }
-
- public XmlSerializer attribute(String namespace, String name, String value) throws IOException,
- IllegalArgumentException, IllegalStateException {
- append(' ');
- if (namespace != null) {
- append(namespace);
- append(':');
- }
- append(name);
- append("=\"");
-
- escapeAndAppendString(value);
- append('"');
- mLineStart = false;
- return this;
- }
-
- public void cdsect(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void comment(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void docdecl(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {
- flush();
- }
-
- public XmlSerializer endTag(String namespace, String name) throws IOException,
- IllegalArgumentException, IllegalStateException {
- mNesting--;
- if (mInTag) {
- append(" />\n");
- } else {
- if (mIndent && mLineStart) {
- appendIndent(mNesting);
- }
- append("</");
- if (namespace != null) {
- append(namespace);
- append(':');
- }
- append(name);
- append(">\n");
- }
- mLineStart = true;
- mInTag = false;
- return this;
- }
-
- public void entityRef(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- private void flushBytes() throws IOException {
- int position;
- if ((position = mBytes.position()) > 0) {
- mBytes.flip();
- mOutputStream.write(mBytes.array(), 0, position);
- mBytes.clear();
- }
- }
-
- public void flush() throws IOException {
- //Log.i("PackageManager", "flush mPos=" + mPos);
- if (mPos > 0) {
- if (mOutputStream != null) {
- CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);
- CoderResult result = mCharset.encode(charBuffer, mBytes, true);
- while (true) {
- if (result.isError()) {
- throw new IOException(result.toString());
- } else if (result.isOverflow()) {
- flushBytes();
- result = mCharset.encode(charBuffer, mBytes, true);
- continue;
- }
- break;
- }
- flushBytes();
- mOutputStream.flush();
- } else {
- mWriter.write(mText, 0, mPos);
- mWriter.flush();
- }
- mPos = 0;
- }
- }
-
- public int getDepth() {
- throw new UnsupportedOperationException();
- }
-
- public boolean getFeature(String name) {
- throw new UnsupportedOperationException();
- }
-
- public String getName() {
- throw new UnsupportedOperationException();
- }
-
- public String getNamespace() {
- throw new UnsupportedOperationException();
- }
-
- public String getPrefix(String namespace, boolean generatePrefix)
- throws IllegalArgumentException {
- throw new UnsupportedOperationException();
- }
-
- public Object getProperty(String name) {
- throw new UnsupportedOperationException();
- }
-
- public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void processingInstruction(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void setFeature(String name, boolean state) throws IllegalArgumentException,
- IllegalStateException {
- if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
- mIndent = true;
- return;
- }
- throw new UnsupportedOperationException();
- }
-
- public void setOutput(OutputStream os, String encoding) throws IOException,
- IllegalArgumentException, IllegalStateException {
- if (os == null)
- throw new IllegalArgumentException();
- if (true) {
- try {
- mCharset = Charset.forName(encoding).newEncoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- } catch (IllegalCharsetNameException e) {
- throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
- encoding).initCause(e));
- } catch (UnsupportedCharsetException e) {
- throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
- encoding).initCause(e));
- }
- mOutputStream = os;
- } else {
- setOutput(
- encoding == null
- ? new OutputStreamWriter(os)
- : new OutputStreamWriter(os, encoding));
- }
- }
-
- public void setOutput(Writer writer) throws IOException, IllegalArgumentException,
- IllegalStateException {
- mWriter = writer;
- }
-
- public void setPrefix(String prefix, String namespace) throws IOException,
- IllegalArgumentException, IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void setProperty(String name, Object value) throws IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void startDocument(String encoding, Boolean standalone) throws IOException,
- IllegalArgumentException, IllegalStateException {
- append("<?xml version='1.0' encoding='utf-8'");
- if (standalone != null) {
- append(" standalone='" + (standalone ? "yes" : "no") + "'");
- }
- append(" ?>\n");
- mLineStart = true;
- }
-
- public XmlSerializer startTag(String namespace, String name) throws IOException,
- IllegalArgumentException, IllegalStateException {
- if (mInTag) {
- append(">\n");
- }
- if (mIndent) {
- appendIndent(mNesting);
- }
- mNesting++;
- append('<');
- if (namespace != null) {
- append(namespace);
- append(':');
- }
- append(name);
- mInTag = true;
- mLineStart = false;
- return this;
- }
-
- public XmlSerializer text(char[] buf, int start, int len) throws IOException,
- IllegalArgumentException, IllegalStateException {
- if (mInTag) {
- append(">");
- mInTag = false;
- }
- escapeAndAppendString(buf, start, len);
- if (mIndent) {
- mLineStart = buf[start+len-1] == '\n';
- }
- return this;
- }
-
- public XmlSerializer text(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- if (mInTag) {
- append(">");
- mInTag = false;
- }
- escapeAndAppendString(text);
- if (mIndent) {
- mLineStart = text.length() > 0 && (text.charAt(text.length()-1) == '\n');
- }
- return this;
- }
-
-}
diff --git a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
index 282fdad294eb..ba2ea88e8e01 100644
--- a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
+++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
@@ -125,6 +125,9 @@ public class AutomaticZenRuleTest {
Field configActivity = Class.forName(CLASS).getDeclaredField("configurationActivity");
configActivity.setAccessible(true);
configActivity.set(rule, new ComponentName(longString, longString));
+ Field trigger = Class.forName(CLASS).getDeclaredField("mTriggerDescription");
+ trigger.setAccessible(true);
+ trigger.set(rule, longString);
} catch (NoSuchFieldException e) {
fail(e.toString());
} catch (ClassNotFoundException e) {
@@ -149,5 +152,6 @@ public class AutomaticZenRuleTest {
fromParcel.getOwner().getPackageName().length());
assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
fromParcel.getOwner().getClassName().length());
+ assertEquals(AutomaticZenRule.MAX_DESC_LENGTH, rule.getTriggerDescription().length());
}
}
diff --git a/core/tests/coretests/src/android/app/time/TEST_MAPPING b/core/tests/coretests/src/android/app/time/TEST_MAPPING
deleted file mode 100644
index 9d711a271642..000000000000
--- a/core/tests/coretests/src/android/app/time/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
- "postsubmit": [
- {
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.app.time."
- }
- ]
- }
- ]
-}
diff --git a/core/tests/coretests/src/android/app/timedetector/OWNERS b/core/tests/coretests/src/android/app/timedetector/OWNERS
deleted file mode 100644
index c6124734bc5c..000000000000
--- a/core/tests/coretests/src/android/app/timedetector/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 847766
-include /core/java/android/app/timedetector/OWNERS
diff --git a/core/tests/coretests/src/android/app/timedetector/TEST_MAPPING b/core/tests/coretests/src/android/app/timedetector/TEST_MAPPING
deleted file mode 100644
index 6c4d48de30a3..000000000000
--- a/core/tests/coretests/src/android/app/timedetector/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
- "postsubmit": [
- {
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.app.timedetector."
- }
- ]
- }
- ]
-}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/OWNERS b/core/tests/coretests/src/android/app/timezonedetector/OWNERS
deleted file mode 100644
index 2e9c3246e4fc..000000000000
--- a/core/tests/coretests/src/android/app/timezonedetector/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 847766
-include /core/java/android/app/timezonedetector/OWNERS
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TEST_MAPPING b/core/tests/coretests/src/android/app/timezonedetector/TEST_MAPPING
deleted file mode 100644
index 8872f642f604..000000000000
--- a/core/tests/coretests/src/android/app/timezonedetector/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
- "postsubmit": [
- {
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.app.timezonedetector."
- }
- ]
- }
- ]
-}
diff --git a/core/tests/coretests/src/android/service/TEST_MAPPING b/core/tests/coretests/src/android/service/TEST_MAPPING
index 7ebda0062335..bec72d988e74 100644
--- a/core/tests/coretests/src/android/service/TEST_MAPPING
+++ b/core/tests/coretests/src/android/service/TEST_MAPPING
@@ -10,7 +10,6 @@
{"include-filter": "android.service.notification"},
{"include-filter": "android.service.quicksettings"},
{"include-filter": "android.service.settings.suggestions"},
- {"include-filter": "android.service.timezone"},
{"exclude-annotation": "org.junit.Ignore"}
]
}
diff --git a/core/tests/coretests/src/android/service/timezone/OWNERS b/core/tests/coretests/src/android/service/timezone/OWNERS
deleted file mode 100644
index 811638805996..000000000000
--- a/core/tests/coretests/src/android/service/timezone/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 847766
-include /core/java/android/service/timezone/OWNERS
diff --git a/core/tests/coretests/src/android/service/timezone/TEST_MAPPING b/core/tests/coretests/src/android/service/timezone/TEST_MAPPING
deleted file mode 100644
index 46f476f43861..000000000000
--- a/core/tests/coretests/src/android/service/timezone/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
- "postsubmit": [
- {
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.service.timezone."
- }
- ]
- }
- ]
-}
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index e7117a7da0e9..dfe6cf81813d 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -49,6 +49,7 @@ import static org.junit.Assume.assumeTrue;
import android.app.Instrumentation;
import android.app.UiModeManager;
import android.content.Context;
+import android.graphics.ForceDarkType;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
import android.os.SystemProperties;
@@ -593,7 +594,7 @@ public class ViewRootImplTest {
mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
);
- assertThat(mViewRootImpl.isForceDarkEnabled()).isFalse();
+ assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.NONE);
}
@Test
@@ -613,7 +614,8 @@ public class ViewRootImplTest {
mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
);
- assertThat(mViewRootImpl.isForceDarkEnabled()).isTrue();
+ assertThat(mViewRootImpl.determineForceDarkType())
+ .isEqualTo(ForceDarkType.FORCE_INVERT_COLOR_DARK);
}
@Test
@@ -634,7 +636,7 @@ public class ViewRootImplTest {
mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
);
- assertThat(mViewRootImpl.isForceDarkEnabled()).isFalse();
+ assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.NONE);
}
@Test
@@ -654,7 +656,7 @@ public class ViewRootImplTest {
mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
);
- assertThat(mViewRootImpl.isForceDarkEnabled()).isTrue();
+ assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.FORCE_DARK);
}
private boolean setForceDarkSysProp(boolean isForceDarkEnabled) {
diff --git a/core/tests/timetests/Android.bp b/core/tests/timetests/Android.bp
new file mode 100644
index 000000000000..51181a8a7b13
--- /dev/null
+++ b/core/tests/timetests/Android.bp
@@ -0,0 +1,25 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FrameworksTimeCoreTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "device-time-shell-utils",
+ "junit",
+ "junit-params",
+ "mockito-target-minus-junit4",
+ "platform-test-annotations",
+ "truth",
+ ],
+ libs: ["android.test.runner"],
+ certificate: "platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/timetests/AndroidManifest.xml b/core/tests/timetests/AndroidManifest.xml
new file mode 100644
index 000000000000..330e05fb407d
--- /dev/null
+++ b/core/tests/timetests/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.time">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.coretests.time"
+ android:label="Frameworks Time Core Tests" />
+
+</manifest>
diff --git a/core/tests/timetests/AndroidTest.xml b/core/tests/timetests/AndroidTest.xml
new file mode 100644
index 000000000000..d2d1255768d8
--- /dev/null
+++ b/core/tests/timetests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Time Core Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="FrameworksTimeCoreTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.coretests.time" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/core/tests/coretests/src/android/app/time/OWNERS b/core/tests/timetests/OWNERS
index 292cb72f2dbe..292cb72f2dbe 100644
--- a/core/tests/coretests/src/android/app/time/OWNERS
+++ b/core/tests/timetests/OWNERS
diff --git a/core/tests/timetests/TEST_MAPPING b/core/tests/timetests/TEST_MAPPING
new file mode 100644
index 000000000000..57480445a7b0
--- /dev/null
+++ b/core/tests/timetests/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+ // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
+ "postsubmit": [
+ {
+ "name": "FrameworksTimeCoreTests"
+ }
+ ]
+}
diff --git a/core/tests/coretests/src/android/app/time/DetectorStatusTypesTest.java b/core/tests/timetests/src/android/app/time/DetectorStatusTypesTest.java
index 2e1e09c14d5e..2e1e09c14d5e 100644
--- a/core/tests/coretests/src/android/app/time/DetectorStatusTypesTest.java
+++ b/core/tests/timetests/src/android/app/time/DetectorStatusTypesTest.java
diff --git a/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java b/core/tests/timetests/src/android/app/time/ExternalTimeSuggestionTest.java
index ae3357a75fd1..ae3357a75fd1 100644
--- a/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
+++ b/core/tests/timetests/src/android/app/time/ExternalTimeSuggestionTest.java
diff --git a/core/tests/coretests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java b/core/tests/timetests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java
index 384a5a82181b..384a5a82181b 100644
--- a/core/tests/coretests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java
+++ b/core/tests/timetests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java
diff --git a/core/tests/coretests/src/android/app/time/ParcelableTestSupport.java b/core/tests/timetests/src/android/app/time/ParcelableTestSupport.java
index 13e5e14ce01c..d2c9c3a35ce5 100644
--- a/core/tests/coretests/src/android/app/time/ParcelableTestSupport.java
+++ b/core/tests/timetests/src/android/app/time/ParcelableTestSupport.java
@@ -47,6 +47,10 @@ public final class ParcelableTestSupport {
return toReturn;
}
+ /**
+ * Asserts that the parameter can be parceled and unparceled and return an object considered
+ * equal to the original.
+ */
public static <T extends Parcelable> void assertRoundTripParcelable(T instance) {
assertEqualsAndHashCode(instance, roundTripParcelable(instance));
}
diff --git a/core/tests/coretests/src/android/app/time/TelephonyTimeZoneAlgorithmStatusTest.java b/core/tests/timetests/src/android/app/time/TelephonyTimeZoneAlgorithmStatusTest.java
index e6e2371d312f..e6e2371d312f 100644
--- a/core/tests/coretests/src/android/app/time/TelephonyTimeZoneAlgorithmStatusTest.java
+++ b/core/tests/timetests/src/android/app/time/TelephonyTimeZoneAlgorithmStatusTest.java
diff --git a/core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java b/core/tests/timetests/src/android/app/time/TimeCapabilitiesTest.java
index 3ead97f1528a..3ead97f1528a 100644
--- a/core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java
+++ b/core/tests/timetests/src/android/app/time/TimeCapabilitiesTest.java
diff --git a/core/tests/coretests/src/android/app/time/TimeManagerTest.java b/core/tests/timetests/src/android/app/time/TimeManagerTest.java
index 89c8d6a2e42b..89c8d6a2e42b 100644
--- a/core/tests/coretests/src/android/app/time/TimeManagerTest.java
+++ b/core/tests/timetests/src/android/app/time/TimeManagerTest.java
diff --git a/core/tests/coretests/src/android/app/time/TimeStateTest.java b/core/tests/timetests/src/android/app/time/TimeStateTest.java
index 50da3a68a140..50da3a68a140 100644
--- a/core/tests/coretests/src/android/app/time/TimeStateTest.java
+++ b/core/tests/timetests/src/android/app/time/TimeStateTest.java
diff --git a/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java b/core/tests/timetests/src/android/app/time/TimeZoneCapabilitiesTest.java
index e368d2815855..e368d2815855 100644
--- a/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
+++ b/core/tests/timetests/src/android/app/time/TimeZoneCapabilitiesTest.java
diff --git a/core/tests/coretests/src/android/app/time/TimeZoneConfigurationTest.java b/core/tests/timetests/src/android/app/time/TimeZoneConfigurationTest.java
index 4ad3e41383aa..4ad3e41383aa 100644
--- a/core/tests/coretests/src/android/app/time/TimeZoneConfigurationTest.java
+++ b/core/tests/timetests/src/android/app/time/TimeZoneConfigurationTest.java
diff --git a/core/tests/coretests/src/android/app/time/TimeZoneDetectorStatusTest.java b/core/tests/timetests/src/android/app/time/TimeZoneDetectorStatusTest.java
index 4ef60a3306aa..4ef60a3306aa 100644
--- a/core/tests/coretests/src/android/app/time/TimeZoneDetectorStatusTest.java
+++ b/core/tests/timetests/src/android/app/time/TimeZoneDetectorStatusTest.java
diff --git a/core/tests/coretests/src/android/app/time/TimeZoneStateTest.java b/core/tests/timetests/src/android/app/time/TimeZoneStateTest.java
index 0b816ecc0489..0b816ecc0489 100644
--- a/core/tests/coretests/src/android/app/time/TimeZoneStateTest.java
+++ b/core/tests/timetests/src/android/app/time/TimeZoneStateTest.java
diff --git a/core/tests/coretests/src/android/app/time/UnixEpochTimeTest.java b/core/tests/timetests/src/android/app/time/UnixEpochTimeTest.java
index 0b485c0af6ed..0b485c0af6ed 100644
--- a/core/tests/coretests/src/android/app/time/UnixEpochTimeTest.java
+++ b/core/tests/timetests/src/android/app/time/UnixEpochTimeTest.java
diff --git a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java b/core/tests/timetests/src/android/app/timedetector/ManualTimeSuggestionTest.java
index b06845602a87..b06845602a87 100644
--- a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
+++ b/core/tests/timetests/src/android/app/timedetector/ManualTimeSuggestionTest.java
diff --git a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java b/core/tests/timetests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
index 2716ebf53019..2716ebf53019 100644
--- a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
+++ b/core/tests/timetests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
diff --git a/core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java b/core/tests/timetests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java
index 8e1f0a19b4ab..8e1f0a19b4ab 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java
+++ b/core/tests/timetests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java
diff --git a/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java b/core/tests/timetests/src/android/app/timezonedetector/ShellCommandTestSupport.java
index 4efaed11168e..59a73048bc07 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java
+++ b/core/tests/timetests/src/android/app/timezonedetector/ShellCommandTestSupport.java
@@ -29,10 +29,17 @@ import java.util.List;
public final class ShellCommandTestSupport {
private ShellCommandTestSupport() {}
+ /**
+ * Returns a {@link ShellCommand} from the supplied String, where elements of the command are
+ * separated with spaces. No escaping is performed.
+ */
public static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) {
return createShellCommandWithArgsAndOptions(Arrays.asList(argsWithSpaces.split(" ")));
}
+ /**
+ * Returns a {@link ShellCommand} from the supplied list of command line elements.
+ */
public static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) {
ShellCommand command = mock(ShellCommand.class);
class ArgProvider {
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java b/core/tests/timetests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java
index 42cb856694bc..42cb856694bc 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java
+++ b/core/tests/timetests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java
diff --git a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderEventTest.java b/core/tests/timetests/src/android/service/timezone/TimeZoneProviderEventTest.java
index 26e424513092..26e424513092 100644
--- a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderEventTest.java
+++ b/core/tests/timetests/src/android/service/timezone/TimeZoneProviderEventTest.java
diff --git a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java b/core/tests/timetests/src/android/service/timezone/TimeZoneProviderStatusTest.java
index 9b2455982f70..cf37db680326 100644
--- a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
+++ b/core/tests/timetests/src/android/service/timezone/TimeZoneProviderStatusTest.java
@@ -32,6 +32,9 @@ import android.service.timezone.TimeZoneProviderStatus.OperationStatus;
import androidx.test.filters.SmallTest;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,9 +42,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
-import junitparams.JUnitParamsRunner;
-import junitparams.Parameters;
-
/** Non-SDK tests. See CTS for SDK API tests. */
@RunWith(JUnitParamsRunner.class)
@SmallTest
@@ -83,6 +83,7 @@ public class TimeZoneProviderStatusTest {
providerStatus.couldEnableTelephonyFallback());
}
+ /** Parameters for {@link #couldEnableTelephonyFallback}. */
public static Integer[][] couldEnableTelephonyFallbackParams() {
List<Integer[]> params = new ArrayList<>();
@DependencyStatus int[] dependencyStatuses =
diff --git a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderSuggestionTest.java b/core/tests/timetests/src/android/service/timezone/TimeZoneProviderSuggestionTest.java
index a091036f8eaf..a091036f8eaf 100644
--- a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderSuggestionTest.java
+++ b/core/tests/timetests/src/android/service/timezone/TimeZoneProviderSuggestionTest.java
diff --git a/graphics/java/android/graphics/ForceDarkType.java b/graphics/java/android/graphics/ForceDarkType.java
new file mode 100644
index 000000000000..396b03703bb9
--- /dev/null
+++ b/graphics/java/android/graphics/ForceDarkType.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The style of force dark to use in {@link HardwareRenderer}.
+ *
+ * You must keep this in sync with the C++ enum ForceDarkType in
+ * frameworks/base/libs/hwui/utils/ForceDark.h
+ *
+ * @hide
+ */
+public class ForceDarkType {
+ /**
+ * Force dark disabled: normal, default operation.
+ *
+ * @hide
+ */
+ public static final int NONE = 0;
+
+ /**
+ * Use force dark
+ * @hide
+ */
+ public static final int FORCE_DARK = 1;
+
+ /**
+ * Force force-dark. {@see Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED}
+ * @hide */
+ public static final int FORCE_INVERT_COLOR_DARK = 2;
+
+ /** @hide */
+ @IntDef({
+ NONE,
+ FORCE_DARK,
+ FORCE_INVERT_COLOR_DARK,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ForceDarkTypeDef {}
+
+}
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 8cd262e783d8..20e393eaee6d 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -182,7 +182,7 @@ public class HardwareRenderer {
/** @hide */
protected RenderNode mRootNode;
private boolean mOpaque = true;
- private boolean mForceDark = false;
+ private int mForceDark = ForceDarkType.NONE;
private @ActivityInfo.ColorMode int mColorMode = ActivityInfo.COLOR_MODE_DEFAULT;
private float mDesiredSdrHdrRatio = 1f;
@@ -571,10 +571,10 @@ public class HardwareRenderer {
* Whether or not the force-dark feature should be used for this renderer.
* @hide
*/
- public boolean setForceDark(boolean enable) {
- if (mForceDark != enable) {
- mForceDark = enable;
- nSetForceDark(mNativeProxy, enable);
+ public boolean setForceDark(@ForceDarkType.ForceDarkTypeDef int type) {
+ if (mForceDark != type) {
+ mForceDark = type;
+ nSetForceDark(mNativeProxy, type);
return true;
}
return false;
@@ -1597,7 +1597,7 @@ public class HardwareRenderer {
private static native void nAllocateBuffers(long nativeProxy);
- private static native void nSetForceDark(long nativeProxy, boolean enabled);
+ private static native void nSetForceDark(long nativeProxy, int type);
private static native void nSetDisplayDensityDpi(int densityDpi);
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 0e59e9ad744d..29bdd5ce0c9e 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -28,3 +28,10 @@ flag {
description: "Enables invoking split contextually"
bug: "276361926"
}
+
+flag {
+ name: "enable_taskbar_navbar_unification"
+ namespace: "multitasking"
+ description: "Enables taskbar / navbar unification"
+ bug: "309671494"
+}
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index b556150e2ab9..3e66bbbf8d39 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -72,7 +72,7 @@
<!-- Warning message when we try to dock a non-resizeable task and launch it in fullscreen instead [CHAR LIMIT=NONE] -->
<string name="dock_non_resizeble_failed_to_dock_text">App does not support split screen</string>
<!-- Warning message when we try to dock an app not supporting multiple instances split into multiple sides [CHAR LIMIT=NONE] -->
- <string name="dock_multi_instances_not_supported_text">This app can only be opened in 1 window.</string>
+ <string name="dock_multi_instances_not_supported_text">This app can only be opened in 1 window</string>
<!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity to be displayed on a secondary display and that things might crash/not work properly [CHAR LIMIT=NONE] -->
<string name="forced_resizable_secondary_display">App may not work on a secondary display.</string>
<!-- Warning message when we try to launch a non-resizeable activity on a secondary display and launch it on the primary instead. -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
index 5cf9175073c0..8241e1a481ee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
@@ -136,6 +136,7 @@ class ActivityEmbeddingAnimationAdapter {
/** Called on frame update. */
final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
+ mTransformation.clear();
// Extract the transformation to the current time.
mAnimation.getTransformation(Math.min(currentPlayTime, mAnimation.getDuration()),
mTransformation);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index d28bb499c907..3e131bc44d39 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -40,6 +40,7 @@
#ifdef __ANDROID__
#include "include/gpu/ganesh/SkImageGanesh.h"
#endif
+#include "utils/ForceDark.h"
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
@@ -403,16 +404,21 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
deleteDisplayList(observer, info);
mDisplayList = std::move(mStagingDisplayList);
if (mDisplayList) {
- WebViewSyncData syncData {
- .applyForceDark = info && !info->disableForceDark
- };
+ WebViewSyncData syncData{.applyForceDark = shouldEnableForceDark(info)};
mDisplayList.syncContents(syncData);
handleForceDark(info);
}
}
+inline bool RenderNode::shouldEnableForceDark(TreeInfo* info) {
+ return CC_UNLIKELY(
+ info &&
+ (!info->disableForceDark ||
+ info->forceDarkType == android::uirenderer::ForceDarkType::FORCE_INVERT_COLOR_DARK));
+}
+
void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) {
- if (CC_LIKELY(!info || info->disableForceDark)) {
+ if (!shouldEnableForceDark(info)) {
return;
}
auto usage = usageHint();
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c959db37474b..1f3834be5bef 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -233,6 +233,7 @@ private:
void syncProperties();
void syncDisplayList(TreeObserver& observer, TreeInfo* info);
void handleForceDark(TreeInfo* info);
+ bool shouldEnableForceDark(TreeInfo* info);
void prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info);
diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp
index 750f869e2551..717157c09a53 100644
--- a/libs/hwui/TreeInfo.cpp
+++ b/libs/hwui/TreeInfo.cpp
@@ -24,7 +24,8 @@ TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContex
: mode(mode)
, prepareTextures(mode == MODE_FULL)
, canvasContext(canvasContext)
- , disableForceDark(canvasContext.useForceDark() ? 0 : 1)
+ , disableForceDark(canvasContext.getForceDarkType() == ForceDarkType::NONE ? 1 : 0)
+ , forceDarkType(canvasContext.getForceDarkType())
, screenSize(canvasContext.getNextFrameSize()) {}
} // namespace android::uirenderer
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index ea25f68d7170..88449f3a3572 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -24,6 +24,7 @@
#include "Properties.h"
#include "SkSize.h"
#include "SkippedFrameInfo.h"
+#include "utils/ForceDark.h"
#include "utils/Macros.h"
namespace android {
@@ -97,6 +98,7 @@ public:
bool updateWindowPositions = false;
int disableForceDark;
+ ForceDarkType forceDarkType = ForceDarkType::NONE;
const SkISize screenSize;
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 422ffeaecfd0..d15b1680de94 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -35,6 +35,7 @@
#include <gui/TraceUtils.h>
#include <include/encode/SkPngEncoder.h>
#include <inttypes.h>
+#include <log/log.h>
#include <media/NdkImage.h>
#include <media/NdkImageReader.h>
#include <nativehelper/JNIPlatformHelp.h>
@@ -53,11 +54,11 @@
#include <algorithm>
#include <atomic>
-#include <log/log.h>
#include <vector>
#include "JvmErrorReporter.h"
#include "android_graphics_HardwareRendererObserver.h"
+#include "utils/ForceDark.h"
namespace android {
@@ -824,10 +825,10 @@ static void android_view_ThreadedRenderer_allocateBuffers(JNIEnv* env, jobject c
proxy->allocateBuffers();
}
-static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jboolean enable) {
+static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz, jlong proxyPtr,
+ jint type) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->setForceDark(enable);
+ proxy->setForceDark(static_cast<ForceDarkType>(type));
}
static void android_view_ThreadedRenderer_preload(JNIEnv*, jclass) {
@@ -1016,7 +1017,7 @@ static const JNINativeMethod gMethods[] = {
{"nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess},
{"nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority},
{"nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers},
- {"nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark},
+ {"nSetForceDark", "(JI)V", (void*)android_view_ThreadedRenderer_setForceDark},
{"nSetDisplayDensityDpi", "(I)V",
(void*)android_view_ThreadedRenderer_setDisplayDensityDpi},
{"nInitDisplayInfo", "(IIFIJJZZ)V", (void*)android_view_ThreadedRenderer_initDisplayInfo},
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 7fac0c9776ac..9e3bb79f03f3 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -969,6 +969,7 @@ void CanvasContext::buildLayer(RenderNode* node) {
// buildLayer() will leave the tree in an unknown state, so we must stop drawing
stopDrawing();
+ ScopedActiveContext activeContext(this);
TreeInfo info(TreeInfo::MODE_FULL, *this);
info.damageAccumulator = &mDamageAccumulator;
info.layerUpdateQueue = &mLayerUpdateQueue;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 37e4f7ecca54..be9b649030ae 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -46,6 +46,7 @@
#include "renderstate/RenderState.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
+#include "utils/ForceDark.h"
#include "utils/RingBuffer.h"
namespace android {
@@ -194,11 +195,9 @@ public:
mRenderPipeline->setPictureCapturedCallback(callback);
}
- void setForceDark(bool enable) { mUseForceDark = enable; }
+ void setForceDark(ForceDarkType type) { mForceDarkType = type; }
- bool useForceDark() {
- return mUseForceDark;
- }
+ ForceDarkType getForceDarkType() { return mForceDarkType; }
SkISize getNextFrameSize() const;
@@ -321,7 +320,7 @@ private:
nsecs_t mLastDropVsync = 0;
bool mOpaque;
- bool mUseForceDark = false;
+ ForceDarkType mForceDarkType = ForceDarkType::NONE;
LightInfo mLightInfo;
LightGeometry mLightGeometry = {{0, 0, 0}, 0};
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index be163bad77a7..c3c136feef69 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -417,8 +417,8 @@ void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr)
});
}
-void RenderProxy::setForceDark(bool enable) {
- mRenderThread.queue().post([this, enable]() { mContext->setForceDark(enable); });
+void RenderProxy::setForceDark(ForceDarkType type) {
+ mRenderThread.queue().post([this, type]() { mContext->setForceDark(type); });
}
void RenderProxy::copySurfaceInto(ANativeWindow* window, std::shared_ptr<CopyRequest>&& request) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 47c1b0cd28e5..f2d8e94c7bd2 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -31,6 +31,7 @@
#include "DrawFrameTask.h"
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
+#include "utils/ForceDark.h"
class SkBitmap;
class SkPicture;
@@ -142,7 +143,7 @@ public:
void addFrameMetricsObserver(FrameMetricsObserver* observer);
void removeFrameMetricsObserver(FrameMetricsObserver* observer);
- void setForceDark(bool enable);
+ void setForceDark(ForceDarkType type);
static void copySurfaceInto(ANativeWindow* window, std::shared_ptr<CopyRequest>&& request);
static void prepareToDraw(Bitmap& bitmap);
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/OnMainSwitchChangeListener.java b/libs/hwui/utils/ForceDark.h
index 03868f99663d..28538c4b7a7b 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/OnMainSwitchChangeListener.java
+++ b/libs/hwui/utils/ForceDark.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,19 +14,21 @@
* limitations under the License.
*/
-package com.android.settingslib.widget;
+#ifndef FORCEDARKUTILS_H
+#define FORCEDARKUTILS_H
-import android.widget.Switch;
-
-import com.android.settingslib.widget.mainswitch.R;
+namespace android {
+namespace uirenderer {
/**
- * Called when the checked state of the Switch has changed.
+ * The type of force dark set on the renderer, if any.
+ *
+ * This should stay in sync with the java @IntDef in
+ * frameworks/base/graphics/java/android/graphics/ForceDarkType.java
*/
-public interface OnMainSwitchChangeListener {
- /**
- * @param switchView The Switch view whose state has changed.
- * @param isChecked The new checked state of switchView.
- */
- void onSwitchChanged(Switch switchView, boolean isChecked);
-}
+enum class ForceDarkType : __uint8_t { NONE = 0, FORCE_DARK = 1, FORCE_INVERT_COLOR_DARK = 2 };
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // FORCEDARKUTILS_H \ No newline at end of file
diff --git a/packages/CredentialManager/wear/Android.bp b/packages/CredentialManager/wear/Android.bp
index c883b1f26160..2a89a9940936 100644
--- a/packages/CredentialManager/wear/Android.bp
+++ b/packages/CredentialManager/wear/Android.bp
@@ -35,6 +35,7 @@ android_app {
"androidx.compose.ui_ui",
"androidx.compose.ui_ui-tooling",
"androidx.core_core-ktx",
+ "androidx.hilt_hilt-navigation-compose",
"androidx.lifecycle_lifecycle-extensions",
"androidx.lifecycle_lifecycle-livedata",
"androidx.lifecycle_lifecycle-runtime-ktx",
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 0a63cb74a25a..f2df64aee22e 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -21,16 +21,10 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
import androidx.wear.compose.material.MaterialTheme
import com.android.credentialmanager.ui.WearApp
-import com.android.credentialmanager.ui.screens.single.password.SinglePasswordScreen
import com.google.android.horologist.annotations.ExperimentalHorologistApi
-import com.google.android.horologist.compose.layout.belowTimeTextPreview
import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.launch
@AndroidEntryPoint(ComponentActivity::class)
class CredentialSelectorActivity : Hilt_CredentialSelectorActivity() {
@@ -42,50 +36,14 @@ class CredentialSelectorActivity : Hilt_CredentialSelectorActivity() {
super.onCreate(savedInstanceState)
setTheme(android.R.style.Theme_DeviceDefault)
-
- // TODO: b/301027810 due to this issue with compose in Main platform, we are implementing a
- // workaround. Once the issue is fixed, remove the "else" bracket and leave only the
- // contents of the "if" bracket.
- if (false) {
- setContent {
- MaterialTheme {
- WearApp(
- viewModel = viewModel,
- onCloseApp = ::finish,
- )
- }
- }
- } else {
- // TODO: b/301027810 Remove the content of this "else" bracket fully once issue is fixed
- lifecycleScope.launch {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- viewModel.uiState.collect { uiState ->
- when (uiState) {
- CredentialSelectorUiState.Idle -> {
- // Don't display anything, assuming that there should be minimal latency
- // to parse the Credential Manager intent and define the state of the
- // app. If latency is big, then a "loading" screen should be displayed
- // to the user.
- }
-
- is CredentialSelectorUiState.Get -> {
- setContent {
- MaterialTheme {
- SinglePasswordScreen(
- columnState = belowTimeTextPreview(),
- onCloseApp = ::finish,
- )
- }
- }
- }
-
- else -> finish()
- }
- }
- }
+ setContent {
+ MaterialTheme {
+ WearApp(
+ viewModel = viewModel,
+ onCloseApp = ::finish,
+ )
}
}
-
viewModel.onNewIntent(intent)
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt
index 81a067289d89..c28df3e8895a 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt
@@ -27,8 +27,8 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
+import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.credentialmanager.R
import com.android.credentialmanager.TAG
import com.android.credentialmanager.activity.StartBalIntentSenderForResultContract
@@ -47,7 +47,7 @@ fun SinglePasswordScreen(
columnState: ScalingLazyColumnState,
onCloseApp: () -> Unit,
modifier: Modifier = Modifier,
- viewModel: SinglePasswordScreenViewModel = viewModel(),
+ viewModel: SinglePasswordScreenViewModel = hiltViewModel(),
) {
viewModel.initialize()
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 600115545a16..2b5fcd807899 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -24,8 +24,8 @@ import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
-import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.ColorInt;
@@ -41,9 +41,9 @@ import java.util.List;
* This component is used as the main switch of the page
* to enable or disable the prefereces on the page.
*/
-public class MainSwitchBar extends LinearLayout implements CompoundButton.OnCheckedChangeListener {
+public class MainSwitchBar extends LinearLayout implements OnCheckedChangeListener {
- private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
+ private final List<OnCheckedChangeListener> mSwitchChangeListeners = new ArrayList<>();
@ColorInt
private int mBackgroundColor;
@@ -51,8 +51,8 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec
private int mBackgroundActivatedColor;
protected TextView mTextView;
- protected Switch mSwitch;
- private View mFrameView;
+ protected CompoundButton mSwitch;
+ private final View mFrameView;
public MainSwitchBar(Context context) {
this(context, null);
@@ -84,8 +84,8 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec
setClickable(true);
mFrameView = findViewById(R.id.frame);
- mTextView = (TextView) findViewById(R.id.switch_text);
- mSwitch = (Switch) findViewById(android.R.id.switch_widget);
+ mTextView = findViewById(R.id.switch_text);
+ mSwitch = findViewById(android.R.id.switch_widget);
addOnSwitchChangeListener((switchView, isChecked) -> setChecked(isChecked));
if (mSwitch.getVisibility() == VISIBLE) {
@@ -136,13 +136,6 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec
}
/**
- * Return the Switch
- */
- public final Switch getSwitch() {
- return mSwitch;
- }
-
- /**
* Set the title text
*/
public void setTitle(CharSequence text) {
@@ -192,7 +185,7 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec
/**
* Adds a listener for switch changes
*/
- public void addOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
+ public void addOnSwitchChangeListener(OnCheckedChangeListener listener) {
if (!mSwitchChangeListeners.contains(listener)) {
mSwitchChangeListeners.add(listener);
}
@@ -201,7 +194,7 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec
/**
* Remove a listener for switch changes
*/
- public void removeOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
+ public void removeOnSwitchChangeListener(OnCheckedChangeListener listener) {
mSwitchChangeListeners.remove(listener);
}
@@ -223,9 +216,8 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec
private void propagateChecked(boolean isChecked) {
setBackground(isChecked);
- final int count = mSwitchChangeListeners.size();
- for (int n = 0; n < count; n++) {
- mSwitchChangeListeners.get(n).onSwitchChanged(mSwitch, isChecked);
+ for (OnCheckedChangeListener changeListener : mSwitchChangeListeners) {
+ changeListener.onCheckedChanged(mSwitch, isChecked);
}
}
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
index 11a680466ecf..b294d4e3ad19 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
@@ -19,24 +19,25 @@ package com.android.settingslib.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
-import android.widget.Switch;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.TwoStatePreference;
+import com.android.settingslib.widget.mainswitch.R;
+
import java.util.ArrayList;
import java.util.List;
-import com.android.settingslib.widget.mainswitch.R;
-
/**
* MainSwitchPreference is a Preference with a customized Switch.
* This component is used as the main switch of the page
* to enable or disable the prefereces on the page.
*/
-public class MainSwitchPreference extends TwoStatePreference implements OnMainSwitchChangeListener {
+public class MainSwitchPreference extends TwoStatePreference implements OnCheckedChangeListener {
- private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
+ private final List<OnCheckedChangeListener> mSwitchChangeListeners = new ArrayList<>();
private MainSwitchBar mMainSwitchBar;
@@ -120,7 +121,7 @@ public class MainSwitchPreference extends TwoStatePreference implements OnMainSw
}
@Override
- public void onSwitchChanged(Switch switchView, boolean isChecked) {
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
super.setChecked(isChecked);
}
@@ -138,7 +139,7 @@ public class MainSwitchPreference extends TwoStatePreference implements OnMainSw
/**
* Adds a listener for switch changes
*/
- public void addOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
+ public void addOnSwitchChangeListener(OnCheckedChangeListener listener) {
if (!mSwitchChangeListeners.contains(listener)) {
mSwitchChangeListeners.add(listener);
}
@@ -151,7 +152,7 @@ public class MainSwitchPreference extends TwoStatePreference implements OnMainSw
/**
* Remove a listener for switch changes
*/
- public void removeOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
+ public void removeOnSwitchChangeListener(OnCheckedChangeListener listener) {
mSwitchChangeListeners.remove(listener);
if (mMainSwitchBar != null) {
mMainSwitchBar.removeOnSwitchChangeListener(listener);
@@ -159,7 +160,7 @@ public class MainSwitchPreference extends TwoStatePreference implements OnMainSw
}
private void registerListenerToSwitchBar() {
- for (OnMainSwitchChangeListener listener : mSwitchChangeListeners) {
+ for (OnCheckedChangeListener listener : mSwitchChangeListeners) {
mMainSwitchBar.addOnSwitchChangeListener(listener);
}
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt
new file mode 100644
index 000000000000..2c60db4e76c7
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.framework.common
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.UserHandle
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.flowOn
+
+/**
+ * A [BroadcastReceiver] flow for the given [intentFilter].
+ */
+fun Context.broadcastReceiverAsUserFlow(
+ intentFilter: IntentFilter,
+ userHandle: UserHandle,
+): Flow<Intent> = callbackFlow {
+ val broadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ trySend(intent)
+ }
+ }
+ registerReceiverAsUser(
+ broadcastReceiver,
+ userHandle,
+ intentFilter,
+ null,
+ null,
+ Context.RECEIVER_NOT_EXPORTED,
+ )
+
+ awaitClose { unregisterReceiver(broadcastReceiver) }
+}.conflate().flowOn(Dispatchers.Default)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
index ad907cfeb5bf..7d6ee1928111 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
@@ -17,14 +17,14 @@
package com.android.settingslib.spaprivileged.framework.compose
import android.content.BroadcastReceiver
-import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.UserHandle
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
-import com.android.settingslib.spa.framework.compose.LifecycleEffect
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
+import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverAsUserFlow
/**
* A [BroadcastReceiver] which registered when on start and unregistered when on stop.
@@ -35,27 +35,6 @@ fun DisposableBroadcastReceiverAsUser(
userHandle: UserHandle,
onReceive: (Intent) -> Unit,
) {
- val context = LocalContext.current
- val broadcastReceiver = remember {
- object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- onReceive(intent)
- }
- }
- }
- LifecycleEffect(
- onStart = {
- context.registerReceiverAsUser(
- broadcastReceiver,
- userHandle,
- intentFilter,
- null,
- null,
- Context.RECEIVER_NOT_EXPORTED,
- )
- },
- onStop = {
- context.unregisterReceiver(broadcastReceiver)
- },
- )
+ LocalContext.current.broadcastReceiverAsUserFlow(intentFilter, userHandle)
+ .collectLatestWithLifecycle(LocalLifecycleOwner.current, action = onReceive)
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
new file mode 100644
index 000000000000..dfb8e22c7b52
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.framework.common
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.isNull
+import org.mockito.kotlin.mock
+
+@RunWith(AndroidJUnit4::class)
+class BroadcastReceiverAsUserFlowTest {
+
+ private var registeredBroadcastReceiver: BroadcastReceiver? = null
+
+ private val context = mock<Context> {
+ on {
+ registerReceiverAsUser(
+ any(),
+ eq(USER_HANDLE),
+ eq(INTENT_FILTER),
+ isNull(),
+ isNull(),
+ eq(Context.RECEIVER_NOT_EXPORTED),
+ )
+ } doAnswer {
+ registeredBroadcastReceiver = it.arguments[0] as BroadcastReceiver
+ null
+ }
+ }
+
+ @Test
+ fun broadcastReceiverAsUserFlow_registered() = runBlocking {
+ val flow = context.broadcastReceiverAsUserFlow(INTENT_FILTER, USER_HANDLE)
+
+ flow.firstWithTimeoutOrNull()
+
+ assertThat(registeredBroadcastReceiver).isNotNull()
+ }
+
+ @Test
+ fun broadcastReceiverAsUserFlow_isCalledOnReceive() = runBlocking {
+ var onReceiveIsCalled = false
+ launch {
+ context.broadcastReceiverAsUserFlow(INTENT_FILTER, USER_HANDLE).first {
+ onReceiveIsCalled = true
+ true
+ }
+ }
+
+ delay(100)
+ registeredBroadcastReceiver!!.onReceive(context, Intent())
+ delay(100)
+
+ assertThat(onReceiveIsCalled).isTrue()
+ }
+
+ private companion object {
+ val USER_HANDLE: UserHandle = UserHandle.of(0)
+
+ val INTENT_FILTER = IntentFilter()
+ }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
index 2c8fb66fab0a..f812f959db32 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
@@ -23,38 +23,32 @@ import android.content.IntentFilter
import android.os.UserHandle
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
-import org.junit.Before
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.eq
import org.mockito.kotlin.isNull
-import org.mockito.kotlin.whenever
+import org.mockito.kotlin.mock
@RunWith(AndroidJUnit4::class)
class DisposableBroadcastReceiverAsUserTest {
@get:Rule
val composeTestRule = createComposeRule()
- @get:Rule
- val mockito: MockitoRule = MockitoJUnit.rule()
-
- @Mock
- private lateinit var context: Context
-
private var registeredBroadcastReceiver: BroadcastReceiver? = null
- @Before
- fun setUp() {
- whenever(
- context.registerReceiverAsUser(
+ private val context = mock<Context> {
+ on {
+ registerReceiverAsUser(
any(),
eq(USER_HANDLE),
eq(INTENT_FILTER),
@@ -62,7 +56,7 @@ class DisposableBroadcastReceiverAsUserTest {
isNull(),
eq(Context.RECEIVER_NOT_EXPORTED),
)
- ).then {
+ } doAnswer {
registeredBroadcastReceiver = it.arguments[0] as BroadcastReceiver
null
}
@@ -71,7 +65,10 @@ class DisposableBroadcastReceiverAsUserTest {
@Test
fun broadcastReceiver_registered() {
composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
+ CompositionLocalProvider(
+ LocalContext provides context,
+ LocalLifecycleOwner provides TestLifecycleOwner(),
+ ) {
DisposableBroadcastReceiverAsUser(INTENT_FILTER, USER_HANDLE) {}
}
}
@@ -80,10 +77,13 @@ class DisposableBroadcastReceiverAsUserTest {
}
@Test
- fun broadcastReceiver_isCalledOnReceive() {
+ fun broadcastReceiver_isCalledOnReceive() = runBlocking {
var onReceiveIsCalled = false
composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
+ CompositionLocalProvider(
+ LocalContext provides context,
+ LocalLifecycleOwner provides TestLifecycleOwner(),
+ ) {
DisposableBroadcastReceiverAsUser(INTENT_FILTER, USER_HANDLE) {
onReceiveIsCalled = true
}
@@ -91,6 +91,7 @@ class DisposableBroadcastReceiverAsUserTest {
}
registeredBroadcastReceiver!!.onReceive(context, Intent())
+ delay(100)
assertThat(onReceiveIsCalled).isTrue()
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
index 840bca8b14ec..44973a743c76 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
@@ -19,6 +19,8 @@ package com.android.settingslib.spaprivileged.model.app
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
+import android.content.pm.FakeFeatureFlagsImpl
+import android.content.pm.Flags
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ApplicationInfoFlags
import android.content.pm.PackageManager.ResolveInfoFlags
@@ -29,76 +31,62 @@ import android.os.UserManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.internal.R
-import com.android.settingslib.spaprivileged.framework.common.userManager
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Spy
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
-import android.content.pm.FakeFeatureFlagsImpl
-import android.content.pm.Flags
@RunWith(AndroidJUnit4::class)
class AppListRepositoryTest {
- @get:Rule
- val mockito: MockitoRule = MockitoJUnit.rule()
-
- @Spy
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- @Mock
- private lateinit var resources: Resources
-
- @Mock
- private lateinit var packageManager: PackageManager
-
- @Mock
- private lateinit var userManager: UserManager
-
- private lateinit var repository: AppListRepository
+ private val resources = mock<Resources> {
+ on { getStringArray(R.array.config_hideWhenDisabled_packageNames) } doReturn emptyArray()
+ }
- @Before
- fun setUp() {
- whenever(context.resources).thenReturn(resources)
- whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames))
- .thenReturn(emptyArray())
- whenever(context.packageManager).thenReturn(packageManager)
- whenever(context.userManager).thenReturn(userManager)
- whenever(packageManager.getInstalledModules(any())).thenReturn(emptyList())
- whenever(packageManager.getHomeActivities(any())).thenAnswer {
+ private val packageManager = mock<PackageManager> {
+ on { getInstalledModules(any()) } doReturn emptyList()
+ on { getHomeActivities(any()) } doAnswer {
@Suppress("UNCHECKED_CAST")
val resolveInfos = it.arguments[0] as MutableList<ResolveInfo>
resolveInfos += resolveInfoOf(packageName = HOME_APP.packageName)
null
}
- whenever(
- packageManager.queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), any<Int>())
- ).thenReturn(listOf(resolveInfoOf(packageName = IN_LAUNCHER_APP.packageName)))
- whenever(userManager.getUserInfo(ADMIN_USER_ID)).thenReturn(UserInfo().apply {
+ on { queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), any<Int>()) } doReturn
+ listOf(resolveInfoOf(packageName = IN_LAUNCHER_APP.packageName))
+ }
+
+ private val mockUserManager = mock<UserManager> {
+ on { getUserInfo(ADMIN_USER_ID) } doReturn UserInfo().apply {
flags = UserInfo.FLAG_ADMIN
- })
- whenever(userManager.getProfileIdsWithDisabled(ADMIN_USER_ID))
- .thenReturn(intArrayOf(ADMIN_USER_ID, MANAGED_PROFILE_USER_ID))
+ }
+ on { getProfileIdsWithDisabled(ADMIN_USER_ID) } doReturn
+ intArrayOf(ADMIN_USER_ID, MANAGED_PROFILE_USER_ID)
+ }
- repository = AppListRepositoryImpl(context)
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { resources } doReturn resources
+ on { packageManager } doReturn packageManager
+ on { getSystemService(UserManager::class.java) } doReturn mockUserManager
}
+ private val repository = AppListRepositoryImpl(context)
+
private fun mockInstalledApplications(apps: List<ApplicationInfo>, userId: Int) {
- whenever(
- packageManager.getInstalledApplicationsAsUser(any<ApplicationInfoFlags>(), eq(userId))
- ).thenReturn(apps)
+ packageManager.stub {
+ on { getInstalledApplicationsAsUser(any<ApplicationInfoFlags>(), eq(userId)) } doReturn
+ apps
+ }
}
@Test
@@ -135,13 +123,13 @@ class AppListRepositoryTest {
)
assertThat(appList).containsExactly(NORMAL_APP)
- argumentCaptor<ApplicationInfoFlags> {
+ val flags = argumentCaptor<ApplicationInfoFlags> {
verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID))
- assertThat(firstValue.value).isEqualTo(
- PackageManager.MATCH_DISABLED_COMPONENTS or
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
- )
- }
+ }.firstValue
+ assertThat(flags.value).isEqualTo(
+ PackageManager.MATCH_DISABLED_COMPONENTS or
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ )
}
@Test
@@ -154,11 +142,10 @@ class AppListRepositoryTest {
)
assertThat(appList).containsExactly(NORMAL_APP)
- argumentCaptor<ApplicationInfoFlags> {
+ val flags = argumentCaptor<ApplicationInfoFlags> {
verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID))
- assertThat(firstValue.value and PackageManager.MATCH_ANY_USER.toLong())
- .isGreaterThan(0L)
- }
+ }.firstValue
+ assertThat(flags.value and PackageManager.MATCH_ANY_USER.toLong()).isGreaterThan(0L)
}
@Test
@@ -278,14 +265,14 @@ class AppListRepositoryTest {
val appList = repository.loadApps(userId = ADMIN_USER_ID)
assertThat(appList).containsExactly(NORMAL_APP, ARCHIVED_APP)
- argumentCaptor<ApplicationInfoFlags> {
+ val flags = argumentCaptor<ApplicationInfoFlags> {
verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID))
- assertThat(firstValue.value).isEqualTo(
- (PackageManager.MATCH_DISABLED_COMPONENTS or
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong() or
- PackageManager.MATCH_ARCHIVED_PACKAGES
- )
- }
+ }.firstValue
+ assertThat(flags.value).isEqualTo(
+ (PackageManager.MATCH_DISABLED_COMPONENTS or
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong() or
+ PackageManager.MATCH_ARCHIVED_PACKAGES
+ )
}
@Test
@@ -294,13 +281,13 @@ class AppListRepositoryTest {
val appList = repository.loadApps(userId = ADMIN_USER_ID)
assertThat(appList).containsExactly(NORMAL_APP)
- argumentCaptor<ApplicationInfoFlags> {
+ val flags = argumentCaptor<ApplicationInfoFlags> {
verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID))
- assertThat(firstValue.value).isEqualTo(
- PackageManager.MATCH_DISABLED_COMPONENTS or
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
- )
- }
+ }.firstValue
+ assertThat(flags.value).isEqualTo(
+ PackageManager.MATCH_DISABLED_COMPONENTS or
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ )
}
@Test
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 0e7b79ba297a..119aef6da12e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -136,7 +136,7 @@ public class LocalBluetoothProfileManager {
/**
* create profile instance according to bluetooth supported profile list
*/
- void updateLocalProfiles() {
+ synchronized void updateLocalProfiles() {
List<Integer> supportedList = BluetoothAdapter.getDefaultAdapter().getSupportedProfiles();
if (CollectionUtils.isEmpty(supportedList)) {
if (DEBUG) Log.d(TAG, "supportedList is null");
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
index 942e91525f02..74a282fbd106 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
@@ -21,30 +21,25 @@ import static android.graphics.text.LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
-import android.text.TextUtils;
import android.view.View;
-import android.widget.Switch;
+import android.widget.CompoundButton;
import android.widget.TextView;
+import androidx.test.core.app.ApplicationProvider;
+
import com.android.settingslib.widget.mainswitch.R;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class MainSwitchBarTest {
- private Context mContext;
- private MainSwitchBar mBar;
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ private final MainSwitchBar mBar = new MainSwitchBar(mContext);
- @Before
- public void setUp() {
- mContext = RuntimeEnvironment.application;
- mBar = new MainSwitchBar(mContext);
- }
+ private final CompoundButton mSwitch = mBar.findViewById(android.R.id.switch_widget);
@Test
public void setChecked_true_shouldChecked() {
@@ -60,7 +55,7 @@ public class MainSwitchBarTest {
mBar.setTitle(title);
final TextView textView = ((TextView) mBar.findViewById(R.id.switch_text));
- assertThat(textView.getText()).isEqualTo(title);
+ assertThat(textView.getText().toString()).isEqualTo(title);
}
@Test
@@ -69,23 +64,18 @@ public class MainSwitchBarTest {
mBar.setTitle(title);
- final Switch switchObj = mBar.getSwitch();
- assertThat(TextUtils.isEmpty(switchObj.getContentDescription())).isTrue();
+ assertThat(mSwitch.getContentDescription()).isNull();
}
@Test
public void getSwitch_shouldNotNull() {
- final Switch switchObj = mBar.getSwitch();
-
- assertThat(switchObj).isNotNull();
+ assertThat(mSwitch).isNotNull();
}
@Test
public void getSwitch_shouldNotFocusableAndClickable() {
- final Switch switchObj = mBar.getSwitch();
-
- assertThat(switchObj.isFocusable()).isFalse();
- assertThat(switchObj.isClickable()).isFalse();
+ assertThat(mSwitch.isFocusable()).isFalse();
+ assertThat(mSwitch.isClickable()).isFalse();
}
@Test
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index 6bc27160c0a8..c2fc0d9a4d91 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -29,6 +29,7 @@ import android.app.ActivityManager;
import android.content.AttributionSource;
import android.content.IContentProvider;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Process;
@@ -219,14 +220,29 @@ public final class DeviceConfigService extends Binder {
return lines;
}
+ private static void log(String msg) {
+ if (Build.IS_DEBUGGABLE) {
+ Slog.wtf(TAG, msg);
+ } else {
+ Slog.e(TAG, msg);
+ }
+ }
+
public static List<String> listAllAconfigFlags(IContentProvider provider) {
HashMap<String, String> allFlags = getAllFlags(provider);
HashSet<String> aconfigFlagNames = getAconfigFlagNamesInDeviceConfig();
final ArrayList<String> lines = new ArrayList<>();
- for (String key : aconfigFlagNames) {
- String val = allFlags.get(key);
+ for (String aconfigFlag : aconfigFlagNames) {
+ String val = allFlags.get(aconfigFlag);
if (val != null) {
- lines.add(key + "=" + val);
+ int idx = aconfigFlag.indexOf("/");
+ if (idx == -1 || idx == aconfigFlag.length() - 1 || idx == 0) {
+ log("invalid flag entry in device config: " + aconfigFlag);
+ continue;
+ }
+ String aconfigFlagNameByPackage = aconfigFlag.substring(idx+1);
+ String namespace = aconfigFlag.substring(0, idx);
+ lines.add(aconfigFlagNameByPackage + " " + namespace + "=" + val);
}
}
Collections.sort(lines);
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 56970d7e3005..d668c691ee0d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -154,7 +154,7 @@ private fun SceneScope.BouncerScene(
Bouncer(
viewModel = viewModel,
dialogFactory = dialogFactory,
- isUserInputAreaVisible = true,
+ userInputAreaVisibility = UserInputAreaVisibility.FULL,
modifier = childModifier,
)
Layout.SIDE_BY_SIDE ->
@@ -189,7 +189,7 @@ private fun SceneScope.BouncerScene(
private fun Bouncer(
viewModel: BouncerViewModel,
dialogFactory: BouncerSceneDialogFactory,
- isUserInputAreaVisible: Boolean,
+ userInputAreaVisibility: UserInputAreaVisibility,
modifier: Modifier = Modifier,
) {
val message: BouncerViewModel.MessageViewModel by viewModel.message.collectAsState()
@@ -214,12 +214,11 @@ private fun Bouncer(
}
Box(Modifier.weight(1f)) {
- if (isUserInputAreaVisible) {
- UserInputArea(
- viewModel = viewModel,
- modifier = Modifier.align(Alignment.Center),
- )
- }
+ UserInputArea(
+ viewModel = viewModel,
+ visibility = userInputAreaVisibility,
+ modifier = Modifier.align(Alignment.Center),
+ )
}
if (viewModel.isEmergencyButtonVisible) {
@@ -269,6 +268,7 @@ private fun Bouncer(
@Composable
private fun UserInputArea(
viewModel: BouncerViewModel,
+ visibility: UserInputAreaVisibility,
modifier: Modifier = Modifier,
) {
val authMethodViewModel: AuthMethodBouncerViewModel? by
@@ -276,21 +276,46 @@ private fun UserInputArea(
when (val nonNullViewModel = authMethodViewModel) {
is PinBouncerViewModel ->
- PinBouncer(
- viewModel = nonNullViewModel,
- modifier = modifier,
- )
+ when (visibility) {
+ UserInputAreaVisibility.FULL ->
+ PinBouncer(
+ viewModel = nonNullViewModel,
+ modifier = modifier,
+ )
+ UserInputAreaVisibility.INPUT_ONLY ->
+ PinPad(
+ viewModel = nonNullViewModel,
+ modifier = modifier,
+ )
+ UserInputAreaVisibility.OUTPUT_ONLY ->
+ PinInputDisplay(
+ viewModel = nonNullViewModel,
+ modifier = modifier,
+ )
+ UserInputAreaVisibility.NONE -> {}
+ }
is PasswordBouncerViewModel ->
- PasswordBouncer(
- viewModel = nonNullViewModel,
- modifier = modifier,
- )
+ when (visibility) {
+ UserInputAreaVisibility.FULL,
+ UserInputAreaVisibility.INPUT_ONLY ->
+ PasswordBouncer(
+ viewModel = nonNullViewModel,
+ modifier = modifier,
+ )
+ else -> {}
+ }
is PatternBouncerViewModel ->
- PatternBouncer(
- viewModel = nonNullViewModel,
- modifier =
- Modifier.aspectRatio(1f, matchHeightConstraintsFirst = false).then(modifier)
- )
+ when (visibility) {
+ UserInputAreaVisibility.FULL,
+ UserInputAreaVisibility.INPUT_ONLY ->
+ PatternBouncer(
+ viewModel = nonNullViewModel,
+ modifier =
+ Modifier.aspectRatio(1f, matchHeightConstraintsFirst = false)
+ .then(modifier)
+ )
+ else -> {}
+ }
else -> Unit
}
}
@@ -435,13 +460,14 @@ private fun Split(
Bouncer(
viewModel = viewModel,
dialogFactory = dialogFactory,
- isUserInputAreaVisible = false,
+ userInputAreaVisibility = UserInputAreaVisibility.OUTPUT_ONLY,
modifier = startContentModifier,
)
},
endContent = { endContentModifier ->
UserInputArea(
viewModel = viewModel,
+ visibility = UserInputAreaVisibility.INPUT_ONLY,
modifier = endContentModifier,
)
},
@@ -545,7 +571,7 @@ private fun SideBySide(
Bouncer(
viewModel = viewModel,
dialogFactory = dialogFactory,
- isUserInputAreaVisible = true,
+ userInputAreaVisibility = UserInputAreaVisibility.FULL,
modifier = endContentModifier,
)
},
@@ -574,7 +600,7 @@ private fun Stacked(
Bouncer(
viewModel = viewModel,
dialogFactory = dialogFactory,
- isUserInputAreaVisible = true,
+ userInputAreaVisibility = UserInputAreaVisibility.FULL,
modifier = Modifier.fillMaxWidth().weight(1f),
)
}
@@ -630,6 +656,27 @@ private enum class Layout {
SPLIT,
}
+/** Enumerates all supported user-input area visibilities. */
+private enum class UserInputAreaVisibility {
+ /**
+ * The entire user input area is shown, including where the user enters input and where it's
+ * reflected to the user.
+ */
+ FULL,
+ /**
+ * Only the area where the user enters the input is shown; the area where the input is reflected
+ * back to the user is not shown.
+ */
+ INPUT_ONLY,
+ /**
+ * Only the area where the input is reflected back to the user is shown; the area where the
+ * input is entered by the user is not shown.
+ */
+ OUTPUT_ONLY,
+ /** The entire user input area is hidden. */
+ NONE,
+}
+
/**
* Calculates an alpha for the user switcher and bouncer such that it's at `1` when the offset of
* the two reaches a stopping point but `0` in the middle of the transition.
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index 6491b70db99b..84e016791816 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -55,12 +55,12 @@ import androidx.compose.ui.unit.dp
import com.android.compose.animation.Easings
import com.android.compose.grid.VerticalGrid
import com.android.compose.modifiers.thenIf
-import com.android.systemui.res.R
import com.android.systemui.bouncer.ui.viewmodel.ActionButtonAppearance
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.res.R
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.DurationUnit
import kotlinx.coroutines.async
@@ -93,7 +93,10 @@ internal fun PinBouncer(
}
@Composable
-private fun PinPad(viewModel: PinBouncerViewModel) {
+fun PinPad(
+ viewModel: PinBouncerViewModel,
+ modifier: Modifier = Modifier,
+) {
val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState()
val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState()
@@ -112,6 +115,7 @@ private fun PinPad(viewModel: PinBouncerViewModel) {
columns = 3,
verticalSpacing = 12.dp,
horizontalSpacing = 20.dp,
+ modifier = modifier,
) {
repeat(9) { index ->
DigitButton(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
index 055ece328fc3..814ea31ad510 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
@@ -51,10 +51,10 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.android.compose.animation.Easings
import com.android.keyguard.PinShapeAdapter
-import com.android.systemui.res.R
import com.android.systemui.bouncer.ui.viewmodel.EntryToken.Digit
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PinInputViewModel
+import com.android.systemui.res.R
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.async
@@ -65,7 +65,10 @@ import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
@Composable
-fun PinInputDisplay(viewModel: PinBouncerViewModel) {
+fun PinInputDisplay(
+ viewModel: PinBouncerViewModel,
+ modifier: Modifier = Modifier,
+) {
val hintedPinLength: Int? by viewModel.hintedPinLength.collectAsState()
val shapeAnimations = rememberShapeAnimations(viewModel.pinShapes)
@@ -81,8 +84,8 @@ fun PinInputDisplay(viewModel: PinBouncerViewModel) {
// unifying into a single, more complex implementation.
when (val length = hintedPinLength) {
- null -> RegularPinInputDisplay(viewModel, shapeAnimations)
- else -> HintingPinInputDisplay(viewModel, shapeAnimations, length)
+ null -> RegularPinInputDisplay(viewModel, shapeAnimations, modifier)
+ else -> HintingPinInputDisplay(viewModel, shapeAnimations, length, modifier)
}
}
@@ -97,6 +100,7 @@ private fun HintingPinInputDisplay(
viewModel: PinBouncerViewModel,
shapeAnimations: ShapeAnimations,
hintedPinLength: Int,
+ modifier: Modifier = Modifier,
) {
val pinInput: PinInputViewModel by viewModel.pinInput.collectAsState()
// [ClearAll] marker pointing at the beginning of the current pin input.
@@ -151,7 +155,7 @@ private fun HintingPinInputDisplay(
LaunchedEffect(Unit) { playAnimation = true }
val dotColor = MaterialTheme.colorScheme.onSurfaceVariant
- Row(modifier = Modifier.heightIn(min = shapeAnimations.shapeSize)) {
+ Row(modifier = modifier.heightIn(min = shapeAnimations.shapeSize)) {
pinEntryDrawable.forEachIndexed { index, drawable ->
// Key the loop by [index] and [drawable], so that updating a shape drawable at the same
// index will play the new animation (by remembering a new [atEnd]).
@@ -183,6 +187,7 @@ private fun HintingPinInputDisplay(
private fun RegularPinInputDisplay(
viewModel: PinBouncerViewModel,
shapeAnimations: ShapeAnimations,
+ modifier: Modifier = Modifier,
) {
// Holds all currently [VisiblePinEntry] composables. This cannot be simply derived from
// `viewModel.pinInput` at composition, since deleting a pin entry needs to play a remove
@@ -226,7 +231,7 @@ private fun RegularPinInputDisplay(
}
}
- pinInputRow.Content()
+ pinInputRow.Content(modifier)
}
private class PinInputRow(
@@ -235,10 +240,11 @@ private class PinInputRow(
private val entries = mutableStateListOf<PinInputEntry>()
@Composable
- fun Content() {
+ fun Content(modifier: Modifier) {
Row(
modifier =
- Modifier.heightIn(min = shapeAnimations.shapeSize)
+ modifier
+ .heightIn(min = shapeAnimations.shapeSize)
// Pins overflowing horizontally should still be shown as scrolling.
.wrapContentSize(unbounded = true),
) {
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8780f58743cd..9a3c6d5b322f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3266,4 +3266,9 @@
<string name="privacy_dialog_active_app_usage_2">In use by <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> (<xliff:g id="attribution_label" example="For Wallet">%2$s</xliff:g> \u2022 <xliff:g id="proxy_label" example="Speech services">%3$s</xliff:g>)</string>
<!-- Label for recent app usage of a phone sensor with sub-attribution and proxy label in the privacy dialog [CHAR LIMIT=NONE] -->
<string name="privacy_dialog_recent_app_usage_2">Recently used by <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> (<xliff:g id="attribution_label" example="For Wallet">%2$s</xliff:g> \u2022 <xliff:g id="proxy_label" example="Speech services">%3$s</xliff:g>)</string>
+
+ <!-- Content description for keyboard backlight brightness dialog [CHAR LIMIT=NONE] -->
+ <string name="keyboard_backlight_dialog_title">Keyboard backlight</string>
+ <!-- Content description for keyboard backlight brightness value [CHAR LIMIT=NONE] -->
+ <string name="keyboard_backlight_value">Level %1$d of %2$d</string>
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java b/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java
index a14f97128662..f005af3780cb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java
@@ -28,6 +28,7 @@ import android.graphics.PixelFormat;
import android.graphics.RecordingCanvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.Looper;
import android.os.Trace;
import android.view.RenderNodeAnimator;
import android.view.View;
@@ -48,6 +49,7 @@ public class KeyButtonRipple extends Drawable {
private static final float GLOW_MAX_ALPHA_DARK = 0.1f;
private static final int ANIMATION_DURATION_SCALE = 350;
private static final int ANIMATION_DURATION_FADE = 450;
+ private static final int ANIMATION_DURATION_FADE_FAST = 80;
private static final Interpolator ALPHA_OUT_INTERPOLATOR =
new PathInterpolator(0f, 0f, 0.8f, 1f);
@@ -71,6 +73,9 @@ public class KeyButtonRipple extends Drawable {
private boolean mLastDark;
private boolean mDark;
private boolean mDelayTouchFeedback;
+ private boolean mSpeedUpNextFade;
+ // When non-null, this runs the next time this ripple is drawn invisibly.
+ private Runnable mOnInvisibleRunnable;
private final Interpolator mInterpolator = new LogInterpolator();
private boolean mSupportHardware;
@@ -112,6 +117,18 @@ public class KeyButtonRipple extends Drawable {
mDelayTouchFeedback = delay;
}
+ /** Next time we fade out (pressed==false), use a shorter duration than the standard. */
+ public void speedUpNextFade() {
+ mSpeedUpNextFade = true;
+ }
+
+ /**
+ * @param onInvisibleRunnable run after we are next drawn invisibly. Only used once.
+ */
+ void setOnInvisibleRunnable(Runnable onInvisibleRunnable) {
+ mOnInvisibleRunnable = onInvisibleRunnable;
+ }
+
public void setType(Type type) {
mType = type;
}
@@ -161,6 +178,11 @@ public class KeyButtonRipple extends Drawable {
} else {
drawSoftware(canvas);
}
+
+ if (!mPressed && !mVisible && mOnInvisibleRunnable != null) {
+ new Handler(Looper.getMainLooper()).post(mOnInvisibleRunnable);
+ mOnInvisibleRunnable = null;
+ }
}
@Override
@@ -270,7 +292,7 @@ public class KeyButtonRipple extends Drawable {
return true;
}
- public void setPressed(boolean pressed) {
+ private void setPressed(boolean pressed) {
if (mDark != mLastDark && pressed) {
mRipplePaint = null;
mLastDark = mDark;
@@ -350,7 +372,7 @@ public class KeyButtonRipple extends Drawable {
private void exitSoftware() {
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this, "glowAlpha", mGlowAlpha, 0f);
alphaAnimator.setInterpolator(ALPHA_OUT_INTERPOLATOR);
- alphaAnimator.setDuration(ANIMATION_DURATION_FADE);
+ alphaAnimator.setDuration(getFadeDuration());
alphaAnimator.addListener(mAnimatorListener);
alphaAnimator.start();
mRunningAnimations.add(alphaAnimator);
@@ -414,6 +436,12 @@ public class KeyButtonRipple extends Drawable {
return Math.min(size, mMaxWidth);
}
+ private int getFadeDuration() {
+ int duration = mSpeedUpNextFade ? ANIMATION_DURATION_FADE_FAST : ANIMATION_DURATION_FADE;
+ mSpeedUpNextFade = false;
+ return duration;
+ }
+
private void enterHardware() {
endAnimations("enterHardware", true /* cancel */);
mVisible = true;
@@ -471,7 +499,7 @@ public class KeyButtonRipple extends Drawable {
mPaintProp = CanvasProperty.createPaint(getRipplePaint());
final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPaintProp,
RenderNodeAnimator.PAINT_ALPHA, 0);
- opacityAnim.setDuration(ANIMATION_DURATION_FADE);
+ opacityAnim.setDuration(getFadeDuration());
opacityAnim.setInterpolator(ALPHA_OUT_INTERPOLATOR);
opacityAnim.addListener(mAnimatorListener);
opacityAnim.addListener(mExitHwTraceAnimator);
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 181aa5c1e648..f0915583f021 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -22,6 +22,7 @@ import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
import static com.android.keyguard.LockIconView.ICON_FINGERPRINT;
import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
+import static com.android.systemui.Flags.keyguardBottomAreaRefactor;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
@@ -459,7 +460,7 @@ public class LockIconViewController implements Dumpable {
private void updateLockIconLocation() {
final float scaleFactor = mAuthController.getScaleFactor();
final int scaledPadding = (int) (mDefaultPaddingPx * scaleFactor);
- if (mFeatureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)) {
+ if (keyguardBottomAreaRefactor()) {
mView.getLockIcon().setPadding(scaledPadding, scaledPadding, scaledPadding,
scaledPadding);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 77384c49882a..dd971b966e7f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -244,15 +244,6 @@ object Flags {
/** Keyguard Migration */
- /**
- * Migrate the bottom area to the new keyguard root view. Because there is no such thing as a
- * "bottom area" after this, this also breaks it up into many smaller, modular pieces.
- */
- // TODO(b/290652751): Tracking bug.
- @JvmField
- val MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA =
- unreleasedFlag("migrate_split_keyguard_bottom_area")
-
// TODO(b/297037052): Tracking bug.
@JvmField
val REMOVE_NPVC_BOTTOM_AREA_USAGE = unreleasedFlag("remove_npvc_bottom_area_usage")
@@ -264,10 +255,6 @@ object Flags {
// TODO(b/287268101): Tracking bug.
@JvmField val TRANSIT_CLOCK = releasedFlag("lockscreen_custom_transit_clock")
- /** Migrate the lock icon view to the new keyguard root view. */
- // TODO(b/286552209): Tracking bug.
- @JvmField val MIGRATE_LOCK_ICON = unreleasedFlag("migrate_lock_icon")
-
// TODO(b/288276738): Tracking bug.
@JvmField val WIDGET_ON_KEYGUARD = unreleasedFlag("widget_on_keyguard")
@@ -494,12 +481,6 @@ object Flags {
namespace = DeviceConfig.NAMESPACE_WINDOW_MANAGER,
)
- // TODO(b/254512674): Tracking Bug
- @Keep
- @JvmField
- val HIDE_NAVBAR_WINDOW =
- sysPropBooleanFlag("persist.wm.debug.hide_navbar_window", default = false)
-
@Keep
@JvmField
val WM_CAPTION_ON_SHELL =
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
index e16bb0bb8482..1e9be09bc3f3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -30,6 +30,7 @@ import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import android.view.Window
import android.view.WindowManager
+import android.view.accessibility.AccessibilityEvent
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
@@ -78,23 +79,29 @@ class KeyboardBacklightDialog(
private lateinit var stepProperties: StepViewProperties
@ColorInt
- var filledRectangleColor = getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
+ private val filledRectangleColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
@ColorInt
- var emptyRectangleColor =
+ private val emptyRectangleColor =
getColorFromStyle(com.android.internal.R.attr.materialColorOutlineVariant)
@ColorInt
- var backgroundColor = getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright)
+ private val backgroundColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright)
@ColorInt
- var defaultIconColor = getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary)
+ private val defaultIconColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary)
@ColorInt
- var defaultIconBackgroundColor =
+ private val defaultIconBackgroundColor =
getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
@ColorInt
- var dimmedIconColor = getColorFromStyle(com.android.internal.R.attr.materialColorOnSurface)
+ private val dimmedIconColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorOnSurface)
@ColorInt
- var dimmedIconBackgroundColor =
+ private val dimmedIconBackgroundColor =
getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceDim)
+ private val levelContentDescription = context.getString(R.string.keyboard_backlight_value)
+
init {
currentLevel = initialCurrentLevel
maxLevel = initialMaxLevel
@@ -103,6 +110,8 @@ class KeyboardBacklightDialog(
override fun onCreate(savedInstanceState: Bundle?) {
setUpWindowProperties(this)
setWindowPosition()
+ // title is used for a11y announcement
+ window?.setTitle(context.getString(R.string.keyboard_backlight_dialog_title))
updateResources()
rootView = buildRootView()
setContentView(rootView)
@@ -159,6 +168,12 @@ class KeyboardBacklightDialog(
currentLevel = current
updateIconTile()
updateStepColors()
+ updateAccessibilityInfo()
+ }
+
+ private fun updateAccessibilityInfo() {
+ rootView.contentDescription = String.format(levelContentDescription, currentLevel, maxLevel)
+ rootView.sendAccessibilityEvent(AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION)
}
private fun updateIconTile() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 61c8e1bbc1d8..1037b0eb4dfc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -27,6 +27,7 @@ import com.android.keyguard.LockIconView
import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardStatusViewComponent
import com.android.systemui.CoreStartable
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
@@ -113,7 +114,7 @@ constructor(
fun bindIndicationArea() {
indicationAreaHandle?.dispose()
- if (!featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (!keyguardBottomAreaRefactor()) {
keyguardRootView.findViewById<View?>(R.id.keyguard_indication_area)?.let {
keyguardRootView.removeView(it)
}
@@ -125,7 +126,6 @@ constructor(
keyguardIndicationAreaViewModel,
keyguardRootViewModel,
indicationController,
- featureFlags,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
index f20a66604ebf..1a8f62597037 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
@@ -22,9 +22,8 @@ import android.view.ViewGroup
import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.res.R
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -54,7 +53,6 @@ object KeyguardIndicationAreaBinder {
viewModel: KeyguardIndicationAreaViewModel,
keyguardRootViewModel: KeyguardRootViewModel,
indicationController: KeyguardIndicationController,
- featureFlags: FeatureFlags,
): DisposableHandle {
val indicationArea: ViewGroup = view.requireViewById(R.id.keyguard_indication_area)
indicationController.setIndicationArea(indicationArea)
@@ -71,7 +69,7 @@ object KeyguardIndicationAreaBinder {
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
keyguardRootViewModel.alpha.collect { alpha ->
indicationArea.apply {
this.importantForAccessibility =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 378656c8f4c2..1f74bb661135 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -33,6 +33,7 @@ import com.android.app.animation.Interpolators
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
import com.android.keyguard.KeyguardClockSwitch.MISSING_CLOCK_ID
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.common.shared.model.TintedIcon
@@ -111,7 +112,7 @@ object KeyguardRootViewBinder {
}
}
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
launch { viewModel.alpha.collect { alpha -> view.alpha = alpha } }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index b797c4b45445..bdd9a6bf3f79 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -41,6 +41,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isInvisible
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.animation.view.LaunchableImageView
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -156,7 +157,7 @@ constructor(
private val shortcutsBindings = mutableSetOf<KeyguardQuickAffordanceViewBinder.Binding>()
init {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
keyguardRootViewModel.enablePreviewMode()
quickAffordancesCombinedViewModel.enablePreviewMode(
initiallySelectedSlotId =
@@ -199,7 +200,7 @@ constructor(
setupKeyguardRootView(previewContext, rootView)
- if (!featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (!keyguardBottomAreaRefactor()) {
setUpBottomArea(rootView)
}
@@ -243,7 +244,7 @@ constructor(
}
fun onSlotSelected(slotId: String) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
quickAffordancesCombinedViewModel.onPreviewSlotSelected(slotId = slotId)
} else {
bottomAreaViewModel.onPreviewSlotSelected(slotId = slotId)
@@ -254,7 +255,7 @@ constructor(
isDestroyed = true
lockscreenSmartspaceController.disconnect()
disposables.forEach { it.dispose() }
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
shortcutsBindings.forEach { it.destroy() }
}
}
@@ -363,7 +364,7 @@ constructor(
disposables.add(
PreviewKeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
setupShortcuts(keyguardRootView)
}
setUpUdfps(previewContext, rootView)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
index 28e6a954a3d1..eb01d4f6f61c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
@@ -25,10 +25,9 @@ import androidx.constraintlayout.widget.ConstraintSet.LEFT
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.RIGHT
import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.res.R
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
@@ -41,7 +40,6 @@ class AlignShortcutsToUdfpsSection
@Inject
constructor(
@Main private val resources: Resources,
- private val featureFlags: FeatureFlags,
private val keyguardQuickAffordancesCombinedViewModel:
KeyguardQuickAffordancesCombinedViewModel,
private val keyguardRootViewModel: KeyguardRootViewModel,
@@ -50,14 +48,14 @@ constructor(
private val vibratorHelper: VibratorHelper,
) : BaseShortcutSection() {
override fun addViews(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
addLeftShortcut(constraintLayout)
addRightShortcut(constraintLayout)
}
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
leftShortcutHandle =
KeyguardQuickAffordanceViewBinder.bind(
constraintLayout.requireViewById(R.id.start_button),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt
index 9371d4e2d465..20cb9b0576db 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt
@@ -29,9 +29,8 @@ import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.res.R
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardAmbientIndicationAreaViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardAmbientIndicationViewModel
@@ -42,14 +41,13 @@ class DefaultAmbientIndicationAreaSection
@Inject
constructor(
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- private val featureFlags: FeatureFlags,
private val keyguardAmbientIndicationViewModel: KeyguardAmbientIndicationViewModel,
private val keyguardRootViewModel: KeyguardRootViewModel,
) : KeyguardSection() {
private var ambientIndicationAreaHandle: KeyguardAmbientIndicationAreaViewBinder.Binding? = null
override fun addViews(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
val view =
LayoutInflater.from(constraintLayout.context)
.inflate(R.layout.ambient_indication, constraintLayout, false)
@@ -59,7 +57,7 @@ constructor(
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
ambientIndicationAreaHandle =
KeyguardAmbientIndicationAreaViewBinder.bind(
constraintLayout,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
index 755549b5478b..ace970a01054 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
@@ -29,6 +29,7 @@ import androidx.constraintlayout.widget.ConstraintSet
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconView
import com.android.keyguard.LockIconViewController
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.biometrics.AuthController
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -60,7 +61,7 @@ constructor(
private val deviceEntryIconViewId = R.id.device_entry_icon_view
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON) &&
+ if (!keyguardBottomAreaRefactor() &&
!featureFlags.isEnabled(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS)
) {
return
@@ -74,7 +75,7 @@ constructor(
if (featureFlags.isEnabled(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS)) {
DeviceEntryIconView(context, null).apply { id = deviceEntryIconViewId }
} else {
- // Flags.MIGRATE_LOCK_ICON
+ // keyguardBottomAreaRefactor()
LockIconView(context, null).apply { id = R.id.lock_icon_view }
}
constraintLayout.addView(view)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
index 623eac013a35..8aef7c23b45d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
@@ -21,9 +21,8 @@ import android.content.Context
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.res.R
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder
import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea
@@ -40,27 +39,25 @@ constructor(
private val keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel,
private val keyguardRootViewModel: KeyguardRootViewModel,
private val indicationController: KeyguardIndicationController,
- private val featureFlags: FeatureFlags,
) : KeyguardSection() {
private val indicationAreaViewId = R.id.keyguard_indication_area
private var indicationAreaHandle: DisposableHandle? = null
override fun addViews(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
val view = KeyguardIndicationArea(context, null)
constraintLayout.addView(view)
}
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
indicationAreaHandle =
KeyguardIndicationAreaBinder.bind(
constraintLayout,
keyguardIndicationAreaViewModel,
keyguardRootViewModel,
indicationController,
- featureFlags,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
index 6fd13e0931aa..9a33f08386a3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
@@ -28,6 +28,7 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
import androidx.core.view.isVisible
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.res.R
import com.android.systemui.animation.view.LaunchableLinearLayout
import com.android.systemui.dagger.qualifiers.Main
@@ -45,7 +46,6 @@ class DefaultSettingsPopupMenuSection
@Inject
constructor(
@Main private val resources: Resources,
- private val featureFlags: FeatureFlags,
private val keyguardSettingsMenuViewModel: KeyguardSettingsMenuViewModel,
private val vibratorHelper: VibratorHelper,
private val activityStarter: ActivityStarter,
@@ -53,7 +53,7 @@ constructor(
private var settingsPopupMenuHandle: DisposableHandle? = null
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (!keyguardBottomAreaRefactor()) {
return
}
val view =
@@ -68,7 +68,7 @@ constructor(
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
settingsPopupMenuHandle =
KeyguardSettingsViewBinder.bind(
constraintLayout.requireViewById<View>(R.id.keyguard_settings_button),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
index a67912017e54..0f6a966aad2e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
@@ -24,6 +24,7 @@ import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
import androidx.constraintlayout.widget.ConstraintSet.LEFT
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.RIGHT
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.res.R
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
@@ -40,7 +41,6 @@ class DefaultShortcutsSection
@Inject
constructor(
@Main private val resources: Resources,
- private val featureFlags: FeatureFlags,
private val keyguardQuickAffordancesCombinedViewModel:
KeyguardQuickAffordancesCombinedViewModel,
private val keyguardRootViewModel: KeyguardRootViewModel,
@@ -49,14 +49,14 @@ constructor(
private val vibratorHelper: VibratorHelper,
) : BaseShortcutSection() {
override fun addViews(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
addLeftShortcut(constraintLayout)
addRightShortcut(constraintLayout)
}
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
leftShortcutHandle =
KeyguardQuickAffordanceViewBinder.bind(
constraintLayout.requireViewById(R.id.start_button),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
index 980cc1b8ebe1..2327c028970b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
@@ -16,9 +16,8 @@
package com.android.systemui.keyguard.ui.viewmodel
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.doze.util.BurnInHelperWrapper
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import javax.inject.Inject
@@ -36,7 +35,6 @@ constructor(
keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel,
private val burnInHelperWrapper: BurnInHelperWrapper,
private val shortcutsCombinedViewModel: KeyguardQuickAffordancesCombinedViewModel,
- private val featureFlags: FeatureFlags,
) {
/** Notifies when a new configuration is set */
@@ -47,7 +45,7 @@ constructor(
/** An observable for whether the indication area should be padded. */
val isIndicationAreaPadded: Flow<Boolean> =
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
combine(shortcutsCombinedViewModel.startButton, shortcutsCombinedViewModel.endButton) {
startButtonModel,
endButtonModel ->
@@ -64,7 +62,7 @@ constructor(
}
/** An observable for the x-offset by which the indication area should be translated. */
val indicationAreaTranslationX: Flow<Float> =
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
keyguardInteractor.clockPosition.map { it.x.toFloat() }.distinctUntilChanged()
} else {
bottomAreaInteractor.clockPosition.map { it.x.toFloat() }.distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index a985236cb38e..5e3a166f5f35 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -1383,7 +1383,17 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
args.putInt(
AssistManager.INVOCATION_TYPE_KEY,
AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
- mAssistManagerLazy.get().startAssist(args);
+ // If Launcher has requested to override long press home, add a delay for the ripple.
+ // TODO(b/304146255): Remove this delay once we can exclude 3-button nav from screenshot.
+ boolean delayAssistInvocation = mAssistManagerLazy.get().shouldOverrideAssist(
+ AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
+ // In practice, I think v should always be a KeyButtonView, but just being safe.
+ if (delayAssistInvocation && v instanceof KeyButtonView) {
+ ((KeyButtonView) v).setOnRippleInvisibleRunnable(
+ () -> mAssistManagerLazy.get().startAssist(args));
+ } else {
+ mAssistManagerLazy.get().startAssist(args);
+ }
mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::awakenDreams);
mView.abortCurrentGesture();
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
index 2928cceb35aa..79aedffc4498 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
@@ -21,6 +21,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG;
import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen;
+import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -49,8 +50,6 @@ 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.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.settings.DisplayTracker;
@@ -83,7 +82,6 @@ public class NavigationBarControllerImpl implements
private final Context mContext;
private final Handler mHandler;
private final NavigationBarComponent.Factory mNavigationBarComponentFactory;
- private FeatureFlags mFeatureFlags;
private final SecureSettings mSecureSettings;
private final DisplayTracker mDisplayTracker;
private final DisplayManager mDisplayManager;
@@ -118,13 +116,11 @@ public class NavigationBarControllerImpl implements
TaskStackChangeListeners taskStackChangeListeners,
Optional<Pip> pipOptional,
Optional<BackAnimation> backAnimation,
- FeatureFlags featureFlags,
SecureSettings secureSettings,
DisplayTracker displayTracker) {
mContext = context;
mHandler = mainHandler;
mNavigationBarComponentFactory = navigationBarComponentFactory;
- mFeatureFlags = featureFlags;
mSecureSettings = secureSettings;
mDisplayTracker = displayTracker;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
@@ -248,8 +244,8 @@ public class NavigationBarControllerImpl implements
/** @return {@code true} if taskbar is enabled, false otherwise */
private boolean initializeTaskbarIfNecessary() {
// Enable for large screens or (phone AND flag is set); assuming phone = !mIsLargeScreen
- boolean taskbarEnabled = (mIsLargeScreen || mFeatureFlags.isEnabled(
- Flags.HIDE_NAVBAR_WINDOW)) && shouldCreateNavBarAndTaskBar(mContext.getDisplayId());
+ boolean taskbarEnabled = (mIsLargeScreen || enableTaskbarNavbarUnification())
+ && shouldCreateNavBarAndTaskBar(mContext.getDisplayId());
if (taskbarEnabled) {
Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary");
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index bc4f7f2513ce..258208d074e3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -62,7 +62,6 @@ import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.res.R;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.ContextualButton;
@@ -73,6 +72,7 @@ import com.android.systemui.navigationbar.buttons.NearestTouchFrame;
import com.android.systemui.navigationbar.buttons.RotationContextButton;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.recents.Recents;
+import com.android.systemui.res.R;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.rotation.FloatingRotationButton;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
index dcf1a8e98f1c..6ec46f627264 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
@@ -58,8 +58,9 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
+import com.android.systemui.assist.AssistManager;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.res.R;
import com.android.systemui.shared.system.QuickStepContract;
public class KeyButtonView extends ImageView implements ButtonInterface {
@@ -439,11 +440,22 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
if (mCode != KeyEvent.KEYCODE_UNKNOWN) {
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
}
+ // When aborting long-press home and Launcher has requested to override it, fade out the
+ // ripple more quickly.
+ if (mCode == KeyEvent.KEYCODE_HOME && Dependency.get(AssistManager.class)
+ .shouldOverrideAssist(AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS)) {
+ mRipple.speedUpNextFade();
+ }
setPressed(false);
mRipple.abortDelayedRipple();
mGestureAborted = true;
}
+ /** Run when the ripple for this button is next invisible. Only used once. */
+ public void setOnRippleInvisibleRunnable(Runnable onRippleInvisibleRunnable) {
+ mRipple.setOnInvisibleRunnable(onRippleInvisibleRunnable);
+ }
+
@Override
public void setDarkIntensity(float darkIntensity) {
mDarkIntensity = darkIntensity;
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 093d098de3e3..d9a8080a1e83 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -325,7 +325,13 @@ constructor(
} else {
// TODO(b/278729185): Replace fire and forget service with a bounded service.
val intent = NoteTaskControllerUpdateService.createIntent(context)
- context.startServiceAsUser(intent, user)
+ try {
+ // If the user is stopped before 'startServiceAsUser' kicks-in, a
+ // 'SecurityException' will be thrown.
+ context.startServiceAsUser(intent, user)
+ } catch (e: SecurityException) {
+ debugLog(error = e) { "Unable to start 'NoteTaskControllerUpdateService'." }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt
index 4dc1c82c5282..2074a14d323f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt
@@ -24,7 +24,6 @@ import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.QSTilesLogBuffers
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.viewmodel.QSTileState
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
import com.android.systemui.statusbar.StatusBarState
@@ -34,7 +33,7 @@ import javax.inject.Inject
class QSTileLogger
@Inject
constructor(
- @QSTilesLogBuffers logBuffers: Map<TileSpec, LogBuffer>,
+ @QSTilesLogBuffers logBuffers: Map<String, LogBuffer>,
private val factory: LogBufferFactory,
private val mStatusBarStateController: StatusBarStateController,
) {
@@ -163,22 +162,15 @@ constructor(
private fun TileSpec.getLogBuffer(): LogBuffer =
synchronized(logBufferCache) {
- logBufferCache.getOrPut(this) {
+ logBufferCache.getOrPut(this.spec) {
factory.create(
- "QSTileLog_${this.getLogTag()}",
+ this.getLogTag(),
BUFFER_MAX_SIZE /* maxSize */,
false /* systrace */
)
}
}
- private fun DataUpdateTrigger.toLogString(): String =
- when (this) {
- is DataUpdateTrigger.ForceUpdate -> "force"
- is DataUpdateTrigger.InitialRequest -> "init"
- is DataUpdateTrigger.UserInput<*> -> input.action.toLogString()
- }
-
private fun QSTileUserAction.toLogString(): String =
when (this) {
is QSTileUserAction.Click -> "click"
@@ -198,7 +190,7 @@ constructor(
"]"
private companion object {
- const val TAG_FORMAT_PREFIX = "QSLog"
+ const val TAG_FORMAT_PREFIX = "QSLog_tile_"
const val DATA_MAX_LENGTH = 50
const val BUFFER_MAX_SIZE = 25
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
index 0bee48fd01ab..12a083e990f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
@@ -39,7 +39,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
-import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -47,6 +46,8 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.cancellable
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
@@ -57,6 +58,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/**
* Provides a hassle-free way to implement new tiles according to current System UI architecture
@@ -83,10 +85,8 @@ class QSTileViewModelImpl<DATA_TYPE>(
private val users: MutableStateFlow<UserHandle> =
MutableStateFlow(userRepository.getSelectedUserInfo().userHandle)
- private val userInputs: MutableSharedFlow<QSTileUserAction> =
- MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
- private val forceUpdates: MutableSharedFlow<Unit> =
- MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ private val userInputs: MutableSharedFlow<QSTileUserAction> = MutableSharedFlow()
+ private val forceUpdates: MutableSharedFlow<Unit> = MutableSharedFlow()
private val spec
get() = config.tileSpec
@@ -130,7 +130,7 @@ class QSTileViewModelImpl<DATA_TYPE>(
tileData.replayCache.isNotEmpty(),
state.replayCache.isNotEmpty()
)
- userInputs.tryEmit(userAction)
+ tileScope.launch { userInputs.emit(userAction) }
}
override fun destroy() {
@@ -151,11 +151,16 @@ class QSTileViewModelImpl<DATA_TYPE>(
emit(DataUpdateTrigger.InitialRequest)
qsTileLogger.logInitialRequest(spec)
}
+ .shareIn(tileScope, SharingStarted.WhileSubscribed())
tileDataInteractor()
.tileData(user, updateTriggers)
+ // combine makes sure updateTriggers is always listened even if
+ // tileDataInteractor#tileData doesn't flatMapLatest on it
+ .combine(updateTriggers) { data, _ -> data }
.cancellable()
.flowOn(backgroundDispatcher)
}
+ .distinctUntilChanged()
.shareIn(
tileScope,
SharingStarted.WhileSubscribed(),
@@ -171,8 +176,8 @@ class QSTileViewModelImpl<DATA_TYPE>(
*
* Subscribing to the result flow twice will result in doubling all actions, logs and analytics.
*/
- private fun userInputFlow(user: UserHandle): Flow<DataUpdateTrigger> {
- return userInputs
+ private fun userInputFlow(user: UserHandle): Flow<DataUpdateTrigger> =
+ userInputs
.filterFalseActions()
.filterByPolicy(user)
.throttle(CLICK_THROTTLE_DURATION, systemClock)
@@ -187,7 +192,6 @@ class QSTileViewModelImpl<DATA_TYPE>(
}
.onEach { userActionInteractor().handleInput(it.input) }
.flowOn(backgroundDispatcher)
- }
private fun Flow<QSTileUserAction>.filterByPolicy(user: UserHandle): Flow<QSTileUserAction> =
config.policy.let { policy ->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt
index c4d7dfba23bf..18a4e2d26e89 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt
@@ -36,9 +36,9 @@ data class QSTileConfig(
*/
sealed interface QSTileUIConfig {
- val tileIconRes: Int
+ val iconRes: Int
@DrawableRes get
- val tileLabelRes: Int
+ val labelRes: Int
@StringRes get
/**
@@ -46,16 +46,16 @@ sealed interface QSTileUIConfig {
* of [Resource]. Returns [Resources.ID_NULL] for each field.
*/
data object Empty : QSTileUIConfig {
- override val tileIconRes: Int
+ override val iconRes: Int
get() = Resources.ID_NULL
- override val tileLabelRes: Int
+ override val labelRes: Int
get() = Resources.ID_NULL
}
/** Config containing actual icon and label resources. */
data class Resource(
- @StringRes override val tileIconRes: Int,
- @StringRes override val tileLabelRes: Int,
+ @DrawableRes override val iconRes: Int,
+ @StringRes override val labelRes: Int,
) : QSTileUIConfig
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
index dc5ccccd6f7f..30b87cc9e662 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.viewmodel
+import android.content.Context
import android.service.quicksettings.Tile
import com.android.systemui.common.shared.model.Icon
@@ -41,11 +42,19 @@ data class QSTileState(
companion object {
+ fun build(
+ context: Context,
+ config: QSTileUIConfig,
+ build: Builder.() -> Unit
+ ): QSTileState =
+ build(
+ { Icon.Resource(config.iconRes, null) },
+ context.getString(config.labelRes),
+ build,
+ )
+
fun build(icon: () -> Icon, label: CharSequence, build: Builder.() -> Unit): QSTileState =
Builder(icon, label).apply(build).build()
-
- fun build(icon: Icon, label: CharSequence, build: Builder.() -> Unit): QSTileState =
- build({ icon }, label, build)
}
enum class ActivationState(val legacyState: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
index efa6da764e6e..771d07c35cc3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
@@ -192,7 +192,7 @@ constructor(
with(qsTileViewModel.config.uiConfig) {
when (this) {
is QSTileUIConfig.Empty -> qsTileViewModel.currentState?.label ?: ""
- is QSTileUIConfig.Resource -> context.getString(tileLabelRes)
+ is QSTileUIConfig.Resource -> context.getString(labelRes)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
index 018f31b0c3d6..e40d2b7fd659 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -17,6 +17,7 @@
package com.android.systemui.scene.shared.flag
import androidx.annotation.VisibleForTesting
+import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.Flags.sceneContainer
import com.android.systemui.compose.ComposeFacade
@@ -57,8 +58,6 @@ constructor(
@VisibleForTesting
val classicFlagTokens: List<Flag<Boolean>> =
listOf(
- Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA,
- Flags.MIGRATE_LOCK_ICON,
Flags.MIGRATE_NSSL,
Flags.MIGRATE_KEYGUARD_STATUS_VIEW,
Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW,
@@ -72,6 +71,10 @@ constructor(
flagName = AConfigFlags.FLAG_SCENE_CONTAINER,
flagValue = sceneContainer(),
),
+ AconfigFlagMustBeEnabled(
+ flagName = AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR,
+ flagValue = keyguardBottomAreaRefactor(),
+ ),
) +
classicFlagTokens.map { flagToken -> FlagMustBeEnabled(flagToken) } +
listOf(ComposeMustBeAvailable(), CompileTimeFlagMustBeEnabled())
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 85a4a7e45b32..823caa0805bd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -24,6 +24,7 @@ import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
+import static com.android.systemui.Flags.keyguardBottomAreaRefactor;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.GENERIC;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -1070,7 +1071,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mQsController.init();
mShadeHeadsUpTracker.addTrackingHeadsUpListener(
mNotificationStackScrollLayoutController::setTrackingHeadsUp);
- if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (!keyguardBottomAreaRefactor()) {
setKeyguardBottomArea(mView.findViewById(R.id.keyguard_bottom_area));
}
@@ -1409,7 +1410,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
updateViewControllers(userAvatarView, keyguardUserSwitcherView);
- if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (!keyguardBottomAreaRefactor()) {
// Update keyguard bottom area
int index = mView.indexOfChild(mKeyguardBottomArea);
mView.removeView(mKeyguardBottomArea);
@@ -1443,7 +1444,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mBarState);
}
- if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (!keyguardBottomAreaRefactor()) {
setKeyguardBottomAreaVisibility(mBarState, false);
}
@@ -1456,7 +1457,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
private void initBottomArea() {
- if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (!keyguardBottomAreaRefactor()) {
mKeyguardBottomArea.init(
mKeyguardBottomAreaViewModel,
mFalsingManager,
@@ -1643,7 +1644,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mKeyguardStatusViewController.setLockscreenClockY(
mClockPositionAlgorithm.getExpandedPreferredClockY());
}
- if (mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
mKeyguardInteractor.setClockPosition(
mClockPositionResult.clockX, mClockPositionResult.clockY);
} else {
@@ -2710,7 +2711,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
float alpha = Math.min(expansionAlpha, 1 - mQsController.computeExpansionFraction());
alpha *= mBottomAreaShadeAlpha;
- if (mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
mKeyguardInteractor.setAlpha(alpha);
} else {
mKeyguardBottomAreaInteractor.setAlpha(alpha);
@@ -2936,7 +2937,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
private void updateDozingVisibilities(boolean animate) {
- if (mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
mKeyguardInteractor.setAnimateDozingTransitions(animate);
} else {
mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
@@ -3144,7 +3145,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mDozing = dozing;
// TODO (b/) make listeners for this
mNotificationStackScrollLayoutController.setDozing(mDozing, animate);
- if (mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
mKeyguardInteractor.setAnimateDozingTransitions(animate);
} else {
mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
@@ -4441,7 +4442,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
goingToFullShade,
mBarState);
- if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (!keyguardBottomAreaRefactor()) {
setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
}
@@ -4698,7 +4699,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mKeyguardStatusViewController.setAlpha(alpha);
stackScroller.setAlpha(alpha);
- if (mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+ if (keyguardBottomAreaRefactor()) {
mKeyguardInteractor.setAlpha(alpha);
} else {
mKeyguardBottomAreaInteractor.setAlpha(alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 121aa425e67c..e9779cd02760 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -52,6 +52,7 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.DumpsysTableLogger;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -59,6 +60,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.res.R;
import com.android.systemui.scene.ui.view.WindowRootViewComponent;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
@@ -150,6 +152,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
ConfigurationController configurationController,
KeyguardViewMediator keyguardViewMediator,
KeyguardBypassController keyguardBypassController,
+ @Main Executor mainExecutor,
@Background Executor backgroundExecutor,
SysuiColorExtractor colorExtractor,
DumpManager dumpManager,
@@ -158,7 +161,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
AuthController authController,
Lazy<ShadeInteractor> shadeInteractorLazy,
ShadeWindowLogger logger,
- Lazy<SelectedUserInteractor> userInteractor) {
+ Lazy<SelectedUserInteractor> userInteractor,
+ UserTracker userTracker) {
mContext = context;
mWindowRootViewComponentFactory = windowRootViewComponentFactory;
mWindowManager = windowManager;
@@ -184,7 +188,9 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
.addCallback(mStateListener,
SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
configurationController.addCallback(this);
-
+ if (android.multiuser.Flags.useAllCpusDuringUserSwitch()) {
+ userTracker.addCallback(mUserTrackerCallback, mainExecutor);
+ }
float desiredPreferredRefreshRate = context.getResources()
.getInteger(R.integer.config_keyguardRefreshRate);
float actualPreferredRefreshRate = -1;
@@ -572,6 +578,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
state.qsExpanded,
state.headsUpNotificationShowing,
state.lightRevealScrimOpaque,
+ state.isSwitchingUsers,
state.forceWindowCollapsed,
state.forceDozeBrightness,
state.forceUserActivity,
@@ -624,7 +631,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
private void applyHasTopUi(NotificationShadeWindowState state) {
- mHasTopUiChanged = !state.componentsForcingTopUi.isEmpty() || isExpanded(state);
+ mHasTopUiChanged = !state.componentsForcingTopUi.isEmpty() || isExpanded(state)
+ || state.isSwitchingUsers;
}
private void applyNotTouchable(NotificationShadeWindowState state) {
@@ -954,4 +962,24 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
setDreaming(isDreaming);
}
};
+
+ private final UserTracker.Callback mUserTrackerCallback = new UserTracker.Callback() {
+ @Override
+ public void onBeforeUserSwitching(int newUser) {
+ setIsSwitchingUsers(true);
+ }
+
+ @Override
+ public void onUserChanged(int newUser, Context userContext) {
+ setIsSwitchingUsers(false);
+ }
+
+ private void setIsSwitchingUsers(boolean isSwitchingUsers) {
+ if (mCurrentState.isSwitchingUsers == isSwitchingUsers) {
+ return;
+ }
+ mCurrentState.isSwitchingUsers = isSwitchingUsers;
+ apply(mCurrentState);
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
index fbe164a8077f..0b20170834d8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
@@ -40,6 +40,7 @@ class NotificationShadeWindowState(
@JvmField var qsExpanded: Boolean = false,
@JvmField var headsUpNotificationShowing: Boolean = false,
@JvmField var lightRevealScrimOpaque: Boolean = false,
+ @JvmField var isSwitchingUsers: Boolean = false,
@JvmField var forceWindowCollapsed: Boolean = false,
@JvmField var forceDozeBrightness: Boolean = false,
// TODO: forceUserActivity seems to be unused, delete?
@@ -78,6 +79,7 @@ class NotificationShadeWindowState(
qsExpanded.toString(),
headsUpNotificationShowing.toString(),
lightRevealScrimOpaque.toString(),
+ isSwitchingUsers.toString(),
forceWindowCollapsed.toString(),
forceDozeBrightness.toString(),
forceUserActivity.toString(),
@@ -117,6 +119,7 @@ class NotificationShadeWindowState(
qsExpanded: Boolean,
headsUpShowing: Boolean,
lightRevealScrimOpaque: Boolean,
+ isSwitchingUsers: Boolean,
forceCollapsed: Boolean,
forceDozeBrightness: Boolean,
forceUserActivity: Boolean,
@@ -145,6 +148,7 @@ class NotificationShadeWindowState(
this.qsExpanded = qsExpanded
this.headsUpNotificationShowing = headsUpShowing
this.lightRevealScrimOpaque = lightRevealScrimOpaque
+ this.isSwitchingUsers = isSwitchingUsers
this.forceWindowCollapsed = forceCollapsed
this.forceDozeBrightness = forceDozeBrightness
this.forceUserActivity = forceUserActivity
@@ -191,6 +195,7 @@ class NotificationShadeWindowState(
"qsExpanded",
"headsUpShowing",
"lightRevealScrimOpaque",
+ "isSwitchingUsers",
"forceCollapsed",
"forceDozeBrightness",
"forceUserActivity",
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index 966ff35d0109..ec90a8d6ad59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -90,10 +90,10 @@ public abstract class StackScrollerDecorView extends ExpandableView {
} else {
setWillBeGone(true);
}
- setContentVisible(visible, true /* animate */, null /* runAfter */);
+ setContentVisible(visible, true /* animate */, null /* onAnimationEnded */);
} else {
setVisibility(visible ? VISIBLE : GONE);
- setContentVisible(visible, false /* animate */, null /* runAfter */);
+ setContentVisible(visible, false /* animate */, null /* onAnimationEnded */);
setWillBeGone(false);
notifyHeightChanged(false /* needsAnimation */);
}
@@ -108,7 +108,7 @@ public abstract class StackScrollerDecorView extends ExpandableView {
* Change content visibility to {@code visible}, animated.
*/
public void setContentVisibleAnimated(boolean visible) {
- setContentVisible(visible, true /* animate */, null /* runAfter */);
+ setContentVisible(visible, true /* animate */, null /* onAnimationEnded */);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index 5c1149bafb2f..580431a13d1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -53,7 +53,7 @@ public class SectionHeaderView extends StackScrollerDecorView {
mContents = requireViewById(R.id.content);
bindContents();
super.onFinishInflate();
- setVisible(true /* nowVisible */, false /* animate */);
+ setVisible(true /* visible */, false /* animate */);
}
private void bindContents() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index d61ca697642a..1d4f2cbe6b64 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -21,7 +21,6 @@ import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
-import static com.android.systemui.flags.Flags.MIGRATE_LOCK_ICON;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
@@ -39,6 +38,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.AuthRippleController;
@@ -148,9 +148,10 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
when(mStatusBarStateController.isDozing()).thenReturn(false);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+ mSetFlagsRule.disableFlags(Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR);
+
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(FACE_AUTH_REFACTOR, false);
- mFeatureFlags.set(MIGRATE_LOCK_ICON, false);
mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
mFeatureFlags.set(LOCKSCREEN_ENABLE_LANDSCAPE, false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt
new file mode 100644
index 000000000000..8b572eb3d906
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui.view
+
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import android.view.accessibility.AccessibilityEvent
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWithLooper
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyboardBacklightDialogTest : SysuiTestCase() {
+
+ private lateinit var dialog: KeyboardBacklightDialog
+ private lateinit var rootView: View
+ private val descriptionString = context.getString(R.string.keyboard_backlight_value)
+
+ @Before
+ fun setUp() {
+ dialog =
+ KeyboardBacklightDialog(context, initialCurrentLevel = 0, initialMaxLevel = MAX_LEVEL)
+ dialog.show()
+ rootView = dialog.requireViewById(R.id.keyboard_backlight_dialog_container)
+ }
+
+ @Test
+ fun rootViewContentDescription_containsInitialLevel() {
+ assertThat(rootView.contentDescription).isEqualTo(contentDescriptionForLevel(INITIAL_LEVEL))
+ }
+
+ @Test
+ fun contentDescriptionUpdated_afterEveryLevelUpdate() {
+ val events = startCollectingAccessibilityEvents(rootView)
+
+ dialog.updateState(current = 1, max = MAX_LEVEL)
+
+ assertThat(rootView.contentDescription).isEqualTo(contentDescriptionForLevel(1))
+ assertThat(events).contains(AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION)
+ }
+
+ private fun contentDescriptionForLevel(level: Int): String {
+ return String.format(descriptionString, level, MAX_LEVEL)
+ }
+
+ private fun startCollectingAccessibilityEvents(rootView: View): MutableList<Int> {
+ val events = mutableListOf<Int>()
+ rootView.accessibilityDelegate =
+ object : View.AccessibilityDelegate() {
+ override fun sendAccessibilityEvent(host: View, eventType: Int) {
+ super.sendAccessibilityEvent(host, eventType)
+ events.add(eventType)
+ }
+ }
+ return events
+ }
+
+ companion object {
+ private const val MAX_LEVEL = 5
+ private const val INITIAL_LEVEL = 0
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 814a317a72f8..b16c3520d978 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -194,6 +194,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Captor ArgumentCaptor<KeyguardUpdateMonitorCallback>
mKeyguardUpdateMonitorCallbackCaptor;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
+ private FakeExecutor mUiMainExecutor = new FakeExecutor(new FakeSystemClock());
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private FalsingCollectorFake mFalsingCollector;
@@ -247,6 +248,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mConfigurationController,
mViewMediator,
mKeyguardBypassController,
+ mUiMainExecutor,
mUiBgExecutor,
mColorExtractor,
mDumpManager,
@@ -255,7 +257,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mAuthController,
() -> mShadeInteractor,
mShadeWindowLogger,
- () -> mSelectedUserInteractor);
+ () -> mSelectedUserInteractor,
+ mUserTracker);
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false);
mFeatureFlags.set(Flags.REFACTOR_GETCURRENTUSER, true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
index c7f7c3c3cecf..71313c8a5bf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
@@ -26,6 +26,7 @@ import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconViewController
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
@@ -59,9 +60,11 @@ class DefaultDeviceEntryIconSectionTest : SysuiTestCase() {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
+
featureFlags =
FakeFeatureFlagsClassic().apply {
- set(Flags.MIGRATE_LOCK_ICON, false)
set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, false)
set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false)
}
@@ -81,7 +84,7 @@ class DefaultDeviceEntryIconSectionTest : SysuiTestCase() {
@Test
fun addViewsConditionally_migrateFlagOn() {
- featureFlags.set(Flags.MIGRATE_LOCK_ICON, true)
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
val constraintLayout = ConstraintLayout(context, null)
underTest.addViews(constraintLayout)
assertThat(constraintLayout.childCount).isGreaterThan(0)
@@ -89,7 +92,7 @@ class DefaultDeviceEntryIconSectionTest : SysuiTestCase() {
@Test
fun addViewsConditionally_migrateAndRefactorFlagsOn() {
- featureFlags.set(Flags.MIGRATE_LOCK_ICON, true)
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
val constraintLayout = ConstraintLayout(context, null)
underTest.addViews(constraintLayout)
@@ -98,7 +101,7 @@ class DefaultDeviceEntryIconSectionTest : SysuiTestCase() {
@Test
fun addViewsConditionally_migrateFlagOff() {
- featureFlags.set(Flags.MIGRATE_LOCK_ICON, false)
+ mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, false)
val constraintLayout = ConstraintLayout(context, null)
underTest.addViews(constraintLayout)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
index 8b8c59b78e46..8dd33d5e60bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
@@ -23,12 +23,10 @@ import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
+import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.statusbar.KeyguardIndicationController
-import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -43,7 +41,6 @@ class DefaultIndicationAreaSectionTest : SysuiTestCase() {
@Mock private lateinit var keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel
@Mock private lateinit var keyguardRootViewModel: KeyguardRootViewModel
@Mock private lateinit var indicationController: KeyguardIndicationController
- @Mock private lateinit var featureFlags: FeatureFlags
private lateinit var underTest: DefaultIndicationAreaSection
@@ -56,13 +53,12 @@ class DefaultIndicationAreaSectionTest : SysuiTestCase() {
keyguardIndicationAreaViewModel,
keyguardRootViewModel,
indicationController,
- featureFlags,
)
}
@Test
fun addViewsConditionally() {
- whenever(featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)).thenReturn(true)
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
val constraintLayout = ConstraintLayout(context, null)
underTest.addViews(constraintLayout)
assertThat(constraintLayout.childCount).isGreaterThan(0)
@@ -70,7 +66,7 @@ class DefaultIndicationAreaSectionTest : SysuiTestCase() {
@Test
fun addViewsConditionally_migrateFlagOff() {
- whenever(featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)).thenReturn(false)
+ mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
val constraintLayout = ConstraintLayout(context, null)
underTest.addViews(constraintLayout)
assertThat(constraintLayout.childCount).isEqualTo(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt
index 34d93fc8788e..88a4aa509c37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt
@@ -20,7 +20,6 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.doze.util.BurnInHelperWrapper
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
@@ -29,7 +28,6 @@ import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -40,14 +38,12 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.MockitoAnnotations
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class KeyguardIndicationAreaViewModelTest : SysuiTestCase() {
@Mock private lateinit var burnInHelperWrapper: BurnInHelperWrapper
@Mock private lateinit var shortcutsCombinedViewModel: KeyguardQuickAffordancesCombinedViewModel
- @Mock private lateinit var featureFlags: FeatureFlags
private lateinit var underTest: KeyguardIndicationAreaViewModel
private lateinit var repository: FakeKeyguardRepository
@@ -87,7 +83,6 @@ class KeyguardIndicationAreaViewModelTest : SysuiTestCase() {
keyguardBottomAreaViewModel = bottomAreaViewModel,
burnInHelperWrapper = burnInHelperWrapper,
shortcutsCombinedViewModel = shortcutsCombinedViewModel,
- featureFlags = featureFlags,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
index 1c6cc873c547..25d141997734 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
@@ -29,6 +29,7 @@ import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dock.DockManagerFake
+import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
@@ -123,9 +124,11 @@ class KeyguardQuickAffordancesCombinedViewModelTest : SysuiTestCase() {
FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER)
dockManager = DockManagerFake()
biometricSettingsRepository = FakeBiometricSettingsRepository()
+
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
+
val featureFlags =
FakeFeatureFlags().apply {
- set(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA, true)
set(Flags.FACE_AUTH_REFACTOR, true)
set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false)
set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 985b6fde4c63..259c74ff25fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -32,6 +32,7 @@ import com.android.systemui.common.ui.data.repository.FakeConfigurationRepositor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
+import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
import com.android.systemui.flags.Flags
@@ -106,9 +107,10 @@ class KeyguardRootViewModelTest : SysuiTestCase() {
testScope = TestScope(testDispatcher)
MockitoAnnotations.initMocks(this)
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
+
val featureFlags =
FakeFeatureFlagsClassic().apply {
- set(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA, true)
set(Flags.FACE_AUTH_REFACTOR, true)
}
@@ -351,7 +353,6 @@ class KeyguardRootViewModelTestWithFakes : SysuiTestCase() {
featureFlags =
FakeFeatureFlagsClassicModule {
setDefault(Flags.NEW_AOD_TRANSITION)
- set(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA, true)
set(Flags.FACE_AUTH_REFACTOR, true)
},
mocks =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
index c835146dd974..8a531fd9c842 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
@@ -111,7 +111,6 @@ public class NavigationBarControllerImplTest extends SysuiTestCase {
TaskStackChangeListeners.getTestInstance(),
Optional.of(mock(Pip.class)),
Optional.of(mock(BackAnimation.class)),
- mock(FeatureFlags.class),
mock(SecureSettings.class),
mDisplayTracker));
initializeNavigationBars();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 48a36cb5eb12..ddceed62fdeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -27,6 +27,7 @@ import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.WindowInsets.Type.ime;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
+import static com.android.systemui.assist.AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS;
import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
@@ -42,6 +43,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -86,6 +88,7 @@ import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.DeadZone;
+import com.android.systemui.navigationbar.buttons.KeyButtonView;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
@@ -120,6 +123,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -143,6 +147,8 @@ public class NavigationBarTest extends SysuiTestCase {
@Mock
ButtonDispatcher mHomeButton;
@Mock
+ KeyButtonView mHomeButtonView;
+ @Mock
ButtonDispatcher mRecentsButton;
@Mock
ButtonDispatcher mAccessibilityButton;
@@ -294,11 +300,38 @@ public class NavigationBarTest extends SysuiTestCase {
@Test
public void testHomeLongPress() {
+ when(mAssistManager.shouldOverrideAssist(INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS))
+ .thenReturn(false);
+
mNavigationBar.init();
mNavigationBar.onViewAttached();
- mNavigationBar.onHomeLongClick(mNavigationBar.getView());
+ mNavigationBar.onHomeLongClick(mHomeButtonView);
verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS);
+ verify(mAssistManager).startAssist(any());
+ }
+
+ @Test
+ public void testHomeLongPressOverride() {
+ when(mAssistManager.shouldOverrideAssist(INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS))
+ .thenReturn(true);
+
+ mNavigationBar.init();
+ mNavigationBar.onViewAttached();
+ mNavigationBar.onHomeLongClick(mHomeButtonView);
+
+ verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS);
+
+ ArgumentCaptor<Runnable> onRippleInvisibleRunnableCaptor = ArgumentCaptor.forClass(
+ Runnable.class);
+ // startAssist is not called initially
+ verify(mAssistManager, never()).startAssist(any());
+ // but a Runnable is added for when the ripple is invisible
+ verify(mHomeButtonView).setOnRippleInvisibleRunnable(
+ onRippleInvisibleRunnableCaptor.capture());
+ // and when that runs, startAssist is called
+ onRippleInvisibleRunnableCaptor.getValue().run();
+ verify(mAssistManager).startAssist(any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
index 078a917eb689..a1010a01f1e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
@@ -50,6 +50,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.assist.AssistManager;
import com.android.systemui.recents.OverviewProxyService;
import org.junit.Before;
@@ -76,6 +77,7 @@ public class KeyButtonViewTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mDependency.injectMockDependency(OverviewProxyService.class);
+ mDependency.injectMockDependency(AssistManager.class);
mUiEventLogger = mDependency.injectMockDependency(UiEventLogger.class);
TestableLooper.get(this).runWithLooper(() -> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
index 31d02ed78404..8f27e4e12d17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
@@ -57,7 +57,7 @@ class QSTileLoggerTest : SysuiTestCase() {
whenever(logBufferFactory.create(any(), any(), any())).thenReturn(logBuffer)
underTest =
QSTileLogger(
- mapOf(TileSpec.create("chatty_tile") to chattyLogBuffer),
+ mapOf("chatty_tile" to chattyLogBuffer),
logBufferFactory,
statusBarController
)
@@ -117,7 +117,7 @@ class QSTileLoggerTest : SysuiTestCase() {
underTest.logUserActionPipeline(
TileSpec.create("test_spec"),
QSTileUserAction.Click(null),
- QSTileState.build(Icon.Resource(0, ContentDescription.Resource(0)), "") {},
+ QSTileState.build({ Icon.Resource(0, ContentDescription.Resource(0)) }, "") {},
"test_data",
)
@@ -143,7 +143,7 @@ class QSTileLoggerTest : SysuiTestCase() {
fun testLogStateUpdate() {
underTest.logStateUpdate(
TileSpec.create("test_spec"),
- QSTileState.build(Icon.Resource(0, ContentDescription.Resource(0)), "") {},
+ QSTileState.build({ Icon.Resource(0, ContentDescription.Resource(0)) }, "") {},
"test_data",
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
index 9bf4a759a1f2..d3b7daad792e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
@@ -97,7 +97,10 @@ class QSTileViewModelInterfaceComplianceTest : SysuiTestCase() {
{
object : QSTileDataToStateMapper<Any> {
override fun map(config: QSTileConfig, data: Any): QSTileState =
- QSTileState.build(Icon.Resource(0, ContentDescription.Resource(0)), "") {}
+ QSTileState.build(
+ { Icon.Resource(0, ContentDescription.Resource(0)) },
+ ""
+ ) {}
}
},
fakeDisabledByPolicyInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
index 32a38bd1faa1..4c8b56227efa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
@@ -67,6 +67,7 @@ internal class SceneContainerFlagsTest(
listOf(
AconfigFlags.FLAG_SCENE_CONTAINER,
+ AconfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR,
)
.forEach { flagToken ->
setFlagsRule.enableFlags(flagToken)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index a7e1e9d35024..e6cd17f448b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -77,6 +77,7 @@ import com.android.systemui.scene.data.repository.SceneContainerRepository;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags;
import com.android.systemui.scene.shared.logger.SceneLogger;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -136,8 +137,10 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
@Mock private ShadeExpansionStateManager mShadeExpansionStateManager;
@Mock private ShadeWindowLogger mShadeWindowLogger;
@Mock private SelectedUserInteractor mSelectedUserInteractor;
+ @Mock private UserTracker mUserTracker;
@Captor private ArgumentCaptor<WindowManager.LayoutParams> mLayoutParameters;
@Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListener;
+ private final Executor mMainExecutor = MoreExecutors.directExecutor();
private final Executor mBackgroundExecutor = MoreExecutors.directExecutor();
private SceneTestUtils mUtils = new SceneTestUtils(this);
private TestScope mTestScope = mUtils.getTestScope();
@@ -261,6 +264,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
mConfigurationController,
mKeyguardViewMediator,
mKeyguardBypassController,
+ mMainExecutor,
mBackgroundExecutor,
mColorExtractor,
mDumpManager,
@@ -269,7 +273,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
mAuthController,
() -> mShadeInteractor,
mShadeWindowLogger,
- () -> mSelectedUserInteractor) {
+ () -> mSelectedUserInteractor,
+ mUserTracker) {
@Override
protected boolean isDebuggable() {
return false;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 4f19742b26d9..a5806001dd43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -334,6 +334,8 @@ public class BubblesTest extends SysuiTestCase {
@Mock
private SelectedUserInteractor mSelectedUserInteractor;
@Mock
+ private UserTracker mUserTracker;
+ @Mock
private NotifPipelineFlags mNotifPipelineFlags;
@Mock
private Icon mAppBubbleIcon;
@@ -488,6 +490,7 @@ public class BubblesTest extends SysuiTestCase {
mKeyguardViewMediator,
mKeyguardBypassController,
syncExecutor,
+ syncExecutor,
mColorExtractor,
mDumpManager,
mKeyguardStateController,
@@ -495,7 +498,8 @@ public class BubblesTest extends SysuiTestCase {
mAuthController,
() -> mShadeInteractor,
mShadeWindowLogger,
- () -> mSelectedUserInteractor
+ () -> mSelectedUserInteractor,
+ mUserTracker
);
mNotificationShadeWindowController.fetchWindowRootView();
mNotificationShadeWindowController.attach();
diff --git a/proto/src/criticalevents/critical_event_log.proto b/proto/src/criticalevents/critical_event_log.proto
index 25814eca9a85..9cda2672eab0 100644
--- a/proto/src/criticalevents/critical_event_log.proto
+++ b/proto/src/criticalevents/critical_event_log.proto
@@ -59,8 +59,11 @@ message CriticalEventProto {
AppNotResponding anr = 4;
JavaCrash java_crash = 5;
NativeCrash native_crash = 6;
+ SystemServerStarted system_server_started = 7;
}
+ message SystemServerStarted {}
+
message Watchdog {
// The watchdog subject.
// Required.
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a14f3fee5303..4e49c6e4e7de 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -199,6 +199,7 @@ java_library_static {
"biometrics_flags_lib",
"am_flags_lib",
"com_android_wm_shell_flags_lib",
+ "android.app.flags-aconfig-java"
],
javac_shard_size: 50,
javacflags: [
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index e6cdbb58a9fd..599d99854b26 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -166,6 +166,7 @@ public class SettingsToPropertiesMapper {
"safety_center",
"sensors",
"system_performance",
+ "system_sw_usb",
"test_suites",
"text",
"threadnetwork",
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 87633e9e255d..47a99fe24ec4 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2030,6 +2030,9 @@ class UserController implements Handler.Callback {
mTargetUserId = targetUserId;
userSwitchUiEnabled = mUserSwitchUiEnabled;
}
+ if (android.multiuser.Flags.useAllCpusDuringUserSwitch()) {
+ mInjector.setHasTopUi(true);
+ }
if (userSwitchUiEnabled) {
UserInfo currentUserInfo = getUserInfo(currentUserId);
Pair<UserInfo, UserInfo> userNames = new Pair<>(currentUserInfo, targetUserInfo);
@@ -2098,6 +2101,9 @@ class UserController implements Handler.Callback {
}
private void endUserSwitch() {
+ if (android.multiuser.Flags.useAllCpusDuringUserSwitch()) {
+ mInjector.setHasTopUi(false);
+ }
final int nextUserId;
synchronized (mLock) {
nextUserId = ObjectUtils.getOrElse(mPendingTargetUserIds.poll(), UserHandle.USER_NULL);
@@ -3781,6 +3787,15 @@ class UserController implements Handler.Callback {
getSystemServiceManager().onUserStarting(TimingsTraceAndSlog.newAsyncLog(), userId);
}
+ void setHasTopUi(boolean hasTopUi) {
+ try {
+ Slogf.i(TAG, "Setting hasTopUi to " + hasTopUi);
+ mService.setHasTopUi(hasTopUi);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "Failed to allow using all CPU cores", e);
+ }
+ }
+
void onSystemUserVisibilityChanged(boolean visible) {
getUserManagerInternal().onSystemUserVisibilityChanged(visible);
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 28970750a5ac..5d4f711b9432 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -70,7 +70,6 @@ import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
-import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -172,7 +171,7 @@ public class AudioDeviceBroker {
@NonNull AudioSystemAdapter audioSystem) {
mContext = context;
mAudioService = service;
- mBtHelper = new BtHelper(this);
+ mBtHelper = new BtHelper(this, context);
mDeviceInventory = new AudioDeviceInventory(this);
mSystemServer = SystemServerAdapter.getDefaultAdapter(mContext);
mAudioSystem = audioSystem;
@@ -188,7 +187,7 @@ public class AudioDeviceBroker {
@NonNull AudioSystemAdapter audioSystem) {
mContext = context;
mAudioService = service;
- mBtHelper = new BtHelper(this);
+ mBtHelper = new BtHelper(this, context);
mDeviceInventory = mockDeviceInventory;
mSystemServer = mockSystemServer;
mAudioSystem = audioSystem;
@@ -1392,6 +1391,10 @@ public class AudioDeviceBroker {
return mAudioService.hasAudioFocusUsers();
}
+ /*package*/ void postInitSpatializerHeadTrackingSensors() {
+ mAudioService.postInitSpatializerHeadTrackingSensors();
+ }
+
//---------------------------------------------------------------------
// Message handling on behalf of helper classes.
// Each of these methods posts a message to mBrokerHandler message queue.
@@ -1475,6 +1478,15 @@ public class AudioDeviceBroker {
sendLMsgNoDelay(MSG_L_RECEIVED_BT_EVENT, SENDMSG_QUEUE, intent);
}
+ /*package*/ void postUpdateLeAudioGroupAddresses(int groupId) {
+ sendIMsgNoDelay(
+ MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES, SENDMSG_QUEUE, groupId);
+ }
+
+ /*package*/ void postSynchronizeLeDevicesInInventory(AdiDeviceState deviceState) {
+ sendLMsgNoDelay(MSG_L_SYNCHRONIZE_LE_DEVICES_IN_INVENTORY, SENDMSG_QUEUE, deviceState);
+ }
+
/*package*/ static final class CommunicationDeviceInfo {
final @NonNull IBinder mCb; // Identifies the requesting client for death handler
final int mUid; // Requester UID
@@ -1604,6 +1616,14 @@ public class AudioDeviceBroker {
}
}
+ /*package*/ int getLeAudioDeviceGroupId(BluetoothDevice device) {
+ return mBtHelper.getLeAudioDeviceGroupId(device);
+ }
+
+ /*package*/ List<String> getLeAudioGroupAddresses(int groupId) {
+ return mBtHelper.getLeAudioGroupAddresses(groupId);
+ }
+
/*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) {
mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent);
}
@@ -1976,6 +1996,22 @@ public class AudioDeviceBroker {
onCheckCommunicationRouteClientState(msg.arg1, msg.arg2 == 1);
}
} break;
+
+ case MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES:
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onUpdateLeAudioGroupAddresses(msg.arg1);
+ }
+ } break;
+
+ case MSG_L_SYNCHRONIZE_LE_DEVICES_IN_INVENTORY:
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onSynchronizeLeDevicesInInventory(
+ (AdiDeviceState) msg.obj);
+ }
+ } break;
+
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -2058,6 +2094,10 @@ public class AudioDeviceBroker {
private static final int MSG_L_RECEIVED_BT_EVENT = 55;
private static final int MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE = 56;
+ private static final int MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES = 57;
+ private static final int MSG_L_SYNCHRONIZE_LE_DEVICES_IN_INVENTORY = 58;
+
+
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
@@ -2582,9 +2622,9 @@ public class AudioDeviceBroker {
}
}
- @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
+ List<String> getDeviceAddresses(AudioDeviceAttributes device) {
synchronized (mDeviceStateLock) {
- return mDeviceInventory.getDeviceSensorUuid(device);
+ return mDeviceInventory.getDeviceAddresses(device);
}
}
@@ -2605,15 +2645,19 @@ public class AudioDeviceBroker {
* in order to be mocked by a test a the same package
* (see https://code.google.com/archive/p/mockito/issues/127)
*/
- public void persistAudioDeviceSettings() {
+ public void postPersistAudioDeviceSettings() {
sendMsg(MSG_PERSIST_AUDIO_DEVICE_SETTINGS, SENDMSG_REPLACE, /*delay*/ 1000);
}
void onPersistAudioDeviceSettings() {
final String deviceSettings = mDeviceInventory.getDeviceSettings();
- Log.v(TAG, "saving AdiDeviceState: " + deviceSettings);
- final SettingsAdapter settings = mAudioService.getSettings();
- boolean res = settings.putSecureStringForUser(mAudioService.getContentResolver(),
+ Log.v(TAG, "onPersistAudioDeviceSettings AdiDeviceState: " + deviceSettings);
+ String currentSettings = readDeviceSettings();
+ if (deviceSettings.equals(currentSettings)) {
+ return;
+ }
+ final SettingsAdapter settingsAdapter = mAudioService.getSettings();
+ boolean res = settingsAdapter.putSecureStringForUser(mAudioService.getContentResolver(),
Settings.Secure.AUDIO_DEVICE_INVENTORY,
deviceSettings, UserHandle.USER_CURRENT);
if (!res) {
@@ -2621,11 +2665,17 @@ public class AudioDeviceBroker {
}
}
- void onReadAudioDeviceSettings() {
+ private String readDeviceSettings() {
final SettingsAdapter settingsAdapter = mAudioService.getSettings();
final ContentResolver contentResolver = mAudioService.getContentResolver();
- String settings = settingsAdapter.getSecureStringForUser(contentResolver,
+ return settingsAdapter.getSecureStringForUser(contentResolver,
Settings.Secure.AUDIO_DEVICE_INVENTORY, UserHandle.USER_CURRENT);
+ }
+
+ void onReadAudioDeviceSettings() {
+ final SettingsAdapter settingsAdapter = mAudioService.getSettings();
+ final ContentResolver contentResolver = mAudioService.getContentResolver();
+ String settings = readDeviceSettings();
if (settings == null) {
Log.i(TAG, "reading AdiDeviceState from legacy key"
+ Settings.Secure.SPATIAL_AUDIO_ENABLED);
@@ -2688,8 +2738,8 @@ public class AudioDeviceBroker {
}
@Nullable
- AdiDeviceState findBtDeviceStateForAddress(String address, boolean isBle) {
- return mDeviceInventory.findBtDeviceStateForAddress(address, isBle);
+ AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) {
+ return mDeviceInventory.findBtDeviceStateForAddress(address, deviceType);
}
//------------------------------------------------
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index e59fd77919c5..7ba0827f2016 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -15,14 +15,23 @@
*/
package com.android.server.audio;
+import static android.media.AudioSystem.DEVICE_IN_ALL_SCO_SET;
import static android.media.AudioSystem.DEVICE_OUT_ALL_A2DP_SET;
import static android.media.AudioSystem.DEVICE_OUT_ALL_BLE_SET;
+import static android.media.AudioSystem.DEVICE_OUT_ALL_SCO_SET;
+import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
+import static android.media.AudioSystem.isBluetoothA2dpOutDevice;
import static android.media.AudioSystem.isBluetoothDevice;
+import static android.media.AudioSystem.isBluetoothLeOutDevice;
+import static android.media.AudioSystem.isBluetoothOutDevice;
+import static android.media.AudioSystem.isBluetoothScoOutDevice;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
@@ -72,7 +81,6 @@ import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
-import java.util.UUID;
import java.util.stream.Stream;
/**
@@ -118,6 +126,7 @@ public class AudioDeviceInventory {
return oldState;
});
}
+ mDeviceBroker.postSynchronizeLeDevicesInInventory(deviceState);
}
/**
@@ -125,23 +134,28 @@ public class AudioDeviceInventory {
* Bluetooth device and no corresponding entry already exists.
* @param ada the device to add if needed
*/
- void addAudioDeviceInInventoryIfNeeded(AudioDeviceAttributes ada) {
- if (!AudioSystem.isBluetoothOutDevice(ada.getInternalType())) {
+ void addAudioDeviceInInventoryIfNeeded(int deviceType, String address, String peerAddres) {
+ if (!isBluetoothOutDevice(deviceType)) {
return;
}
synchronized (mDeviceInventoryLock) {
- if (findDeviceStateForAudioDeviceAttributes(ada, ada.getType()) != null) {
+ AdiDeviceState ads = findBtDeviceStateForAddress(address, deviceType);
+ if (ads == null) {
+ ads = findBtDeviceStateForAddress(peerAddres, deviceType);
+ }
+ if (ads != null) {
+ mDeviceBroker.postSynchronizeLeDevicesInInventory(ads);
return;
}
- AdiDeviceState ads = new AdiDeviceState(
- ada.getType(), ada.getInternalType(), ada.getAddress());
+ ads = new AdiDeviceState(AudioDeviceInfo.convertInternalDeviceToDeviceType(deviceType),
+ deviceType, address);
mDeviceInventory.put(ads.getDeviceId(), ads);
+ mDeviceBroker.postPersistAudioDeviceSettings();
}
- mDeviceBroker.persistAudioDeviceSettings();
}
/**
- * Adds a new AdiDeviceState or updates the audio device cateogory of the matching
+ * Adds a new AdiDeviceState or updates the audio device category of the matching
* AdiDeviceState in the {@link AudioDeviceInventory#mDeviceInventory} list.
* @param deviceState the device to update
*/
@@ -152,6 +166,63 @@ public class AudioDeviceInventory {
return oldState;
});
}
+ mDeviceBroker.postSynchronizeLeDevicesInInventory(deviceState);
+ }
+
+ /**
+ * synchronize AdiDeviceState for LE devices in the same group
+ */
+ void onSynchronizeLeDevicesInInventory(AdiDeviceState updatedDevice) {
+ synchronized (mDevicesLock) {
+ synchronized (mDeviceInventoryLock) {
+ boolean found = false;
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (di.mDeviceType != updatedDevice.getInternalDeviceType()) {
+ continue;
+ }
+ if (di.mDeviceAddress.equals(updatedDevice.getDeviceAddress())) {
+ for (AdiDeviceState ads2 : mDeviceInventory.values()) {
+ if (!(di.mDeviceType == ads2.getInternalDeviceType()
+ && di.mPeerDeviceAddress.equals(ads2.getDeviceAddress()))) {
+ continue;
+ }
+ ads2.setHasHeadTracker(updatedDevice.hasHeadTracker());
+ ads2.setHeadTrackerEnabled(updatedDevice.isHeadTrackerEnabled());
+ ads2.setSAEnabled(updatedDevice.isSAEnabled());
+ ads2.setAudioDeviceCategory(updatedDevice.getAudioDeviceCategory());
+ found = true;
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "onSynchronizeLeDevicesInInventory synced device pair ads1="
+ + updatedDevice + " ads2=" + ads2).printLog(TAG));
+ break;
+ }
+ }
+ if (di.mPeerDeviceAddress.equals(updatedDevice.getDeviceAddress())) {
+ for (AdiDeviceState ads2 : mDeviceInventory.values()) {
+ if (!(di.mDeviceType == ads2.getInternalDeviceType()
+ && di.mDeviceAddress.equals(ads2.getDeviceAddress()))) {
+ continue;
+ }
+ ads2.setHasHeadTracker(updatedDevice.hasHeadTracker());
+ ads2.setHeadTrackerEnabled(updatedDevice.isHeadTrackerEnabled());
+ ads2.setSAEnabled(updatedDevice.isSAEnabled());
+ ads2.setAudioDeviceCategory(updatedDevice.getAudioDeviceCategory());
+ found = true;
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "onSynchronizeLeDevicesInInventory synced device pair ads1="
+ + updatedDevice + " peer ads2=" + ads2).printLog(TAG));
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ mDeviceBroker.postPersistAudioDeviceSettings();
+ }
+ }
+ }
}
/**
@@ -163,9 +234,21 @@ public class AudioDeviceInventory {
* @return the found {@link AdiDeviceState} or {@code null} otherwise.
*/
@Nullable
- AdiDeviceState findBtDeviceStateForAddress(String address, boolean isBle) {
+ AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) {
+ Set<Integer> deviceSet;
+ if (isBluetoothA2dpOutDevice(deviceType)) {
+ deviceSet = DEVICE_OUT_ALL_A2DP_SET;
+ } else if (isBluetoothLeOutDevice(deviceType)) {
+ deviceSet = DEVICE_OUT_ALL_BLE_SET;
+ } else if (isBluetoothScoOutDevice(deviceType)) {
+ deviceSet = DEVICE_OUT_ALL_SCO_SET;
+ } else if (deviceType == DEVICE_OUT_HEARING_AID) {
+ deviceSet = new HashSet<>();
+ deviceSet.add(DEVICE_OUT_HEARING_AID);
+ } else {
+ return null;
+ }
synchronized (mDeviceInventoryLock) {
- final Set<Integer> deviceSet = isBle ? DEVICE_OUT_ALL_BLE_SET : DEVICE_OUT_ALL_A2DP_SET;
for (Integer internalType : deviceSet) {
AdiDeviceState deviceState = mDeviceInventory.get(
new Pair<>(internalType, address));
@@ -345,7 +428,8 @@ public class AudioDeviceInventory {
final @NonNull String mDeviceName;
final @NonNull String mDeviceAddress;
int mDeviceCodecFormat;
- final UUID mSensorUuid;
+ @NonNull String mPeerDeviceAddress;
+ final int mGroupId;
/** Disabled operating modes for this device. Use a negative logic so that by default
* an empty list means all modes are allowed.
@@ -353,12 +437,13 @@ public class AudioDeviceInventory {
@NonNull ArraySet<String> mDisabledModes = new ArraySet(0);
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
- int deviceCodecFormat, @Nullable UUID sensorUuid) {
+ int deviceCodecFormat, String peerDeviceAddress, int groupId) {
mDeviceType = deviceType;
mDeviceName = deviceName == null ? "" : deviceName;
mDeviceAddress = deviceAddress == null ? "" : deviceAddress;
mDeviceCodecFormat = deviceCodecFormat;
- mSensorUuid = sensorUuid;
+ mPeerDeviceAddress = peerDeviceAddress == null ? "" : peerDeviceAddress;
+ mGroupId = groupId;
}
void setModeDisabled(String mode) {
@@ -379,7 +464,8 @@ public class AudioDeviceInventory {
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
int deviceCodecFormat) {
- this(deviceType, deviceName, deviceAddress, deviceCodecFormat, null);
+ this(deviceType, deviceName, deviceAddress, deviceCodecFormat,
+ null, BluetoothLeAudio.GROUP_ID_INVALID);
}
DeviceInfo(int deviceType, String deviceName, String deviceAddress) {
@@ -393,7 +479,8 @@ public class AudioDeviceInventory {
+ ") name:" + mDeviceName
+ " addr:" + mDeviceAddress
+ " codec: " + Integer.toHexString(mDeviceCodecFormat)
- + " sensorUuid: " + Objects.toString(mSensorUuid)
+ + " peer addr:" + mPeerDeviceAddress
+ + " group:" + mGroupId
+ " disabled modes: " + mDisabledModes + "]";
}
@@ -714,6 +801,27 @@ public class AudioDeviceInventory {
}
}
+
+ /*package*/ void onUpdateLeAudioGroupAddresses(int groupId) {
+ synchronized (mDevicesLock) {
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (di.mGroupId == groupId) {
+ List<String> addresses = mDeviceBroker.getLeAudioGroupAddresses(groupId);
+ if (di.mPeerDeviceAddress.equals("")) {
+ for (String addr : addresses) {
+ if (!addr.equals(di.mDeviceAddress)) {
+ di.mPeerDeviceAddress = addr;
+ break;
+ }
+ }
+ } else if (!addresses.contains(di.mPeerDeviceAddress)) {
+ di.mPeerDeviceAddress = "";
+ }
+ }
+ }
+ }
+ }
+
/*package*/ void onReportNewRoutes() {
int n = mRoutesObservers.beginBroadcast();
if (n > 0) {
@@ -1419,7 +1527,7 @@ public class AudioDeviceInventory {
if (!connect) {
purgeDevicesRoles_l();
} else {
- addAudioDeviceInInventoryIfNeeded(attributes);
+ addAudioDeviceInInventoryIfNeeded(device, address, "");
}
}
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
@@ -1477,7 +1585,7 @@ public class AudioDeviceInventory {
final ArraySet<String> toRemove = new ArraySet<>();
// Disconnect ALL DEVICE_OUT_HEARING_AID devices
mConnectedDevices.values().forEach(deviceInfo -> {
- if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
+ if (deviceInfo.mDeviceType == DEVICE_OUT_HEARING_AID) {
toRemove.add(deviceInfo.mDeviceAddress);
}
});
@@ -1485,8 +1593,8 @@ public class AudioDeviceInventory {
.set(MediaMetrics.Property.EVENT, "disconnectHearingAid")
.record();
if (toRemove.size() > 0) {
- final int delay = checkSendBecomingNoisyIntentInt(
- AudioSystem.DEVICE_OUT_HEARING_AID, 0, AudioSystem.DEVICE_NONE);
+ final int delay = checkSendBecomingNoisyIntentInt(DEVICE_OUT_HEARING_AID,
+ AudioService.CONNECTION_STATE_DISCONNECTED, AudioSystem.DEVICE_NONE);
toRemove.stream().forEach(deviceAddress ->
// TODO delay not used?
makeHearingAidDeviceUnavailable(deviceAddress /*, delay*/)
@@ -1687,12 +1795,8 @@ public class AudioDeviceInventory {
// Reset A2DP suspend state each time a new sink is connected
mDeviceBroker.clearA2dpSuspended(true /* internalOnly */);
- // The convention for head tracking sensors associated with A2DP devices is to
- // use a UUID derived from the MAC address as follows:
- // time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address
- UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
- address, codec, sensorUuid);
+ address, codec);
final String diKey = di.getKey();
mConnectedDevices.put(diKey, di);
// on a connection always overwrite the device seen by AudioPolicy, see comment above when
@@ -1703,7 +1807,7 @@ public class AudioDeviceInventory {
setCurrentAudioRouteNameIfPossible(name, true /*fromA2dp*/);
updateBluetoothPreferredModes_l(btInfo.mDevice /*connectedDevice*/);
- addAudioDeviceInInventoryIfNeeded(ada);
+ addAudioDeviceInInventoryIfNeeded(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, "");
}
static final int[] CAPTURE_PRESETS = new int[] {AudioSource.MIC, AudioSource.CAMCORDER,
@@ -1723,15 +1827,15 @@ public class AudioDeviceInventory {
return;
}
DeviceInfo leOutDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
+ getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_BLE_SET);
DeviceInfo leInDevice =
getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_BLE_SET);
DeviceInfo a2dpDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+ getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_A2DP_SET);
DeviceInfo scoOutDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_SCO_SET);
+ getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_SCO_SET);
DeviceInfo scoInDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_SCO_SET);
+ getFirstConnectedDeviceOfTypes(DEVICE_IN_ALL_SCO_SET);
boolean disableA2dp = (leOutDevice != null && leOutDevice.isOutputOnlyModeEnabled());
boolean disableSco = (leOutDevice != null && leOutDevice.isDuplexModeEnabled())
|| (leInDevice != null && leInDevice.isDuplexModeEnabled());
@@ -1765,7 +1869,7 @@ public class AudioDeviceInventory {
continue;
}
- if (AudioSystem.isBluetoothOutDevice(di.mDeviceType)) {
+ if (isBluetoothOutDevice(di.mDeviceType)) {
for (AudioProductStrategy strategy : mStrategies) {
boolean disable = false;
if (strategy.getId() == mDeviceBroker.mCommunicationStrategyId) {
@@ -1832,23 +1936,20 @@ public class AudioDeviceInventory {
int checkProfileIsConnected(int profile) {
switch (profile) {
case BluetoothProfile.HEADSET:
- if (getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_OUT_ALL_SCO_SET) != null
- || getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_IN_ALL_SCO_SET) != null) {
+ if (getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_SCO_SET) != null
+ || getFirstConnectedDeviceOfTypes(DEVICE_IN_ALL_SCO_SET) != null) {
return profile;
}
break;
case BluetoothProfile.A2DP:
- if (getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_OUT_ALL_A2DP_SET) != null) {
+ if (getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_A2DP_SET) != null) {
return profile;
}
break;
case BluetoothProfile.LE_AUDIO:
case BluetoothProfile.LE_AUDIO_BROADCAST:
if (getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_OUT_ALL_BLE_SET) != null
+ DEVICE_OUT_ALL_BLE_SET) != null
|| getFirstConnectedDeviceOfTypes(
AudioSystem.DEVICE_IN_ALL_BLE_SET) != null) {
return profile;
@@ -2006,28 +2107,28 @@ public class AudioDeviceInventory {
private void makeHearingAidDeviceAvailable(
String address, String name, int streamType, String eventSource) {
final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
- AudioSystem.DEVICE_OUT_HEARING_AID);
+ DEVICE_OUT_HEARING_AID);
mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
AudioDeviceAttributes ada = new AudioDeviceAttributes(
- AudioSystem.DEVICE_OUT_HEARING_AID, address, name);
+ DEVICE_OUT_HEARING_AID, address, name);
mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_AVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
- DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
- new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name, address));
- mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_HEARING_AID);
+ DeviceInfo.makeDeviceListKey(DEVICE_OUT_HEARING_AID, address),
+ new DeviceInfo(DEVICE_OUT_HEARING_AID, name, address));
+ mDeviceBroker.postAccessoryPlugMediaUnmute(DEVICE_OUT_HEARING_AID);
mDeviceBroker.postApplyVolumeOnDevice(streamType,
- AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
+ DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
setCurrentAudioRouteNameIfPossible(name, false /*fromA2dp*/);
- addAudioDeviceInInventoryIfNeeded(ada);
+ addAudioDeviceInInventoryIfNeeded(DEVICE_OUT_HEARING_AID, address, "");
new MediaMetrics.Item(mMetricsId + "makeHearingAidDeviceAvailable")
.set(MediaMetrics.Property.ADDRESS, address != null ? address : "")
.set(MediaMetrics.Property.DEVICE,
- AudioSystem.getDeviceName(AudioSystem.DEVICE_OUT_HEARING_AID))
+ AudioSystem.getDeviceName(DEVICE_OUT_HEARING_AID))
.set(MediaMetrics.Property.NAME, name)
.set(MediaMetrics.Property.STREAM_TYPE,
AudioSystem.streamToString(streamType))
@@ -2037,18 +2138,18 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeHearingAidDeviceUnavailable(String address) {
AudioDeviceAttributes ada = new AudioDeviceAttributes(
- AudioSystem.DEVICE_OUT_HEARING_AID, address);
+ DEVICE_OUT_HEARING_AID, address);
mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(
- DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
+ DeviceInfo.makeDeviceListKey(DEVICE_OUT_HEARING_AID, address));
// Remove Hearing Aid routes as well
setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
new MediaMetrics.Item(mMetricsId + "makeHearingAidDeviceUnavailable")
.set(MediaMetrics.Property.ADDRESS, address != null ? address : "")
.set(MediaMetrics.Property.DEVICE,
- AudioSystem.getDeviceName(AudioSystem.DEVICE_OUT_HEARING_AID))
+ AudioSystem.getDeviceName(DEVICE_OUT_HEARING_AID))
.record();
mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
}
@@ -2060,7 +2161,7 @@ public class AudioDeviceInventory {
*/
boolean isHearingAidConnected() {
return getFirstConnectedDeviceOfTypes(
- Sets.newHashSet(AudioSystem.DEVICE_OUT_HEARING_AID)) != null;
+ Sets.newHashSet(DEVICE_OUT_HEARING_AID)) != null;
}
/**
@@ -2102,6 +2203,20 @@ public class AudioDeviceInventory {
final String address = btInfo.mDevice.getAddress();
String name = BtHelper.getName(btInfo.mDevice);
+ // Find LE Group ID and peer headset address if available
+ final int groupId = mDeviceBroker.getLeAudioDeviceGroupId(btInfo.mDevice);
+ String peerAddress = "";
+ if (groupId != BluetoothLeAudio.GROUP_ID_INVALID) {
+ List<String> addresses = mDeviceBroker.getLeAudioGroupAddresses(groupId);
+ if (addresses.size() > 1) {
+ for (String addr : addresses) {
+ if (!addr.equals(address)) {
+ peerAddress = addr;
+ break;
+ }
+ }
+ }
+ }
// The BT Stack does not provide a name for LE Broadcast devices
if (device == AudioSystem.DEVICE_OUT_BLE_BROADCAST && name.equals("")) {
name = "Broadcast";
@@ -2127,14 +2242,12 @@ public class AudioDeviceInventory {
}
// Reset LEA suspend state each time a new sink is connected
mDeviceBroker.clearLeAudioSuspended(true /* internalOnly */);
-
- UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT,
- sensorUuid));
+ peerAddress, groupId));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
- addAudioDeviceInInventoryIfNeeded(ada);
+ addAudioDeviceInInventoryIfNeeded(device, address, peerAddress);
}
if (streamType == AudioSystem.STREAM_DEFAULT) {
@@ -2226,12 +2339,12 @@ public class AudioDeviceInventory {
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HDMI);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE);
- BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(DEVICE_OUT_HEARING_AID);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_BLE_HEADSET);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
- BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+ BECOMING_NOISY_INTENT_DEVICES_SET.addAll(DEVICE_OUT_ALL_A2DP_SET);
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
- BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
+ BECOMING_NOISY_INTENT_DEVICES_SET.addAll(DEVICE_OUT_ALL_BLE_SET);
}
// must be called before removing the device from mConnectedDevices
@@ -2512,16 +2625,22 @@ public class AudioDeviceInventory {
mDevRoleCapturePresetDispatchers.finishBroadcast();
}
- @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
+ List<String> getDeviceAddresses(AudioDeviceAttributes device) {
+ List<String> addresses = new ArrayList<String>();
final String key = DeviceInfo.makeDeviceListKey(device.getInternalType(),
device.getAddress());
synchronized (mDevicesLock) {
DeviceInfo di = mConnectedDevices.get(key);
- if (di == null) {
- return null;
+ if (di != null) {
+ if (!di.mDeviceAddress.isEmpty()) {
+ addresses.add(di.mDeviceAddress);
+ }
+ if (!di.mPeerDeviceAddress.isEmpty()) {
+ addresses.add(di.mPeerDeviceAddress);
+ }
}
- return di.mSensorUuid;
}
+ return addresses;
}
/*package*/ String getDeviceSettings() {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d0ae0f25d6cd..99321c44931b 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -237,7 +237,6 @@ import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
-import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -11054,7 +11053,9 @@ public class AudioService extends IAudioService.Stub
final String addr = Objects.requireNonNull(address);
- AdiDeviceState deviceState = mDeviceBroker.findBtDeviceStateForAddress(addr, isBle);
+ AdiDeviceState deviceState = mDeviceBroker.findBtDeviceStateForAddress(addr,
+ (isBle ? AudioSystem.DEVICE_OUT_BLE_HEADSET
+ : AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
int internalType = !isBle ? DEVICE_OUT_BLUETOOTH_A2DP
: ((btAudioDeviceCategory == AUDIO_DEVICE_CATEGORY_HEADPHONES)
@@ -11070,7 +11071,7 @@ public class AudioService extends IAudioService.Stub
deviceState.setAudioDeviceCategory(btAudioDeviceCategory);
mDeviceBroker.addOrUpdateBtAudioDeviceCategoryInInventory(deviceState);
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
mSpatializerHelper.refreshDevice(deviceState.getAudioDeviceAttributes());
mSoundDoseHelper.setAudioDeviceCategory(addr, internalType,
@@ -11084,7 +11085,8 @@ public class AudioService extends IAudioService.Stub
super.getBluetoothAudioDeviceCategory_enforcePermission();
final AdiDeviceState deviceState = mDeviceBroker.findBtDeviceStateForAddress(
- Objects.requireNonNull(address), isBle);
+ Objects.requireNonNull(address), (isBle ? AudioSystem.DEVICE_OUT_BLE_HEADSET
+ : AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
if (deviceState == null) {
return AUDIO_DEVICE_CATEGORY_UNKNOWN;
}
@@ -13596,8 +13598,8 @@ public class AudioService extends IAudioService.Stub
return activeAssistantUids;
}
- UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
- return mDeviceBroker.getDeviceSensorUuid(device);
+ List<String> getDeviceAddresses(AudioDeviceAttributes device) {
+ return mDeviceBroker.getDeviceAddresses(device);
}
//======================
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index cce6bd2938d1..7b9621581adf 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -26,7 +26,9 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothLeAudioCodecStatus;
import android.bluetooth.BluetoothProfile;
+import android.content.Context;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
@@ -43,6 +45,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.server.utils.EventLogger;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -57,9 +60,11 @@ public class BtHelper {
private static final String TAG = "AS.BtHelper";
private final @NonNull AudioDeviceBroker mDeviceBroker;
+ private final @NonNull Context mContext;
- BtHelper(@NonNull AudioDeviceBroker broker) {
+ BtHelper(@NonNull AudioDeviceBroker broker, Context context) {
mDeviceBroker = broker;
+ mContext = context;
}
// BluetoothHeadset API to control SCO connection
@@ -498,6 +503,32 @@ public class BtHelper {
}
}
+ // BluetoothLeAudio callback used to update the list of addresses in the same group as a
+ // connected LE Audio device
+ MyLeAudioCallback mLeAudioCallback = null;
+
+ class MyLeAudioCallback implements BluetoothLeAudio.Callback {
+ @Override
+ public void onCodecConfigChanged(int groupId,
+ @NonNull BluetoothLeAudioCodecStatus status) {
+ // Do nothing
+ }
+
+ @Override
+ public void onGroupNodeAdded(@NonNull BluetoothDevice device, int groupId) {
+ mDeviceBroker.postUpdateLeAudioGroupAddresses(groupId);
+ }
+
+ @Override
+ public void onGroupNodeRemoved(@NonNull BluetoothDevice device, int groupId) {
+ mDeviceBroker.postUpdateLeAudioGroupAddresses(groupId);
+ }
+ @Override
+ public void onGroupStatusChanged(int groupId, int groupStatus) {
+ mDeviceBroker.postUpdateLeAudioGroupAddresses(groupId);
+ }
+ }
+
// @GuardedBy("mDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
/*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
@@ -519,6 +550,11 @@ public class BtHelper {
mHearingAid = (BluetoothHearingAid) proxy;
break;
case BluetoothProfile.LE_AUDIO:
+ if (mLeAudio == null) {
+ mLeAudioCallback = new MyLeAudioCallback();
+ ((BluetoothLeAudio) proxy).registerCallback(
+ mContext.getMainExecutor(), mLeAudioCallback);
+ }
mLeAudio = (BluetoothLeAudio) proxy;
break;
case BluetoothProfile.A2DP_SINK:
@@ -977,6 +1013,28 @@ public class BtHelper {
return result;
}
+ /*package*/ int getLeAudioDeviceGroupId(BluetoothDevice device) {
+ if (mLeAudio == null || device == null) {
+ return BluetoothLeAudio.GROUP_ID_INVALID;
+ }
+ return mLeAudio.getGroupId(device);
+ }
+
+ /*package*/ List<String> getLeAudioGroupAddresses(int groupId) {
+ List<String> addresses = new ArrayList<String>();
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter == null || mLeAudio == null) {
+ return addresses;
+ }
+ List<BluetoothDevice> activeDevices = adapter.getActiveDevices(BluetoothProfile.LE_AUDIO);
+ for (BluetoothDevice device : activeDevices) {
+ if (device != null && mLeAudio.getGroupId(device) == groupId) {
+ addresses.add(device.getAddress());
+ }
+ }
+ return addresses;
+ }
+
/**
* Returns the String equivalent of the btCodecType.
*
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 7abd9c7f750b..ea92154f2df0 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -564,7 +564,7 @@ public class SpatializerHelper {
}
if (updatedDevice != null) {
onRoutingUpdated();
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(updatedDevice, "addCompatibleAudioDevice");
}
}
@@ -614,7 +614,7 @@ public class SpatializerHelper {
if (deviceState != null && deviceState.isSAEnabled()) {
deviceState.setSAEnabled(false);
onRoutingUpdated();
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(deviceState, "removeCompatibleAudioDevice");
}
}
@@ -716,7 +716,7 @@ public class SpatializerHelper {
ada.getAddress());
initSAState(deviceState);
mDeviceBroker.addOrUpdateDeviceSAStateInInventory(deviceState);
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(deviceState, "addWirelessDeviceIfNew"); // may be updated later.
}
}
@@ -1206,7 +1206,7 @@ public class SpatializerHelper {
}
Log.i(TAG, "setHeadTrackerEnabled enabled:" + enabled + " device:" + ada);
deviceState.setHeadTrackerEnabled(enabled);
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(deviceState, "setHeadTrackerEnabled");
// check current routing to see if it affects the headtracking mode
@@ -1248,7 +1248,7 @@ public class SpatializerHelper {
if (deviceState != null) {
if (!deviceState.hasHeadTracker()) {
deviceState.setHasHeadTracker(true);
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(deviceState, "setHasHeadTracker");
}
return deviceState.isHeadTrackerEnabled();
@@ -1631,25 +1631,33 @@ public class SpatializerHelper {
return headHandle;
}
final AudioDeviceAttributes currentDevice = sRoutingDevices.get(0);
- UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(currentDevice);
+ List<String> deviceAddresses = mAudioService.getDeviceAddresses(currentDevice);
+
// We limit only to Sensor.TYPE_HEAD_TRACKER here to avoid confusion
// with gaming sensors. (Note that Sensor.TYPE_ROTATION_VECTOR
// and Sensor.TYPE_GAME_ROTATION_VECTOR are supported internally by
// SensorPoseProvider).
// Note: this is a dynamic sensor list right now.
List<Sensor> sensors = mSensorManager.getDynamicSensorList(Sensor.TYPE_HEAD_TRACKER);
- for (Sensor sensor : sensors) {
- final UUID uuid = sensor.getUuid();
- if (uuid.equals(routingDeviceUuid)) {
- headHandle = sensor.getHandle();
- if (!setHasHeadTracker(currentDevice)) {
- headHandle = -1;
+ for (String address : deviceAddresses) {
+ UUID routingDeviceUuid = UuidUtils.uuidFromAudioDeviceAttributes(
+ new AudioDeviceAttributes(currentDevice.getInternalType(), address));
+ for (Sensor sensor : sensors) {
+ final UUID uuid = sensor.getUuid();
+ if (uuid.equals(routingDeviceUuid)) {
+ headHandle = sensor.getHandle();
+ if (!setHasHeadTracker(currentDevice)) {
+ headHandle = -1;
+ }
+ break;
+ }
+ if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
+ headHandle = sensor.getHandle();
+ // we do not break, perhaps we find a head tracker on device.
}
- break;
}
- if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
- headHandle = sensor.getHandle();
- // we do not break, perhaps we find a head tracker on device.
+ if (headHandle != -1) {
+ break;
}
}
return headHandle;
diff --git a/services/core/java/com/android/server/criticalevents/CriticalEventLog.java b/services/core/java/com/android/server/criticalevents/CriticalEventLog.java
index ab480e8e8852..08143759fab4 100644
--- a/services/core/java/com/android/server/criticalevents/CriticalEventLog.java
+++ b/services/core/java/com/android/server/criticalevents/CriticalEventLog.java
@@ -31,6 +31,7 @@ import com.android.server.criticalevents.nano.CriticalEventProto.AppNotRespondin
import com.android.server.criticalevents.nano.CriticalEventProto.HalfWatchdog;
import com.android.server.criticalevents.nano.CriticalEventProto.JavaCrash;
import com.android.server.criticalevents.nano.CriticalEventProto.NativeCrash;
+import com.android.server.criticalevents.nano.CriticalEventProto.SystemServerStarted;
import com.android.server.criticalevents.nano.CriticalEventProto.Watchdog;
import java.io.File;
@@ -141,6 +142,13 @@ public class CriticalEventLog {
return System.currentTimeMillis();
}
+ /** Logs when system server started. */
+ public void logSystemServerStarted() {
+ CriticalEventProto event = new CriticalEventProto();
+ event.setSystemServerStarted(new SystemServerStarted());
+ log(event);
+ }
+
/** Logs a watchdog. */
public void logWatchdog(String subject, UUID uuid) {
Watchdog watchdog = new Watchdog();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 71562dc1ed86..9802adf302d1 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -26,6 +26,7 @@ import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
+import android.app.Flags;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
@@ -670,14 +671,37 @@ public class ZenModeHelper {
if (rule.enabled != automaticZenRule.isEnabled()) {
rule.snoozing = false;
}
+ if (Flags.modesApi()) {
+ rule.allowManualInvocation = automaticZenRule.isManualInvocationAllowed();
+ rule.iconResId = automaticZenRule.getIconResId();
+ rule.triggerDescription = automaticZenRule.getTriggerDescription();
+ rule.type = automaticZenRule.getType();
+ }
}
protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
- AutomaticZenRule azr = new AutomaticZenRule(rule.name, rule.component,
- rule.configurationActivity,
- rule.conditionId, rule.zenPolicy,
- NotificationManager.zenModeToInterruptionFilter(rule.zenMode),
- rule.enabled, rule.creationTime);
+ AutomaticZenRule azr;
+ if (Flags.modesApi()) {
+ azr = new AutomaticZenRule.Builder(rule.name, rule.conditionId)
+ .setManualInvocationAllowed(rule.allowManualInvocation)
+ .setCreationTime(rule.creationTime)
+ .setIconResId(rule.iconResId)
+ .setType(rule.type)
+ .setZenPolicy(rule.zenPolicy)
+ .setEnabled(rule.enabled)
+ .setInterruptionFilter(
+ NotificationManager.zenModeToInterruptionFilter(rule.zenMode))
+ .setOwner(rule.component)
+ .setConfigurationActivity(rule.configurationActivity)
+ .setTriggerDescription(rule.triggerDescription)
+ .build();
+ } else {
+ azr = new AutomaticZenRule(rule.name, rule.component,
+ rule.configurationActivity,
+ rule.conditionId, rule.zenPolicy,
+ NotificationManager.zenModeToInterruptionFilter(rule.zenMode),
+ rule.enabled, rule.creationTime);
+ }
azr.setPackageName(rule.pkg);
return azr;
}
@@ -713,6 +737,9 @@ public class ZenModeHelper {
newRule.zenMode = zenMode;
newRule.conditionId = conditionId;
newRule.enabler = caller;
+ if (Flags.modesApi()) {
+ newRule.allowManualInvocation = true;
+ }
newConfig.manualRule = newRule;
}
setConfigLocked(newConfig, reason, null, setRingerMode, callingUid,
diff --git a/services/core/java/com/android/server/timedetector/TEST_MAPPING b/services/core/java/com/android/server/timedetector/TEST_MAPPING
index f1bfea760792..5c37680af745 100644
--- a/services/core/java/com/android/server/timedetector/TEST_MAPPING
+++ b/services/core/java/com/android/server/timedetector/TEST_MAPPING
@@ -1,14 +1,6 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timedetector."
- }
- ]
- },
- {
"name": "CtsTimeTestCases",
"options": [
{
@@ -16,5 +8,11 @@
}
]
}
+ ],
+ // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
+ "postsubmit": [
+ {
+ "name": "FrameworksTimeServicesTests"
+ }
]
}
diff --git a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
index 455accdd198a..63dd7b42f23b 100644
--- a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
+++ b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
@@ -1,14 +1,6 @@
{
"presubmit": [
- {
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timezonedetector."
- }
- ]
- },
- {
+ {
"name": "CtsTimeTestCases",
"options": [
{
@@ -21,6 +13,9 @@
"postsubmit": [
{
"name": "CtsLocationTimeZoneManagerHostTest"
+ },
+ {
+ "name": "FrameworksTimeServicesTests"
}
]
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 4a5311b14397..2c492035140b 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -269,12 +269,27 @@ public class ActivityStartController {
}
}
+ /**
+ * Start intent as a package.
+ *
+ * @param uid Make a call as if this UID did.
+ * @param callingPackage Make a call as if this package did.
+ * @param callingFeatureId Make a call as if this feature in the package did.
+ * @param intent Intent to start.
+ * @param userId Start the intents on this user.
+ * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
+ * @param originatingPendingIntent PendingIntentRecord that originated this activity start or
+ * null if not originated by PendingIntent
+ * @param forcedBalByPiSender If set to allow, the
+ * PendingIntent's sender will try to force allow background activity starts.
+ * This is only possible if the sender of the PendingIntent is a system process.
+ */
final int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
String callingPackage, @Nullable String callingFeatureId, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges) {
+ BackgroundStartPrivileges forcedBalByPiSender) {
userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
reason);
@@ -295,7 +310,7 @@ public class ActivityStartController {
.setUserId(userId)
.setInTask(inTask)
.setOriginatingPendingIntent(originatingPendingIntent)
- .setBackgroundStartPrivileges(backgroundStartPrivileges)
+ .setBackgroundStartPrivileges(forcedBalByPiSender)
.execute();
}
@@ -310,15 +325,18 @@ public class ActivityStartController {
* @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
* @param originatingPendingIntent PendingIntentRecord that originated this activity start or
* null if not originated by PendingIntent
+ * @param forcedBalByPiSender If set to allow, the
+ * PendingIntent's sender will try to force allow background activity starts.
+ * This is only possible if the sender of the PendingIntent is a system process.
*/
final int startActivitiesInPackage(int uid, String callingPackage,
@Nullable String callingFeatureId, Intent[] intents, String[] resolvedTypes,
IBinder resultTo, SafeActivityOptions options, int userId, boolean validateIncomingUser,
PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges) {
+ BackgroundStartPrivileges forcedBalByPiSender) {
return startActivitiesInPackage(uid, 0 /* realCallingPid */, -1 /* realCallingUid */,
callingPackage, callingFeatureId, intents, resolvedTypes, resultTo, options, userId,
- validateIncomingUser, originatingPendingIntent, backgroundStartPrivileges);
+ validateIncomingUser, originatingPendingIntent, forcedBalByPiSender);
}
/**
@@ -333,12 +351,15 @@ public class ActivityStartController {
* @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
* @param originatingPendingIntent PendingIntentRecord that originated this activity start or
* null if not originated by PendingIntent
+ * @param forcedBalByPiSender If set to allow, the
+ * PendingIntent's sender will try to force allow background activity starts.
+ * This is only possible if the sender of the PendingIntent is a system process.
*/
final int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges) {
+ BackgroundStartPrivileges forcedBalByPiSender) {
final String reason = "startActivityInPackage";
@@ -348,14 +369,14 @@ public class ActivityStartController {
// TODO: Switch to user app stacks here.
return startActivities(null, uid, realCallingPid, realCallingUid, callingPackage,
callingFeatureId, intents, resolvedTypes, resultTo, options, userId, reason,
- originatingPendingIntent, backgroundStartPrivileges);
+ originatingPendingIntent, forcedBalByPiSender);
}
int startActivities(IApplicationThread caller, int callingUid, int incomingRealCallingPid,
int incomingRealCallingUid, String callingPackage, @Nullable String callingFeatureId,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options,
int userId, String reason, PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges) {
+ BackgroundStartPrivileges forcedBalByPiSender) {
if (intents == null) {
throw new NullPointerException("intents is null");
}
@@ -463,7 +484,7 @@ public class ActivityStartController {
// top one as otherwise an activity below might consume it.
.setAllowPendingRemoteAnimationRegistryLookup(top /* allowLookup*/)
.setOriginatingPendingIntent(originatingPendingIntent)
- .setBackgroundStartPrivileges(backgroundStartPrivileges);
+ .setBackgroundStartPrivileges(forcedBalByPiSender);
}
// Log if the activities to be started have different uids.
if (startingUidPkgs.size() > 1) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 34bf8edc148f..009b8e048840 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -388,7 +388,7 @@ class ActivityStarter {
WaitResult waitResult;
int filterCallingUid;
PendingIntentRecord originatingPendingIntent;
- BackgroundStartPrivileges backgroundStartPrivileges;
+ BackgroundStartPrivileges forcedBalByPiSender;
final StringBuilder logMessage = new StringBuilder();
@@ -451,7 +451,7 @@ class ActivityStarter {
allowPendingRemoteAnimationRegistryLookup = true;
filterCallingUid = UserHandle.USER_NULL;
originatingPendingIntent = null;
- backgroundStartPrivileges = BackgroundStartPrivileges.NONE;
+ forcedBalByPiSender = BackgroundStartPrivileges.NONE;
errorCallbackToken = null;
}
@@ -494,7 +494,7 @@ class ActivityStarter {
= request.allowPendingRemoteAnimationRegistryLookup;
filterCallingUid = request.filterCallingUid;
originatingPendingIntent = request.originatingPendingIntent;
- backgroundStartPrivileges = request.backgroundStartPrivileges;
+ forcedBalByPiSender = request.forcedBalByPiSender;
errorCallbackToken = request.errorCallbackToken;
}
@@ -1106,7 +1106,7 @@ class ActivityStarter {
realCallingPid,
callerApp,
request.originatingPendingIntent,
- request.backgroundStartPrivileges,
+ request.forcedBalByPiSender,
intent,
checkedOptions);
balCode = balVerdict.getCode();
@@ -3167,9 +3167,8 @@ class ActivityStarter {
return this;
}
- ActivityStarter setBackgroundStartPrivileges(
- BackgroundStartPrivileges backgroundStartPrivileges) {
- mRequest.backgroundStartPrivileges = backgroundStartPrivileges;
+ ActivityStarter setBackgroundStartPrivileges(BackgroundStartPrivileges forcedBalByPiSender) {
+ mRequest.forcedBalByPiSender = forcedBalByPiSender;
return this;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index a2547fd437d1..5604b1a6aa39 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -215,21 +215,39 @@ public abstract class ActivityTaskManagerInternal {
* @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
* @param originatingPendingIntent PendingIntentRecord that originated this activity start or
* null if not originated by PendingIntent
- * @param allowBackgroundActivityStart Whether the background activity start should be allowed
- * from originatingPendingIntent
+ * @param forcedBalByPiSender If set to allow, the
+ * PendingIntent's sender will try to force allow background activity starts.
+ * This is only possible if the sender of the PendingIntent is a system process.
*/
public abstract int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges);
+ BackgroundStartPrivileges forcedBalByPiSender);
+ /**
+ * Start intent as a package.
+ *
+ * @param uid Make a call as if this UID did.
+ * @param realCallingPid PID of the real caller.
+ * @param realCallingUid UID of the real caller.
+ * @param callingPackage Make a call as if this package did.
+ * @param callingFeatureId Make a call as if this feature in the package did.
+ * @param intent Intent to start.
+ * @param userId Start the intents on this user.
+ * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
+ * @param originatingPendingIntent PendingIntentRecord that originated this activity start or
+ * null if not originated by PendingIntent
+ * @param forcedBalByPiSender If set to allow, the
+ * PendingIntent's sender will try to force allow background activity starts.
+ * This is only possible if the sender of the PendingIntent is a system process.
+ */
public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
- String callingPackage, @Nullable String callingFeaturId, Intent intent,
+ String callingPackage, @Nullable String callingFeatureId, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges);
+ BackgroundStartPrivileges forcedBalByPiSender);
/**
* Callback to be called on certain activity start scenarios.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f462efc00ce6..a76fe287f313 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5911,12 +5911,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges) {
+ BackgroundStartPrivileges forcedBalByPiSender) {
assertPackageMatchesCallingUid(callingPackage);
return getActivityStartController().startActivitiesInPackage(uid, realCallingPid,
realCallingUid, callingPackage, callingFeatureId, intents, resolvedTypes,
resultTo, options, userId, validateIncomingUser, originatingPendingIntent,
- backgroundStartPrivileges);
+ forcedBalByPiSender);
}
@Override
@@ -5925,13 +5925,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges) {
+ BackgroundStartPrivileges forcedBalByPiSender) {
assertPackageMatchesCallingUid(callingPackage);
return getActivityStartController().startActivityInPackage(uid, realCallingPid,
realCallingUid, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, options, userId, inTask,
reason, validateIncomingUser, originatingPendingIntent,
- backgroundStartPrivileges);
+ forcedBalByPiSender);
}
@Override
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 2f9ef50297bf..1b5631f59a3e 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -195,6 +195,10 @@ public class BackgroundActivityStartController {
return activity != null && packageName.equals(activity.getPackageName());
}
+ /**
+ * @see #checkBackgroundActivityStart(int, int, String, int, int, WindowProcessController,
+ * PendingIntentRecord, BackgroundStartPrivileges, Intent, ActivityOptions)
+ */
boolean shouldAbortBackgroundActivityStart(
int callingUid,
int callingPid,
@@ -203,13 +207,13 @@ public class BackgroundActivityStartController {
int realCallingPid,
WindowProcessController callerApp,
PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges,
+ BackgroundStartPrivileges forcedBalByPiSender,
Intent intent,
ActivityOptions checkedOptions) {
return checkBackgroundActivityStart(callingUid, callingPid, callingPackage,
realCallingUid, realCallingPid,
callerApp, originatingPendingIntent,
- backgroundStartPrivileges, intent, checkedOptions).blocks();
+ forcedBalByPiSender, intent, checkedOptions).blocks();
}
private class BalState {
@@ -230,7 +234,7 @@ public class BackgroundActivityStartController {
private final @ActivityManager.ProcessState int mRealCallingUidProcState;
private final boolean mIsRealCallingUidPersistentSystemProcess;
private final PendingIntentRecord mOriginatingPendingIntent;
- private final BackgroundStartPrivileges mBackgroundStartPrivileges;
+ private final BackgroundStartPrivileges mForcedBalByPiSender;
private final Intent mIntent;
private final WindowProcessController mCallerApp;
private final WindowProcessController mRealCallerApp;
@@ -239,7 +243,7 @@ public class BackgroundActivityStartController {
int realCallingUid, int realCallingPid,
WindowProcessController callerApp,
PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges,
+ BackgroundStartPrivileges forcedBalByPiSender,
Intent intent,
ActivityOptions checkedOptions) {
this.mCallingPackage = callingPackage;
@@ -248,7 +252,7 @@ public class BackgroundActivityStartController {
mRealCallingUid = realCallingUid;
mRealCallingPid = realCallingPid;
mCallerApp = callerApp;
- mBackgroundStartPrivileges = backgroundStartPrivileges;
+ mForcedBalByPiSender = forcedBalByPiSender;
mOriginatingPendingIntent = originatingPendingIntent;
mIntent = intent;
mRealCallingPackage = mService.getPackageNameIfUnique(realCallingUid, realCallingPid);
@@ -344,7 +348,7 @@ public class BackgroundActivityStartController {
.append(mIsRealCallingUidPersistentSystemProcess);
sb.append("; originatingPendingIntent: ").append(mOriginatingPendingIntent);
}
- sb.append("; backgroundStartPrivileges: ").append(mBackgroundStartPrivileges);
+ sb.append("; mForcedBalByPiSender: ").append(mForcedBalByPiSender);
sb.append("; intent: ").append(mIntent);
sb.append("; callerApp: ").append(mCallerApp);
if (isPendingIntent()) {
@@ -422,8 +426,26 @@ public class BackgroundActivityStartController {
}
/**
- * @return A code denoting which BAL rule allows an activity to be started,
- * or {@link #BAL_BLOCK} if the launch should be blocked
+ * Check if a (background) activity start is allowed.
+ *
+ * @param callingUid The UID that wants to start the activity.
+ * @param callingPid The PID that wants to start the activity.
+ * @param callingPackage The package name that wants to start the activity.
+ * @param realCallingUid The UID that actually calls this method (only if this handles a
+ * PendingIntent, otherwise -1)
+ * @param realCallingPid The PID that actually calls this method (only if this handles a
+ * * PendingIntent, otherwise -1)
+ * @param callerApp The process that calls this method (only if not a PendingIntent)
+ * @param originatingPendingIntent PendingIntentRecord that originated this activity start or
+ * null if not originated by PendingIntent
+ * @param forcedBalByPiSender If set to allow, the
+ * PendingIntent's sender will try to force allow background activity starts.
+ * This is only possible if the sender of the PendingIntent is a system process.
+ * @param intent Intent that should be started.
+ * @param checkedOptions ActivityOptions to allow specific opt-ins/opt outs.
+ *
+ * @return A verdict denoting which BAL rule allows an activity to be started,
+ * or if the launch should be blocked.
*/
BalVerdict checkBackgroundActivityStart(
int callingUid,
@@ -433,7 +455,7 @@ public class BackgroundActivityStartController {
int realCallingPid,
WindowProcessController callerApp,
PendingIntentRecord originatingPendingIntent,
- BackgroundStartPrivileges backgroundStartPrivileges,
+ BackgroundStartPrivileges forcedBalByPiSender,
Intent intent,
ActivityOptions checkedOptions) {
@@ -444,7 +466,7 @@ public class BackgroundActivityStartController {
BalState state = new BalState(callingUid, callingPid, callingPackage,
realCallingUid, realCallingPid, callerApp, originatingPendingIntent,
- backgroundStartPrivileges, intent, checkedOptions);
+ forcedBalByPiSender, intent, checkedOptions);
// In the case of an SDK sandbox calling uid, check if the corresponding app uid has a
// visible window.
@@ -708,12 +730,12 @@ public class BackgroundActivityStartController {
}
// if the realCallingUid is a persistent system process, abort if the IntentSender
// wasn't allowed to start an activity
- if (state.mIsRealCallingUidPersistentSystemProcess
- && state.mBackgroundStartPrivileges.allowsBackgroundActivityStarts()) {
+ if (state.mForcedBalByPiSender.allowsBackgroundActivityStarts()
+ && state.mIsRealCallingUidPersistentSystemProcess) {
return new BalVerdict(BAL_ALLOW_PENDING_INTENT,
/*background*/ false,
"realCallingUid is persistent system process AND intent "
- + "sender allowed (allowBackgroundActivityStart = true).");
+ + "sender forced to allow.");
}
// don't abort if the realCallingUid is an associated companion app
if (mService.isAssociatedCompanionApp(
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 00f2b8963350..2f52de4cb765 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -274,11 +274,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
boolean mClearedForReorderActivityToFront;
/**
- * Whether the TaskFragment surface is managed by a system {@link TaskFragmentOrganizer}.
- */
- boolean mIsSurfaceManagedBySystemOrganizer = false;
-
- /**
* When we are in the process of pausing an activity, before starting the
* next one, this variable holds the activity that is currently being paused.
*
@@ -453,21 +448,13 @@ class TaskFragment extends WindowContainer<WindowContainer> {
void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid,
@NonNull String processName) {
- setTaskFragmentOrganizer(organizer, uid, processName,
- false /* isSurfaceManagedBySystemOrganizer */);
- }
-
- void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid,
- @NonNull String processName, boolean isSurfaceManagedBySystemOrganizer) {
mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.asBinder());
mTaskFragmentOrganizerUid = uid;
mTaskFragmentOrganizerProcessName = processName;
- mIsSurfaceManagedBySystemOrganizer = isSurfaceManagedBySystemOrganizer;
}
void onTaskFragmentOrganizerRemoved() {
mTaskFragmentOrganizer = null;
- mIsSurfaceManagedBySystemOrganizer = false;
}
/** Whether this TaskFragment is organized by the given {@code organizer}. */
@@ -2454,9 +2441,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (mDelayOrganizedTaskFragmentSurfaceUpdate || mTaskFragmentOrganizer == null) {
return;
}
- if (mIsSurfaceManagedBySystemOrganizer) {
- return;
- }
if (mTransitionController.isShellTransitionsEnabled()
&& !mTransitionController.isCollecting(this)) {
// TaskFragmentOrganizer doesn't have access to the surface for security reasons, so
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 95e25151e8cc..89d47bcf41d5 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -2122,8 +2122,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// actions.
TaskFragmentOrganizerToken organizerToken = creationParams.getOrganizer();
taskFragment.setTaskFragmentOrganizer(organizerToken,
- ownerActivity.getUid(), ownerActivity.info.processName,
- mTaskFragmentOrganizerController.isSystemOrganizer(organizerToken.asBinder()));
+ ownerActivity.getUid(), ownerActivity.info.processName);
final int position;
if (creationParams.getPairedPrimaryFragmentToken() != null) {
// When there is a paired primary TaskFragment, we want to place the new TaskFragment
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 56e385d535a0..0a2e80606e96 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -129,6 +129,7 @@ import com.android.server.connectivity.PacProxyService;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.coverage.CoverageService;
import com.android.server.cpu.CpuMonitorService;
+import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.devicestate.DeviceStateManagerService;
import com.android.server.display.DisplayManagerService;
@@ -964,6 +965,7 @@ public final class SystemServer implements Dumpable {
// Only update the timeout after starting all the services so that we use
// the default timeout to start system server.
updateWatchdogTimeout(t);
+ CriticalEventLog.getInstance().logSystemServerStarted();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
diff --git a/services/tests/servicestests/src/com/android/internal/location/timezone/OWNERS b/services/tests/servicestests/src/com/android/internal/location/timezone/OWNERS
deleted file mode 100644
index 28aff188dbd8..000000000000
--- a/services/tests/servicestests/src/com/android/internal/location/timezone/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 847766
-nfuller@google.com
-include /core/java/android/app/timedetector/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
index ad09ef0ccdc1..061b8ffa05a2 100644
--- a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
@@ -79,7 +79,7 @@ public class SpatializerHelperTest {
final AudioDeviceAttributes dev3 =
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "R2:D2:bloop");
- doNothing().when(mSpyDeviceBroker).persistAudioDeviceSettings();
+ doNothing().when(mSpyDeviceBroker).postPersistAudioDeviceSettings();
mSpatHelper.initForTest(true /*binaural*/, true /*transaural*/);
// test with single device
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/OWNERS b/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
deleted file mode 100644
index a0f46e172da6..000000000000
--- a/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 847766
-include /services/core/java/com/android/server/timedetector/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/timedetector/TEST_MAPPING
deleted file mode 100644
index a83d8bf20dc6..000000000000
--- a/services/tests/servicestests/src/com/android/server/timedetector/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
- "postsubmit": [
- {
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timedetector."
- }
- ]
- }
- ]
-}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/timezone/OWNERS
deleted file mode 100644
index d64cbcdc2814..000000000000
--- a/services/tests/servicestests/src/com/android/server/timezone/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 847766
-include /services/core/java/com/android/server/timezone/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/timezonedetector/TEST_MAPPING
deleted file mode 100644
index f59188cb9a52..000000000000
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
- "postsubmit": [
- {
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timezonedetector."
- }
- ]
- }
- ]
-}
diff --git a/services/tests/timetests/Android.bp b/services/tests/timetests/Android.bp
new file mode 100644
index 000000000000..23ab85996fff
--- /dev/null
+++ b/services/tests/timetests/Android.bp
@@ -0,0 +1,27 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FrameworksTimeServicesTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "device-time-shell-utils",
+ "junit",
+ "junit-params",
+ "mockito-target-minus-junit4",
+ "platform-test-annotations",
+ "services.core",
+ "truth",
+ ],
+ libs: ["android.test.runner"],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+}
diff --git a/services/tests/timetests/AndroidManifest.xml b/services/tests/timetests/AndroidManifest.xml
new file mode 100644
index 000000000000..62fbb05ee1e1
--- /dev/null
+++ b/services/tests/timetests/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.framework.services.tests.time">
+
+ <!-- Required for user checks -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.framework.services.tests.time"
+ android:label="Frameworks Time Services Tests" />
+
+</manifest>
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS b/services/tests/timetests/OWNERS
index a6ff1ba8a8cb..a6ff1ba8a8cb 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS
+++ b/services/tests/timetests/OWNERS
diff --git a/services/tests/timetests/TEST_MAPPING b/services/tests/timetests/TEST_MAPPING
new file mode 100644
index 000000000000..b24010ce447a
--- /dev/null
+++ b/services/tests/timetests/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+ // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows.
+ "postsubmit": [
+ {
+ "name": "FrameworksTimeServicesTests"
+ }
+ ]
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/ArrayMapWithHistoryTest.java b/services/tests/timetests/src/com/android/server/timedetector/ArrayMapWithHistoryTest.java
index b6eea461d222..b6eea461d222 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/ArrayMapWithHistoryTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/ArrayMapWithHistoryTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java b/services/tests/timetests/src/com/android/server/timedetector/ConfigurationInternalTest.java
index 808c1ec2603b..392a48f5a7ca 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/ConfigurationInternalTest.java
@@ -33,14 +33,14 @@ import android.app.time.TimeConfiguration;
import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Instant;
-import junitparams.JUnitParamsRunner;
-import junitparams.Parameters;
-
/**
* Tests for {@link ConfigurationInternal} and associated {@link TimeCapabilitiesAndConfig}
* behavior.
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java b/services/tests/timetests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java
index d9bc74dfb1cb..d9bc74dfb1cb 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java b/services/tests/timetests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
index a7a9c0cd86f2..a7a9c0cd86f2 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeSuggestionTest.java b/services/tests/timetests/src/com/android/server/timedetector/GnssTimeSuggestionTest.java
index 57d546929d8b..57d546929d8b 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeSuggestionTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/GnssTimeSuggestionTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java b/services/tests/timetests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
index c8afb78bc12f..c8afb78bc12f 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeSuggestionTest.java b/services/tests/timetests/src/com/android/server/timedetector/NetworkTimeSuggestionTest.java
index fcc76d37de2b..fcc76d37de2b 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeSuggestionTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/NetworkTimeSuggestionTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java b/services/tests/timetests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java
index d91ee92e005e..d91ee92e005e 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java b/services/tests/timetests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java
index d5d2cbd0749e..d5d2cbd0749e 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java b/services/tests/timetests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
index de5a37b43df8..de5a37b43df8 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/timetests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 6b2d4b01dd08..6b2d4b01dd08 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/timetests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index dd58135a8e87..c64ec724b641 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/timetests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -51,6 +51,9 @@ import com.android.server.timedetector.TimeDetectorStrategy.Origin;
import com.android.server.timezonedetector.StateChangeListener;
import com.android.server.timezonedetector.TestStateChangeListener;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -62,9 +65,6 @@ import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
-import junitparams.JUnitParamsRunner;
-import junitparams.Parameters;
-
@RunWith(JUnitParamsRunner.class)
public class TimeDetectorStrategyImplTest {
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index 566c6b03555d..c77fe3943b95 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -35,12 +35,12 @@ import android.app.time.TimeZoneCapabilities;
import android.app.time.TimeZoneCapabilitiesAndConfig;
import android.app.time.TimeZoneConfiguration;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
/**
* Tests for {@link ConfigurationInternal} and associated {@link TimeZoneCapabilitiesAndConfig}
* behavior.
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java b/services/tests/timetests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java
index fc6afe486187..fc6afe486187 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/timetests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index 1e72369ac3a6..74393070209e 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -43,7 +43,7 @@ public class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
this::notifyChangeListeners);
}
- public void initializeConfigurationAndStatus(
+ void initializeConfigurationAndStatus(
ConfigurationInternal configuration, TimeZoneDetectorStatus status) {
mFakeServiceConfigAccessor.initializeCurrentUserConfiguration(configuration);
mStatus = Objects.requireNonNull(status);
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/GeolocationTimeZoneSuggestionTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/GeolocationTimeZoneSuggestionTest.java
index 602842addff2..602842addff2 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/GeolocationTimeZoneSuggestionTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/GeolocationTimeZoneSuggestionTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/LocationAlgorithmEventTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/LocationAlgorithmEventTest.java
index 4c14014405f4..4c14014405f4 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/LocationAlgorithmEventTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/LocationAlgorithmEventTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java
index 8207c1915edb..8207c1915edb 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java
index 3fdac66225a8..3fdac66225a8 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ShellCommandTestSupport.java b/services/tests/timetests/src/com/android/server/timezonedetector/ShellCommandTestSupport.java
index b96c82fc396c..72b181984123 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ShellCommandTestSupport.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/ShellCommandTestSupport.java
@@ -29,10 +29,17 @@ import java.util.List;
public final class ShellCommandTestSupport {
private ShellCommandTestSupport() {}
+ /**
+ * Returns a {@link ShellCommand} from the supplied String, where elements of the command are
+ * separated with spaces. No escaping is performed.
+ */
public static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) {
return createShellCommandWithArgsAndOptions(Arrays.asList(argsWithSpaces.split(" ")));
}
+ /**
+ * Returns a {@link ShellCommand} from the supplied list of command line elements.
+ */
public static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) {
ShellCommand command = mock(ShellCommand.class);
class ArgProvider {
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java b/services/tests/timetests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java
index f45b3a822f1a..67b8cc22fac0 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java
@@ -28,6 +28,7 @@ public class TestCallerIdentityInjector implements CallerIdentityInjector {
private int mCallingUserId;
private Integer mCurrentCallingUserId;
+ /** Initializes the calling user ID. */
public void initializeCallingUserId(@UserIdInt int userId) {
mCallingUserId = userId;
mCurrentCallingUserId = userId;
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestCurrentUserIdentityInjector.java b/services/tests/timetests/src/com/android/server/timezonedetector/TestCurrentUserIdentityInjector.java
index aad06d87f111..61f92602295c 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TestCurrentUserIdentityInjector.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TestCurrentUserIdentityInjector.java
@@ -23,6 +23,7 @@ public class TestCurrentUserIdentityInjector implements CurrentUserIdentityInjec
private Integer mCurrentUserId;
+ /** Initializes the current user ID. */
public void initializeCurrentUserId(@UserIdInt int userId) {
mCurrentUserId = userId;
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestHandler.java b/services/tests/timetests/src/com/android/server/timezonedetector/TestHandler.java
index eb6f00c9250b..eb6f00c9250b 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TestHandler.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TestHandler.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java b/services/tests/timetests/src/com/android/server/timezonedetector/TestState.java
index 97095c4f675f..97095c4f675f 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TestState.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestStateChangeListener.java b/services/tests/timetests/src/com/android/server/timezonedetector/TestStateChangeListener.java
index 9cbf0a34f8fe..23f96a21786b 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TestStateChangeListener.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TestStateChangeListener.java
@@ -27,6 +27,7 @@ public class TestStateChangeListener implements StateChangeListener {
mNotificationsReceived++;
}
+ /** Asserts the expected number of notifications have been received, then resets the count. */
public void assertNotificationsReceivedAndReset(int expectedCount) {
assertNotificationsReceived(expectedCount);
resetNotificationsReceivedCount();
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneCanonicalizerTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneCanonicalizerTest.java
index 0c78f5b85fac..0c78f5b85fac 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneCanonicalizerTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneCanonicalizerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
index a02c8ca001ce..a02c8ca001ce 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index d9d8053e6220..d9d8053e6220 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 03d406f94696..e52e8b60a61d 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -72,6 +72,9 @@ import android.service.timezone.TimeZoneProviderStatus;
import com.android.server.SystemTimeZone.TimeZoneConfidence;
import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -83,9 +86,6 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Function;
-import junitparams.JUnitParamsRunner;
-import junitparams.Parameters;
-
/**
* White-box unit tests for {@link TimeZoneDetectorStrategyImpl}.
*/
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java b/services/tests/timetests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java
index f8d169b54bca..e05d84f50465 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java
@@ -38,6 +38,7 @@ public final class FakeTimeZoneProviderEventPreProcessor
return timeZoneProviderEvent;
}
+ /** Enters a mode where {@link #preProcess} will always return "uncertain" events. */
public void enterUncertainMode() {
mIsUncertain = true;
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/HandlerThreadingDomainTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/location/HandlerThreadingDomainTest.java
index e7dd97949bb0..e7dd97949bb0 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/HandlerThreadingDomainTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/location/HandlerThreadingDomainTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
index 7ff015dd8370..7ff015dd8370 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
index 1ae74c679b53..1ae74c679b53 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java b/services/tests/timetests/src/com/android/server/timezonedetector/location/TestSupport.java
index 042e3ef892f9..042e3ef892f9 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/location/TestSupport.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestThreadingDomain.java b/services/tests/timetests/src/com/android/server/timezonedetector/location/TestThreadingDomain.java
index a3fb5e620c20..a3fb5e620c20 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestThreadingDomain.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/location/TestThreadingDomain.java
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java
index f3440f7c9d1c..f3440f7c9d1c 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 3ba94000d4a5..261b5d33b635 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.app.AutomaticZenRule.TYPE_BEDTIME;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
import static junit.framework.TestCase.assertEquals;
@@ -24,9 +25,12 @@ import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertNull;
import static junit.framework.TestCase.assertTrue;
+import android.app.Flags;
import android.app.NotificationManager.Policy;
import android.content.ComponentName;
import android.net.Uri;
+import android.os.Parcel;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
@@ -41,6 +45,7 @@ import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.UiServiceTestCase;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParserException;
@@ -55,6 +60,28 @@ import java.io.IOException;
@RunWith(AndroidJUnit4.class)
public class ZenModeConfigTest extends UiServiceTestCase {
+ private final String NAME = "name";
+ private final ComponentName OWNER = new ComponentName("pkg", "cls");
+ private final ComponentName CONFIG_ACTIVITY = new ComponentName("pkg", "act");
+ private final ZenPolicy POLICY = new ZenPolicy.Builder().allowAlarms(true).build();
+ private final Uri CONDITION_ID = new Uri.Builder().scheme("scheme")
+ .authority("authority")
+ .appendPath("path")
+ .appendPath("test")
+ .build();
+
+ private final Condition CONDITION = new Condition(CONDITION_ID, "", Condition.STATE_TRUE);
+ private final String TRIGGER_DESC = "Every Night, 10pm to 6am";
+ private final int TYPE = TYPE_BEDTIME;
+ private final boolean ALLOW_MANUAL = true;
+ private final int ICON_RES_ID = 1234;
+ private final int INTERRUPTION_FILTER = Settings.Global.ZEN_MODE_ALARMS;
+ private final boolean ENABLED = true;
+ private final int CREATION_TIME = 123;
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Test
public void testPriorityOnlyMutingAllNotifications() {
ZenModeConfig config = getMutedRingerConfig();
@@ -202,7 +229,59 @@ public class ZenModeConfigTest extends UiServiceTestCase {
}
@Test
- public void testRuleXml() throws Exception {
+ public void testWriteToParcel() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+
+ ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+ rule.configurationActivity = CONFIG_ACTIVITY;
+ rule.component = OWNER;
+ rule.conditionId = CONDITION_ID;
+ rule.condition = CONDITION;
+ rule.enabled = ENABLED;
+ rule.creationTime = 123;
+ rule.id = "id";
+ rule.zenMode = INTERRUPTION_FILTER;
+ rule.modified = true;
+ rule.name = NAME;
+ rule.snoozing = true;
+ rule.pkg = OWNER.getPackageName();
+ rule.zenPolicy = POLICY;
+
+ rule.allowManualInvocation = ALLOW_MANUAL;
+ rule.type = TYPE;
+ rule.iconResId = ICON_RES_ID;
+ rule.triggerDescription = TRIGGER_DESC;
+
+ Parcel parcel = Parcel.obtain();
+ rule.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ZenModeConfig.ZenRule parceled = new ZenModeConfig.ZenRule(parcel);
+
+ assertEquals(rule.pkg, parceled.pkg);
+ assertEquals(rule.snoozing, parceled.snoozing);
+ assertEquals(rule.enabler, parceled.enabler);
+ assertEquals(rule.component, parceled.component);
+ assertEquals(rule.configurationActivity, parceled.configurationActivity);
+ assertEquals(rule.condition, parceled.condition);
+ assertEquals(rule.enabled, parceled.enabled);
+ assertEquals(rule.creationTime, parceled.creationTime);
+ assertEquals(rule.modified, parceled.modified);
+ assertEquals(rule.conditionId, parceled.conditionId);
+ assertEquals(rule.name, parceled.name);
+ assertEquals(rule.zenMode, parceled.zenMode);
+
+ assertEquals(rule.allowManualInvocation, parceled.allowManualInvocation);
+ assertEquals(rule.iconResId, parceled.iconResId);
+ assertEquals(rule.type, parceled.type);
+ assertEquals(rule.triggerDescription, parceled.triggerDescription);
+ assertEquals(rule.zenPolicy, parceled.zenPolicy);
+ assertEquals(rule, parceled);
+ assertEquals(rule.hashCode(), parceled.hashCode());
+
+ }
+
+ @Test
+ public void testRuleXml_classic() throws Exception {
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = new ComponentName("a", "a");
rule.component = new ComponentName("b", "b");
@@ -239,6 +318,58 @@ public class ZenModeConfigTest extends UiServiceTestCase {
}
@Test
+ public void testRuleXml() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+
+ ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+ rule.configurationActivity = CONFIG_ACTIVITY;
+ rule.component = OWNER;
+ rule.conditionId = CONDITION_ID;
+ rule.condition = CONDITION;
+ rule.enabled = ENABLED;
+ rule.creationTime = 123;
+ rule.id = "id";
+ rule.zenMode = INTERRUPTION_FILTER;
+ rule.modified = true;
+ rule.name = NAME;
+ rule.snoozing = true;
+ rule.pkg = OWNER.getPackageName();
+ rule.zenPolicy = POLICY;
+ rule.creationTime = CREATION_TIME;
+
+ rule.allowManualInvocation = ALLOW_MANUAL;
+ rule.type = TYPE;
+ rule.iconResId = ICON_RES_ID;
+ rule.triggerDescription = TRIGGER_DESC;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ writeRuleXml(rule, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenModeConfig.ZenRule fromXml = readRuleXml(bais);
+
+ assertEquals(rule.pkg, fromXml.pkg);
+ // always resets on reboot
+ assertFalse(fromXml.snoozing);
+ //should all match original
+ assertEquals(rule.component, fromXml.component);
+ assertEquals(rule.configurationActivity, fromXml.configurationActivity);
+ assertNull(fromXml.enabler);
+ assertEquals(rule.condition, fromXml.condition);
+ assertEquals(rule.enabled, fromXml.enabled);
+ assertEquals(rule.creationTime, fromXml.creationTime);
+ assertEquals(rule.modified, fromXml.modified);
+ assertEquals(rule.conditionId, fromXml.conditionId);
+ assertEquals(rule.name, fromXml.name);
+ assertEquals(rule.zenMode, fromXml.zenMode);
+ assertEquals(rule.creationTime, fromXml.creationTime);
+
+ assertEquals(rule.allowManualInvocation, fromXml.allowManualInvocation);
+ assertEquals(rule.type, fromXml.type);
+ assertEquals(rule.triggerDescription, fromXml.triggerDescription);
+ assertEquals(rule.iconResId, fromXml.iconResId);
+ }
+
+ @Test
public void testRuleXml_pkg_component() throws Exception {
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = new ComponentName("a", "a");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
index bcd807ab6d2f..fd3d5e9bf863 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
@@ -23,6 +23,7 @@ import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+import android.app.AutomaticZenRule;
import android.content.ComponentName;
import android.net.Uri;
import android.provider.Settings;
@@ -229,6 +230,10 @@ public class ZenModeDiffTest extends UiServiceTestCase {
rule.name = "name";
rule.snoozing = true;
rule.pkg = "a";
+ rule.allowManualInvocation = true;
+ rule.type = AutomaticZenRule.TYPE_SCHEDULE_TIME;
+ rule.iconResId = 123;
+ rule.triggerDescription = "At night";
return rule;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index e22c10489d4d..0349ad9e30c7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.app.AutomaticZenRule.TYPE_BEDTIME;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
@@ -71,6 +72,7 @@ import android.annotation.SuppressLint;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
+import android.app.Flags;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.ComponentName;
@@ -88,6 +90,7 @@ import android.media.VolumePolicy;
import android.net.Uri;
import android.os.Process;
import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.Condition;
@@ -120,6 +123,7 @@ import com.google.common.collect.ImmutableList;
import com.google.protobuf.InvalidProtocolBufferException;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -150,6 +154,28 @@ public class ZenModeHelperTest extends UiServiceTestCase {
private static final int CUSTOM_PKG_UID = 1;
private static final String CUSTOM_RULE_ID = "custom_rule";
+ private final String NAME = "name";
+ private final ComponentName OWNER = new ComponentName("pkg", "cls");
+ private final ComponentName CONFIG_ACTIVITY = new ComponentName("pkg", "act");
+ private final ZenPolicy POLICY = new ZenPolicy.Builder().allowAlarms(true).build();
+ private final Uri CONDITION_ID = new Uri.Builder().scheme("scheme")
+ .authority("authority")
+ .appendPath("path")
+ .appendPath("test")
+ .build();
+
+ private final Condition CONDITION = new Condition(CONDITION_ID, "", Condition.STATE_TRUE);
+ private final String TRIGGER_DESC = "Every Night, 10pm to 6am";
+ private final int TYPE = TYPE_BEDTIME;
+ private final boolean ALLOW_MANUAL = true;
+ private final int ICON_RES_ID = 1234;
+ private final int INTERRUPTION_FILTER = Settings.Global.ZEN_MODE_ALARMS;
+ private final boolean ENABLED = true;
+ private final int CREATION_TIME = 123;
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
ConditionProviders mConditionProviders;
@Mock NotificationManager mNotificationManager;
@Mock PackageManager mPackageManager;
@@ -1961,6 +1987,26 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testSetManualZenMode() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+ setupZenConfig();
+
+ // note that caller=null because that's how it comes in from NMS.setZenMode
+ mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, "",
+ Process.SYSTEM_UID, true);
+
+ // confirm that setting zen mode via setManualZenMode changed the zen mode correctly
+ assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeHelper.mZenMode);
+ assertEquals(true, mZenModeHelper.mConfig.manualRule.allowManualInvocation);
+
+ // and also that it works to turn it back off again
+ mZenModeHelper.setManualZenMode(Global.ZEN_MODE_OFF, null, null, "",
+ Process.SYSTEM_UID, true);
+
+ assertEquals(Global.ZEN_MODE_OFF, mZenModeHelper.mZenMode);
+ }
+
+ @Test
+ public void testSetManualZenMode_legacy() {
setupZenConfig();
// note that caller=null because that's how it comes in from NMS.setZenMode
@@ -2607,6 +2653,47 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertFalse(mZenModeHelper.mConsolidatedPolicy.showPeeking()); // custom stricter
}
+ @Test
+ public void testCreateAutomaticZenRule_allFields() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+ ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+ rule.configurationActivity = CONFIG_ACTIVITY;
+ rule.component = OWNER;
+ rule.conditionId = CONDITION_ID;
+ rule.condition = CONDITION;
+ rule.enabled = ENABLED;
+ rule.creationTime = 123;
+ rule.id = "id";
+ rule.zenMode = INTERRUPTION_FILTER;
+ rule.modified = true;
+ rule.name = NAME;
+ rule.snoozing = true;
+ rule.pkg = OWNER.getPackageName();
+ rule.zenPolicy = POLICY;
+
+ rule.allowManualInvocation = ALLOW_MANUAL;
+ rule.type = TYPE;
+ rule.iconResId = ICON_RES_ID;
+ rule.triggerDescription = TRIGGER_DESC;
+
+ AutomaticZenRule actual = mZenModeHelper.createAutomaticZenRule(rule);
+
+ assertEquals(NAME, actual.getName());
+ assertEquals(OWNER, actual.getOwner());
+ assertEquals(CONDITION_ID, actual.getConditionId());
+ assertEquals(NotificationManager.INTERRUPTION_FILTER_ALARMS,
+ actual.getInterruptionFilter());
+ assertEquals(ENABLED, actual.isEnabled());
+ assertEquals(POLICY, actual.getZenPolicy());
+ assertEquals(CONFIG_ACTIVITY, actual.getConfigurationActivity());
+ assertEquals(TYPE, actual.getType());
+ assertEquals(ALLOW_MANUAL, actual.isManualInvocationAllowed());
+ assertEquals(CREATION_TIME, actual.getCreationTime());
+ assertEquals(OWNER.getPackageName(), actual.getPackageName());
+ assertEquals(ICON_RES_ID, actual.getIconResId());
+ assertEquals(TRIGGER_DESC, actual.getTriggerDescription());
+ }
+
private void setupZenConfig() {
mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
mZenModeHelper.mConfig.allowAlarms = false;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 7822071f3933..ec068bed1a3b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -27,12 +27,8 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -130,17 +126,6 @@ public class TaskFragmentTest extends WindowTestsBase {
}
@Test
- public void testUpdateOrganizedTaskFragmentSurface_noSurfaceUpdateWhenOrganizedBySystem() {
- clearInvocations(mTransaction);
- mTaskFragment.mIsSurfaceManagedBySystemOrganizer = true;
-
- mTaskFragment.updateOrganizedTaskFragmentSurface();
-
- verify(mTransaction, never()).setPosition(eq(mLeash), anyFloat(), anyFloat());
- verify(mTransaction, never()).setWindowCrop(eq(mLeash), anyInt(), anyInt());
- }
-
- @Test
public void testShouldStartChangeTransition_relativePositionChange() {
final Task task = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
ACTIVITY_TYPE_STANDARD);
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 11cbcb1c149d..4b1a72695e50 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -568,6 +568,7 @@ public class ApnSetting implements Parcelable {
private final int mSkip464Xlat;
private final boolean mAlwaysOn;
private final @InfrastructureBitmask int mInfrastructureBitmask;
+ private final boolean mEsimBootstrapProvisioning;
/**
* Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
@@ -979,6 +980,18 @@ public class ApnSetting implements Parcelable {
return mInfrastructureBitmask;
}
+ /**
+ * Returns esim bootstrap provisioning flag for which the APN can be used on. For example,
+ * some APNs are only allowed to bring up network, when the device esim bootstrap provisioning
+ * is being activated.
+ *
+ * {@code true} if the APN is used for eSIM bootstrap provisioning, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isEsimBootstrapProvisioning() {
+ return mEsimBootstrapProvisioning;
+ }
+
private ApnSetting(Builder builder) {
this.mEntryName = builder.mEntryName;
this.mApnName = builder.mApnName;
@@ -1016,6 +1029,7 @@ public class ApnSetting implements Parcelable {
this.mSkip464Xlat = builder.mSkip464Xlat;
this.mAlwaysOn = builder.mAlwaysOn;
this.mInfrastructureBitmask = builder.mInfrastructureBitmask;
+ this.mEsimBootstrapProvisioning = builder.mEsimBootstrapProvisioning;
}
/**
@@ -1097,6 +1111,8 @@ public class ApnSetting implements Parcelable {
.setAlwaysOn(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.ALWAYS_ON)) == 1)
.setInfrastructureBitmask(cursor.getInt(cursor.getColumnIndexOrThrow(
Telephony.Carriers.INFRASTRUCTURE_BITMASK)))
+ .setEsimBootstrapProvisioning(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Carriers.ESIM_BOOTSTRAP_PROVISIONING)) == 1)
.buildWithoutCheck();
}
@@ -1137,6 +1153,7 @@ public class ApnSetting implements Parcelable {
.setSkip464Xlat(apn.mSkip464Xlat)
.setAlwaysOn(apn.mAlwaysOn)
.setInfrastructureBitmask(apn.mInfrastructureBitmask)
+ .setEsimBootstrapProvisioning(apn.mEsimBootstrapProvisioning)
.buildWithoutCheck();
}
@@ -1184,6 +1201,7 @@ public class ApnSetting implements Parcelable {
sb.append(", ").append(mAlwaysOn);
sb.append(", ").append(mInfrastructureBitmask);
sb.append(", ").append(Objects.hash(mUser, mPassword));
+ sb.append(", ").append(mEsimBootstrapProvisioning);
return sb.toString();
}
@@ -1247,7 +1265,7 @@ public class ApnSetting implements Parcelable {
mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask,
mLingeringNetworkTypeBitmask, mProfileId, mPersistent, mMaxConns, mWaitTime,
mMaxConnsTime, mMvnoType, mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat,
- mAlwaysOn, mInfrastructureBitmask);
+ mAlwaysOn, mInfrastructureBitmask, mEsimBootstrapProvisioning);
}
@Override
@@ -1289,7 +1307,8 @@ public class ApnSetting implements Parcelable {
&& mCarrierId == other.mCarrierId
&& mSkip464Xlat == other.mSkip464Xlat
&& mAlwaysOn == other.mAlwaysOn
- && mInfrastructureBitmask == other.mInfrastructureBitmask;
+ && mInfrastructureBitmask == other.mInfrastructureBitmask
+ && mEsimBootstrapProvisioning == other.mEsimBootstrapProvisioning;
}
/**
@@ -1340,7 +1359,8 @@ public class ApnSetting implements Parcelable {
&& Objects.equals(mCarrierId, other.mCarrierId)
&& Objects.equals(mSkip464Xlat, other.mSkip464Xlat)
&& Objects.equals(mAlwaysOn, other.mAlwaysOn)
- && Objects.equals(mInfrastructureBitmask, other.mInfrastructureBitmask);
+ && Objects.equals(mInfrastructureBitmask, other.mInfrastructureBitmask)
+ && Objects.equals(mEsimBootstrapProvisioning, other.mEsimBootstrapProvisioning);
}
/**
@@ -1378,7 +1398,9 @@ public class ApnSetting implements Parcelable {
&& Objects.equals(this.mCarrierId, other.mCarrierId)
&& Objects.equals(this.mSkip464Xlat, other.mSkip464Xlat)
&& Objects.equals(this.mAlwaysOn, other.mAlwaysOn)
- && Objects.equals(this.mInfrastructureBitmask, other.mInfrastructureBitmask);
+ && Objects.equals(this.mInfrastructureBitmask, other.mInfrastructureBitmask)
+ && Objects.equals(this.mEsimBootstrapProvisioning,
+ other.mEsimBootstrapProvisioning);
}
// Equal or one is null.
@@ -1451,6 +1473,7 @@ public class ApnSetting implements Parcelable {
apnValue.put(Telephony.Carriers.SKIP_464XLAT, mSkip464Xlat);
apnValue.put(Telephony.Carriers.ALWAYS_ON, mAlwaysOn);
apnValue.put(Telephony.Carriers.INFRASTRUCTURE_BITMASK, mInfrastructureBitmask);
+ apnValue.put(Telephony.Carriers.ESIM_BOOTSTRAP_PROVISIONING, mEsimBootstrapProvisioning);
return apnValue;
}
@@ -1724,6 +1747,7 @@ public class ApnSetting implements Parcelable {
dest.writeInt(mSkip464Xlat);
dest.writeBoolean(mAlwaysOn);
dest.writeInt(mInfrastructureBitmask);
+ dest.writeBoolean(mEsimBootstrapProvisioning);
}
private static ApnSetting readFromParcel(Parcel in) {
@@ -1760,6 +1784,7 @@ public class ApnSetting implements Parcelable {
.setSkip464Xlat(in.readInt())
.setAlwaysOn(in.readBoolean())
.setInfrastructureBitmask(in.readInt())
+ .setEsimBootstrapProvisioning(in.readBoolean())
.buildWithoutCheck();
}
@@ -1842,6 +1867,7 @@ public class ApnSetting implements Parcelable {
private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT;
private boolean mAlwaysOn;
private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR;
+ private boolean mEsimBootstrapProvisioning;
/**
* Default constructor for Builder.
@@ -2280,6 +2306,19 @@ public class ApnSetting implements Parcelable {
}
/**
+ * Sets esim bootstrap provisioning flag
+ *
+ * @param esimBootstrapProvisioning {@code true} if the APN is used for eSIM bootstrap
+ * provisioning, {@code false} otherwise.
+ * @hide
+ */
+ @NonNull
+ public Builder setEsimBootstrapProvisioning(boolean esimBootstrapProvisioning) {
+ this.mEsimBootstrapProvisioning = esimBootstrapProvisioning;
+ return this;
+ }
+
+ /**
* Builds {@link ApnSetting} from this builder.
*
* @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)}
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp b/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp
new file mode 100644
index 000000000000..afaa3f0f293f
--- /dev/null
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "ConcurrentMultiSessionImeTest",
+ srcs: ["src/**/*.java"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "platform-test-annotations",
+ "platform-test-rules",
+ "truth",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ sdk_version: "current",
+
+ // Store test artifacts in separated directories for easier debugging.
+ per_testcase_directory: true,
+}
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/AndroidManifest.xml b/tests/inputmethod/ConcurrentMultiSessionImeTest/AndroidManifest.xml
new file mode 100644
index 000000000000..0defe5b3f2ff
--- /dev/null
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.inputmethod.multisessiontest">
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.inputmethod.multisessiontest"></instrumentation>
+</manifest>
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/AndroidTest.xml b/tests/inputmethod/ConcurrentMultiSessionImeTest/AndroidTest.xml
new file mode 100644
index 000000000000..fd598c568974
--- /dev/null
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/AndroidTest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Config for Concurrent Multi-Session IME tests">
+ <object class="com.android.tradefed.testtype.suite.module.DeviceFeatureModuleController"
+ type="module_controller">
+ <option name="required-feature" value="android.software.input_methods" />
+
+ <!-- Currently enabled to automotive only -->
+ <option name="required-feature" value="android.hardware.type.automotive" />
+ </object>
+ <option name="test-suite-tag" value="apct" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_abi_dialog 1" />
+ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
+ <option name="teardown-command"
+ value="settings delete secure show_ime_with_hard_keyboard" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="force-install-mode" value="FULL" />
+ <option name="test-file-name" value="ConcurrentMultiSessionImeTest.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.server.inputmethod.multisessiontest" />
+ </test>
+</configuration>
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
new file mode 100644
index 000000000000..b66ceba458ac
--- /dev/null
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod.multisessiontest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class ConcurrentMultiUserTest {
+
+ @Before
+ public void doBeforeEachTest() {
+ // No op
+ }
+
+ @Test
+ public void behaviorBeingTested_expectedResult() {
+ // Sample test
+ Context context =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertThat(context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE)).isTrue();
+ assertThat(context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_INPUT_METHODS)).isTrue();
+ }
+}
diff --git a/tests/inputmethod/OWNERS b/tests/inputmethod/OWNERS
new file mode 100644
index 000000000000..6bb4b17ed4eb
--- /dev/null
+++ b/tests/inputmethod/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 34867
+
+include /services/core/java/com/android/server/inputmethod/OWNERS