summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--Ravenwood.bp50
-rw-r--r--core/api/test-current.txt4
-rw-r--r--core/java/android/app/IActivityManager.aidl8
-rw-r--r--core/java/android/app/admin/flags/flags.aconfig14
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java262
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/hardware/face/FaceSensorConfigurations.java74
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java75
-rw-r--r--core/java/android/provider/Settings.java4
-rw-r--r--core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java23
-rw-r--r--core/java/android/view/BatchedInputEventReceiver.java9
-rw-r--r--core/java/android/view/PointerIcon.java14
-rw-r--r--core/java/android/view/ViewRootImpl.java19
-rw-r--r--core/java/com/android/internal/os/BinderInternal.java65
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java4
-rw-r--r--core/jni/android_util_Binder.cpp29
-rw-r--r--core/tests/coretests/Android.bp2
-rw-r--r--core/tests/coretests/AndroidTest.xml2
-rw-r--r--core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml3
-rw-r--r--core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java39
-rw-r--r--core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java21
-rw-r--r--core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl5
-rw-r--r--core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl4
-rw-r--r--core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java13
-rw-r--r--core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java13
-rw-r--r--core/tests/coretests/src/android/os/BinderProxyCountingTest.java106
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java17
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt13
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt1
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt23
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt16
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt32
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt31
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt30
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt29
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt3
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt34
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt206
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt22
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt22
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt16
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt33
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt22
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt35
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt108
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt33
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt13
-rw-r--r--packages/SystemUI/res/layout/screenshot_shelf.xml12
-rw-r--r--packages/SystemUI/res/values/dimens.xml1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIService.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/Communal.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/data/model/DisplayContentModel.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/data/model/SystemUiState.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepository.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepositoryImpl.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt87
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt97
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractor.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt202
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt51
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt64
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt130
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java27
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt16
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt11
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt13
-rw-r--r--ravenwood/Android.bp14
-rw-r--r--ravenwood/scripts/bulk_enable.py (renamed from ravenwood/bulk_enable.py)0
-rwxr-xr-xravenwood/scripts/fix_test_runner.py (renamed from ravenwood/fix_test_runner.py)0
-rwxr-xr-xravenwood/scripts/list-ravenwood-tests.sh (renamed from ravenwood/list-ravenwood-tests.sh)0
-rwxr-xr-xravenwood/scripts/ravenwood-stats-checker.sh18
-rwxr-xr-xravenwood/scripts/ravenwood-stats-collector.sh52
-rwxr-xr-xravenwood/scripts/run-ravenwood-tests.sh (renamed from ravenwood/run-ravenwood-tests.sh)2
-rw-r--r--ravenwood/texts/framework-minus-apex-ravenwood-policies.txt (renamed from ravenwood/framework-minus-apex-ravenwood-policies.txt)0
-rw-r--r--ravenwood/texts/ravenwood-annotation-allowed-classes.txt (renamed from ravenwood/ravenwood-annotation-allowed-classes.txt)0
-rw-r--r--ravenwood/texts/ravenwood-services-jarjar-rules.txt (renamed from ravenwood/ravenwood-services-jarjar-rules.txt)0
-rw-r--r--ravenwood/texts/ravenwood-standard-options.txt (renamed from ravenwood/ravenwood-standard-options.txt)0
-rw-r--r--ravenwood/texts/services.core-ravenwood-policies.txt (renamed from ravenwood/services.core-ravenwood-policies.txt)0
-rw-r--r--services/Android.bp1
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java17
-rw-r--r--services/core/java/com/android/server/SensitiveContentProtectionManagerService.java51
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java92
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java2
-rw-r--r--services/core/java/com/android/server/am/UidRecord.java36
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java38
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java33
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java31
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java25
-rw-r--r--services/core/java/com/android/server/pm/Settings.java14
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java9
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java19
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java6
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java32
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java27
-rw-r--r--wifi/tests/Android.bp8
-rw-r--r--wifi/tests/AndroidManifest.xml2
193 files changed, 3168 insertions, 1313 deletions
diff --git a/Android.bp b/Android.bp
index 59e903ef37d3..f6bfe6545284 100644
--- a/Android.bp
+++ b/Android.bp
@@ -389,7 +389,6 @@ java_defaults {
// TODO(b/120066492): remove gps_debug and protolog.conf.json when the build
// system propagates "required" properly.
"gps_debug.conf",
- "core.protolog.pb",
"framework-res",
// any install dependencies should go into framework-minus-apex-install-dependencies
// rather than here to avoid bloating incremental build time
diff --git a/Ravenwood.bp b/Ravenwood.bp
index f43c37bf637d..c3b22c4f4331 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -30,7 +30,7 @@ java_genrule {
name: "framework-minus-apex.ravenwood-base",
tools: ["hoststubgen"],
cmd: "$(location hoststubgen) " +
- "@$(location ravenwood/ravenwood-standard-options.txt) " +
+ "@$(location ravenwood/texts/ravenwood-standard-options.txt) " +
"--debug-log $(location hoststubgen_framework-minus-apex.log) " +
"--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " +
@@ -41,13 +41,13 @@ java_genrule {
"--gen-input-dump-file $(location hoststubgen_dump.txt) " +
"--in-jar $(location :framework-minus-apex-for-hoststubgen) " +
- "--policy-override-file $(location ravenwood/framework-minus-apex-ravenwood-policies.txt) " +
- "--annotation-allowed-classes-file $(location ravenwood/ravenwood-annotation-allowed-classes.txt) ",
+ "--policy-override-file $(location ravenwood/texts/framework-minus-apex-ravenwood-policies.txt) " +
+ "--annotation-allowed-classes-file $(location ravenwood/texts/ravenwood-annotation-allowed-classes.txt) ",
srcs: [
":framework-minus-apex-for-hoststubgen",
- "ravenwood/framework-minus-apex-ravenwood-policies.txt",
- "ravenwood/ravenwood-standard-options.txt",
- "ravenwood/ravenwood-annotation-allowed-classes.txt",
+ "ravenwood/texts/framework-minus-apex-ravenwood-policies.txt",
+ "ravenwood/texts/ravenwood-standard-options.txt",
+ "ravenwood/texts/ravenwood-annotation-allowed-classes.txt",
],
out: [
"ravenwood.jar",
@@ -77,6 +77,19 @@ java_genrule {
],
}
+// Extract the stats file.
+genrule {
+ name: "framework-minus-apex.ravenwood.stats",
+ defaults: ["ravenwood-internal-only-visibility-genrule"],
+ cmd: "cp $(in) $(out)",
+ srcs: [
+ ":framework-minus-apex.ravenwood-base{hoststubgen_framework-minus-apex_stats.csv}",
+ ],
+ out: [
+ "hoststubgen_framework-minus-apex_stats.csv",
+ ],
+}
+
java_library {
name: "services.core-for-hoststubgen",
installable: false, // host only jar.
@@ -91,7 +104,7 @@ java_genrule {
name: "services.core.ravenwood-base",
tools: ["hoststubgen"],
cmd: "$(location hoststubgen) " +
- "@$(location ravenwood/ravenwood-standard-options.txt) " +
+ "@$(location ravenwood/texts/ravenwood-standard-options.txt) " +
"--debug-log $(location hoststubgen_services.core.log) " +
"--stats-file $(location hoststubgen_services.core_stats.csv) " +
@@ -102,13 +115,13 @@ java_genrule {
"--gen-input-dump-file $(location hoststubgen_dump.txt) " +
"--in-jar $(location :services.core-for-hoststubgen) " +
- "--policy-override-file $(location ravenwood/services.core-ravenwood-policies.txt) " +
- "--annotation-allowed-classes-file $(location ravenwood/ravenwood-annotation-allowed-classes.txt) ",
+ "--policy-override-file $(location ravenwood/texts/services.core-ravenwood-policies.txt) " +
+ "--annotation-allowed-classes-file $(location ravenwood/texts/ravenwood-annotation-allowed-classes.txt) ",
srcs: [
":services.core-for-hoststubgen",
- "ravenwood/services.core-ravenwood-policies.txt",
- "ravenwood/ravenwood-standard-options.txt",
- "ravenwood/ravenwood-annotation-allowed-classes.txt",
+ "ravenwood/texts/services.core-ravenwood-policies.txt",
+ "ravenwood/texts/ravenwood-standard-options.txt",
+ "ravenwood/texts/ravenwood-annotation-allowed-classes.txt",
],
out: [
"ravenwood.jar",
@@ -135,6 +148,19 @@ java_genrule {
],
}
+// Extract the stats file.
+genrule {
+ name: "services.core.ravenwood.stats",
+ defaults: ["ravenwood-internal-only-visibility-genrule"],
+ cmd: "cp $(in) $(out)",
+ srcs: [
+ ":services.core.ravenwood-base{hoststubgen_services.core_stats.csv}",
+ ],
+ out: [
+ "hoststubgen_services.core_stats.csv",
+ ],
+}
+
java_library {
name: "services.core.ravenwood-jarjar",
installable: false,
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index ca5d3eb4a292..61897030a991 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3676,6 +3676,10 @@ package android.view {
field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800
}
+ public final class PointerIcon implements android.os.Parcelable {
+ method @FlaggedApi("android.view.flags.enable_vector_cursors") public void setDrawNativeDropShadow(boolean);
+ }
+
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface RemotableViewMethod {
method public abstract String asyncImpl() default "";
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 5e6b54b1d0ea..84bc6cec7208 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -962,4 +962,12 @@ interface IActivityManager {
*/
oneway void frozenBinderTransactionDetected(int debugPid, int code, int flags, int err);
int getBindingUidProcessState(int uid, in String callingPackage);
+
+ /**
+ * Return the timestampe (in the elapsed timebase) when the UID became idle from active
+ * last time (regardless of if the UID is still idle, or became active again).
+ * This is useful when trying to detect whether an UID has ever became idle since a certain
+ * time in the past.
+ */
+ long getUidLastIdleElapsedTime(int uid, in String callingPackage);
}
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index be0aaff95c96..25697c5c662c 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -197,8 +197,8 @@ flag {
description: "Fix provisioning for single-user headless DO"
bug: "289515470"
metadata {
- purpose: PURPOSE_BUGFIX
- }
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
@@ -214,3 +214,13 @@ flag {
description: "Guards a new flow for recursive required enterprise app list merging"
bug: "319084618"
}
+
+flag {
+ name: "headless_device_owner_delegate_security_logging_bug_fix"
+ namespace: "enterprise"
+ description: "Fix delegate security logging for single user headless DO."
+ bug: "289515470"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 2c26389071ce..a08d659ab4aa 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -26,6 +26,7 @@ import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
@@ -80,25 +81,27 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
- * System level service for managing companion devices
+ * Public interfaces for managing companion devices.
*
- * See <a href="{@docRoot}guide/topics/connectivity/companion-device-pairing">this guide</a>
- * for a usage example.
+ * <p>The interfaces in this class allow companion apps to
+ * {@link #associate(AssociationRequest, Executor, Callback)} discover and request device profiles}
+ * for companion devices, {@link #startObservingDevicePresence(String) listen to device presence
+ * events}, {@link #startSystemDataTransfer(int, Executor, OutcomeReceiver) transfer system level
+ * data} via {@link #attachSystemDataTransport(int, InputStream, OutputStream) the reported
+ * channel} and more.</p>
*
- * <p>To obtain an instance call {@link Context#getSystemService}({@link
- * Context#COMPANION_DEVICE_SERVICE}) Then, call {@link #associate(AssociationRequest,
- * Callback, Handler)} to initiate the flow of associating current package with a
- * device selected by user.</p>
- *
- * @see CompanionDeviceManager#associate
- * @see AssociationRequest
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about managing companion devices, read the <a href=
+ * "{@docRoot}guide/topics/connectivity/companion-device-pairing">Companion Device Pairing</a>
+ * developer guide.
+ * </div>
*/
@SuppressLint("LongLogTag")
@SystemService(Context.COMPANION_DEVICE_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP)
public final class CompanionDeviceManager {
-
- private static final boolean DEBUG = false;
- private static final String LOG_TAG = "CDM_CompanionDeviceManager";
+ private static final String TAG = "CDM_CompanionDeviceManager";
/** @hide */
@IntDef(prefix = {"RESULT_"}, value = {
@@ -374,7 +377,7 @@ public final class CompanionDeviceManager {
}
private final ICompanionDeviceManager mService;
- private Context mContext;
+ private final Context mContext;
@GuardedBy("mListeners")
private final ArrayList<OnAssociationsChangedListenerProxy> mListeners = new ArrayList<>();
@@ -432,7 +435,11 @@ public final class CompanionDeviceManager {
@NonNull AssociationRequest request,
@NonNull Callback callback,
@Nullable Handler handler) {
- if (!checkFeaturePresent()) return;
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
Objects.requireNonNull(request, "Request cannot be null");
Objects.requireNonNull(callback, "Callback cannot be null");
handler = Handler.mainIfNull(handler);
@@ -492,7 +499,11 @@ public final class CompanionDeviceManager {
@NonNull AssociationRequest request,
@NonNull Executor executor,
@NonNull Callback callback) {
- if (!checkFeaturePresent()) return;
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
Objects.requireNonNull(request, "Request cannot be null");
Objects.requireNonNull(executor, "Executor cannot be null");
Objects.requireNonNull(callback, "Callback cannot be null");
@@ -521,7 +532,10 @@ public final class CompanionDeviceManager {
@UserHandleAware
@Nullable
public IntentSender buildAssociationCancellationIntent() {
- if (!checkFeaturePresent()) return null;
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return null;
+ }
try {
PendingIntent pendingIntent = mService.buildAssociationCancellationIntent(
@@ -543,7 +557,8 @@ public final class CompanionDeviceManager {
* @param flags system data types to be enabled.
*/
public void enableSystemDataSyncForTypes(int associationId, @DataSyncTypes int flags) {
- if (!checkFeaturePresent()) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
return;
}
@@ -565,7 +580,8 @@ public final class CompanionDeviceManager {
* @param flags system data types to be disabled.
*/
public void disableSystemDataSyncForTypes(int associationId, @DataSyncTypes int flags) {
- if (!checkFeaturePresent()) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
return;
}
@@ -580,6 +596,11 @@ public final class CompanionDeviceManager {
* @hide
*/
public void enablePermissionsSync(int associationId) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
try {
mService.enablePermissionsSync(associationId);
} catch (RemoteException e) {
@@ -591,6 +612,11 @@ public final class CompanionDeviceManager {
* @hide
*/
public void disablePermissionsSync(int associationId) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
try {
mService.disablePermissionsSync(associationId);
} catch (RemoteException e) {
@@ -602,6 +628,11 @@ public final class CompanionDeviceManager {
* @hide
*/
public PermissionSyncRequest getPermissionSyncRequest(int associationId) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return null;
+ }
+
try {
return mService.getPermissionSyncRequest(associationId);
} catch (RemoteException e) {
@@ -636,7 +667,10 @@ public final class CompanionDeviceManager {
@UserHandleAware
@NonNull
public List<AssociationInfo> getMyAssociations() {
- if (!checkFeaturePresent()) return Collections.emptyList();
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return Collections.emptyList();
+ }
try {
return mService.getAssociations(mContext.getOpPackageName(), mContext.getUserId());
@@ -665,7 +699,10 @@ public final class CompanionDeviceManager {
@UserHandleAware
@Deprecated
public void disassociate(@NonNull String deviceMacAddress) {
- if (!checkFeaturePresent()) return;
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
try {
mService.legacyDisassociate(deviceMacAddress, mContext.getOpPackageName(),
@@ -690,7 +727,10 @@ public final class CompanionDeviceManager {
*/
@UserHandleAware
public void disassociate(int associationId) {
- if (!checkFeaturePresent()) return;
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
try {
mService.disassociate(associationId);
@@ -716,9 +756,11 @@ public final class CompanionDeviceManager {
*/
@UserHandleAware
public void requestNotificationAccess(ComponentName component) {
- if (!checkFeaturePresent()) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
return;
}
+
try {
PendingIntent pendingIntent = mService.requestNotificationAccess(
component, mContext.getUserId());
@@ -755,9 +797,11 @@ public final class CompanionDeviceManager {
*/
@Deprecated
public boolean hasNotificationAccess(ComponentName component) {
- if (!checkFeaturePresent()) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
return false;
}
+
try {
return mService.hasNotificationAccess(component);
} catch (RemoteException e) {
@@ -793,7 +837,11 @@ public final class CompanionDeviceManager {
@NonNull String packageName,
@NonNull MacAddress macAddress,
@NonNull UserHandle user) {
- if (!checkFeaturePresent()) return false;
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return false;
+ }
+
Objects.requireNonNull(packageName, "package name cannot be null");
Objects.requireNonNull(macAddress, "mac address cannot be null");
Objects.requireNonNull(user, "user cannot be null");
@@ -816,7 +864,8 @@ public final class CompanionDeviceManager {
@SystemApi
@UserHandleAware
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
- public @NonNull List<AssociationInfo> getAllAssociations() {
+ @NonNull
+ public List<AssociationInfo> getAllAssociations() {
return getAllAssociations(mContext.getUserId());
}
@@ -826,8 +875,13 @@ public final class CompanionDeviceManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
- public @NonNull List<AssociationInfo> getAllAssociations(@UserIdInt int userId) {
- if (!checkFeaturePresent()) return Collections.emptyList();
+ @NonNull
+ public List<AssociationInfo> getAllAssociations(@UserIdInt int userId) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return Collections.emptyList();
+ }
+
try {
return mService.getAllAssociationsForUser(userId);
} catch (RemoteException e) {
@@ -875,7 +929,11 @@ public final class CompanionDeviceManager {
public void addOnAssociationsChangedListener(
@NonNull Executor executor, @NonNull OnAssociationsChangedListener listener,
@UserIdInt int userId) {
- if (!checkFeaturePresent()) return;
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
synchronized (mListeners) {
final OnAssociationsChangedListenerProxy proxy = new OnAssociationsChangedListenerProxy(
executor, listener);
@@ -899,7 +957,11 @@ public final class CompanionDeviceManager {
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
public void removeOnAssociationsChangedListener(
@NonNull OnAssociationsChangedListener listener) {
- if (!checkFeaturePresent()) return;
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
synchronized (mListeners) {
final Iterator<OnAssociationsChangedListenerProxy> iterator = mListeners.iterator();
while (iterator.hasNext()) {
@@ -931,6 +993,11 @@ public final class CompanionDeviceManager {
public void addOnTransportsChangedListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<List<AssociationInfo>> listener) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
final OnTransportsChangedListenerProxy proxy = new OnTransportsChangedListenerProxy(
executor, listener);
try {
@@ -950,6 +1017,11 @@ public final class CompanionDeviceManager {
@RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void removeOnTransportsChangedListener(
@NonNull Consumer<List<AssociationInfo>> listener) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
final OnTransportsChangedListenerProxy proxy = new OnTransportsChangedListenerProxy(
null, listener);
try {
@@ -969,6 +1041,11 @@ public final class CompanionDeviceManager {
*/
@RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void sendMessage(int messageType, @NonNull byte[] data, @NonNull int[] associationIds) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
try {
mService.sendMessage(messageType, data, associationIds);
} catch (RemoteException e) {
@@ -989,6 +1066,11 @@ public final class CompanionDeviceManager {
public void addOnMessageReceivedListener(
@NonNull @CallbackExecutor Executor executor, int messageType,
@NonNull BiConsumer<Integer, byte[]> listener) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
final OnMessageReceivedListenerProxy proxy = new OnMessageReceivedListenerProxy(
executor, listener);
try {
@@ -1006,6 +1088,11 @@ public final class CompanionDeviceManager {
@RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void removeOnMessageReceivedListener(int messageType,
@NonNull BiConsumer<Integer, byte[]> listener) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
final OnMessageReceivedListenerProxy proxy = new OnMessageReceivedListenerProxy(
null, listener);
try {
@@ -1031,9 +1118,11 @@ public final class CompanionDeviceManager {
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
public boolean canPairWithoutPrompt(@NonNull String packageName,
@NonNull String deviceMacAddress, @NonNull UserHandle user) {
- if (!checkFeaturePresent()) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
return false;
}
+
Objects.requireNonNull(packageName, "package name cannot be null");
Objects.requireNonNull(deviceMacAddress, "device mac address cannot be null");
Objects.requireNonNull(user, "user handle cannot be null");
@@ -1081,9 +1170,11 @@ public final class CompanionDeviceManager {
@RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE)
public void startObservingDevicePresence(@NonNull String deviceAddress)
throws DeviceNotAssociatedException {
- if (!checkFeaturePresent()) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
return;
}
+
Objects.requireNonNull(deviceAddress, "address cannot be null");
try {
mService.legacyStartObservingDevicePresence(deviceAddress,
@@ -1123,9 +1214,11 @@ public final class CompanionDeviceManager {
@RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE)
public void stopObservingDevicePresence(@NonNull String deviceAddress)
throws DeviceNotAssociatedException {
- if (!checkFeaturePresent()) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
return;
}
+
Objects.requireNonNull(deviceAddress, "address cannot be null");
try {
mService.legacyStopObservingDevicePresence(deviceAddress,
@@ -1171,6 +1264,11 @@ public final class CompanionDeviceManager {
@FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
@RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE)
public void startObservingDevicePresence(@NonNull ObservingDevicePresenceRequest request) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
Objects.requireNonNull(request, "request cannot be null");
try {
@@ -1192,6 +1290,11 @@ public final class CompanionDeviceManager {
@FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
@RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE)
public void stopObservingDevicePresence(@NonNull ObservingDevicePresenceRequest request) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
Objects.requireNonNull(request, "request cannot be null");
try {
@@ -1222,7 +1325,7 @@ public final class CompanionDeviceManager {
@RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES)
public void dispatchMessage(int messageId, int associationId, @NonNull byte[] message)
throws DeviceNotAssociatedException {
- Log.w(LOG_TAG, "dispatchMessage replaced by attachSystemDataTransport");
+ Log.w(TAG, "dispatchMessage replaced by attachSystemDataTransport");
}
/**
@@ -1244,6 +1347,11 @@ public final class CompanionDeviceManager {
@RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES)
public void attachSystemDataTransport(int associationId, @NonNull InputStream in,
@NonNull OutputStream out) throws DeviceNotAssociatedException {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
synchronized (mTransports) {
if (mTransports.contains(associationId)) {
detachSystemDataTransport(associationId);
@@ -1272,6 +1380,11 @@ public final class CompanionDeviceManager {
@RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES)
public void detachSystemDataTransport(int associationId)
throws DeviceNotAssociatedException {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
synchronized (mTransports) {
final Transport transport = mTransports.get(associationId);
if (transport != null) {
@@ -1296,9 +1409,11 @@ public final class CompanionDeviceManager {
@NonNull String packageName,
@NonNull MacAddress macAddress,
@NonNull byte[] certificate) {
- if (!checkFeaturePresent()) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
return;
}
+
Objects.requireNonNull(packageName, "package name cannot be null");
Objects.requireNonNull(macAddress, "mac address cannot be null");
@@ -1327,6 +1442,11 @@ public final class CompanionDeviceManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED)
public void notifyDeviceAppeared(int associationId) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
try {
mService.notifySelfManagedDeviceAppeared(associationId);
} catch (RemoteException e) {
@@ -1349,6 +1469,11 @@ public final class CompanionDeviceManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED)
public void notifyDeviceDisappeared(int associationId) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
try {
mService.notifySelfManagedDeviceDisappeared(associationId);
} catch (RemoteException e) {
@@ -1384,6 +1509,11 @@ public final class CompanionDeviceManager {
@Nullable
public IntentSender buildPermissionTransferUserConsentIntent(int associationId)
throws DeviceNotAssociatedException {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return null;
+ }
+
try {
PendingIntent pendingIntent = mService.buildPermissionTransferUserConsentIntent(
mContext.getOpPackageName(),
@@ -1420,6 +1550,11 @@ public final class CompanionDeviceManager {
@UserHandleAware
@FlaggedApi(Flags.FLAG_PERM_SYNC_USER_CONSENT)
public boolean isPermissionTransferUserConsented(int associationId) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return false;
+ }
+
try {
return mService.isPermissionTransferUserConsented(mContext.getOpPackageName(),
mContext.getUserId(), associationId);
@@ -1446,6 +1581,11 @@ public final class CompanionDeviceManager {
@Deprecated
@UserHandleAware
public void startSystemDataTransfer(int associationId) throws DeviceNotAssociatedException {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
try {
mService.startSystemDataTransfer(mContext.getOpPackageName(), mContext.getUserId(),
associationId, null);
@@ -1478,6 +1618,11 @@ public final class CompanionDeviceManager {
@NonNull Executor executor,
@NonNull OutcomeReceiver<Void, CompanionException> result)
throws DeviceNotAssociatedException {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
try {
mService.startSystemDataTransfer(mContext.getOpPackageName(), mContext.getUserId(),
associationId, new SystemDataTransferCallbackProxy(executor, result));
@@ -1495,6 +1640,11 @@ public final class CompanionDeviceManager {
*/
@UserHandleAware
public boolean isCompanionApplicationBound() {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return false;
+ }
+
try {
return mService.isCompanionApplicationBound(
mContext.getOpPackageName(), mContext.getUserId());
@@ -1513,6 +1663,11 @@ public final class CompanionDeviceManager {
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
public void enableSecureTransport(boolean enabled) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
try {
mService.enableSecureTransport(enabled);
} catch (RemoteException e) {
@@ -1534,6 +1689,11 @@ public final class CompanionDeviceManager {
@FlaggedApi(Flags.FLAG_ASSOCIATION_TAG)
@UserHandleAware
public void setAssociationTag(int associationId, @NonNull String tag) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
Objects.requireNonNull(tag, "tag cannot be null");
if (tag.length() > ASSOCIATION_TAG_LENGTH_LIMIT) {
@@ -1560,6 +1720,11 @@ public final class CompanionDeviceManager {
@FlaggedApi(Flags.FLAG_ASSOCIATION_TAG)
@UserHandleAware
public void clearAssociationTag(int associationId) {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
try {
mService.clearAssociationTag(associationId);
} catch (RemoteException e) {
@@ -1567,15 +1732,6 @@ public final class CompanionDeviceManager {
}
}
- private boolean checkFeaturePresent() {
- boolean featurePresent = mService != null;
- if (!featurePresent && DEBUG) {
- Log.d(LOG_TAG, "Feature " + PackageManager.FEATURE_COMPANION_DEVICE_SETUP
- + " not available");
- }
- return featurePresent;
- }
-
private static class AssociationRequestCallbackProxy extends IAssociationRequestCallback.Stub {
private final Handler mHandler;
private final Callback mCallback;
@@ -1613,7 +1769,7 @@ public final class CompanionDeviceManager {
private <T> void execute(Consumer<T> callback, T arg) {
if (mExecutor != null) {
mExecutor.execute(() -> callback.accept(arg));
- } else {
+ } else if (mHandler != null) {
mHandler.post(() -> callback.accept(arg));
}
}
@@ -1716,6 +1872,11 @@ public final class CompanionDeviceManager {
}
public void start() throws IOException {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
final ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair();
final ParcelFileDescriptor localFd = pair[0];
final ParcelFileDescriptor remoteFd = pair[1];
@@ -1734,7 +1895,7 @@ public final class CompanionDeviceManager {
copyWithFlushing(mLocalIn, mRemoteOut);
} catch (IOException e) {
if (!mStopped) {
- Log.w(LOG_TAG, "Trouble during outgoing transport", e);
+ Log.w(TAG, "Trouble during outgoing transport", e);
stop();
}
}
@@ -1744,7 +1905,7 @@ public final class CompanionDeviceManager {
copyWithFlushing(mRemoteIn, mLocalOut);
} catch (IOException e) {
if (!mStopped) {
- Log.w(LOG_TAG, "Trouble during incoming transport", e);
+ Log.w(TAG, "Trouble during incoming transport", e);
stop();
}
}
@@ -1752,13 +1913,18 @@ public final class CompanionDeviceManager {
}
public void stop() {
+ if (mService == null) {
+ Log.w(TAG, "CompanionDeviceManager service is not available.");
+ return;
+ }
+
mStopped = true;
try {
mService.detachSystemDataTransport(mContext.getPackageName(),
mContext.getUserId(), mAssociationId);
} catch (RemoteException e) {
- Log.w(LOG_TAG, "Failed to detach transport", e);
+ Log.w(TAG, "Failed to detach transport", e);
}
IoUtils.closeQuietly(mRemoteIn);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index bff90f1d2298..5d4babb8a36d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -847,5 +847,5 @@ interface IPackageManager {
@EnforcePermission("GET_APP_METADATA")
int getAppMetadataSource(String packageName, int userId);
- ComponentName getDomainVerificationAgent();
+ ComponentName getDomainVerificationAgent(int userId);
}
diff --git a/core/java/android/hardware/face/FaceSensorConfigurations.java b/core/java/android/hardware/face/FaceSensorConfigurations.java
index 6ef692f81069..12471681f913 100644
--- a/core/java/android/hardware/face/FaceSensorConfigurations.java
+++ b/core/java/android/hardware/face/FaceSensorConfigurations.java
@@ -22,11 +22,12 @@ import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.SensorProps;
+import android.os.Binder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import androidx.annotation.NonNull;
@@ -36,7 +37,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.function.Function;
/**
* Provides the sensor props for face sensor, if available.
@@ -74,22 +74,10 @@ public class FaceSensorConfigurations implements Parcelable {
/**
* Process AIDL instances to extract sensor props and add it to the sensor map.
* @param aidlInstances available face AIDL instances
- * @param getIFace function that provides the daemon for the specific instance
*/
- public void addAidlConfigs(@NonNull String[] aidlInstances,
- @NonNull Function<String, IFace> getIFace) {
+ public void addAidlConfigs(@NonNull String[] aidlInstances) {
for (String aidlInstance : aidlInstances) {
- final String fqName = IFace.DESCRIPTOR + "/" + aidlInstance;
- IFace face = getIFace.apply(fqName);
- try {
- if (face != null) {
- mSensorPropsMap.put(aidlInstance, face.getSensorProps());
- } else {
- Slog.e(TAG, "Unable to get declared service: " + fqName);
- }
- } catch (RemoteException e) {
- Log.d(TAG, "Unable to get sensor properties!");
- }
+ mSensorPropsMap.put(aidlInstance, null);
}
}
@@ -131,38 +119,31 @@ public class FaceSensorConfigurations implements Parcelable {
}
/**
- * Return sensor props for the given instance. If instance is not available,
- * then null is returned.
+ * Checks if {@param instance} exists.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPairForInstance(String instance) {
- if (mSensorPropsMap.containsKey(instance)) {
- return new Pair<>(instance, mSensorPropsMap.get(instance));
- }
-
- return null;
+ public boolean doesInstanceExist(String instance) {
+ return mSensorPropsMap.containsKey(instance);
}
/**
- * Return the first pair of instance and sensor props, which does not correspond to the given
- * If instance is not available, then null is returned.
+ * Return the first HAL instance, which does not correspond to the given {@param instance}.
+ * If another instance is not available, then null is returned.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPairNotForInstance(String instance) {
+ public String getSensorNameNotForInstance(String instance) {
Optional<String> notAVirtualInstance = mSensorPropsMap.keySet().stream().filter(
(instanceName) -> !instanceName.equals(instance)).findFirst();
- return notAVirtualInstance.map(this::getSensorPairForInstance).orElseGet(
- this::getSensorPair);
+ return notAVirtualInstance.orElse(null);
}
/**
- * Returns the first pair of instance and sensor props that has been added to the map.
+ * Returns the first instance that has been added to the map.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPair() {
+ public String getSensorInstance() {
Optional<String> optionalInstance = mSensorPropsMap.keySet().stream().findFirst();
- return optionalInstance.map(this::getSensorPairForInstance).orElse(null);
-
+ return optionalInstance.orElse(null);
}
public boolean getResetLockoutRequiresChallenge() {
@@ -179,4 +160,31 @@ public class FaceSensorConfigurations implements Parcelable {
dest.writeByte((byte) (mResetLockoutRequiresChallenge ? 1 : 0));
dest.writeMap(mSensorPropsMap);
}
+
+ /**
+ * Returns face sensor props for the HAL {@param instance}.
+ */
+ @Nullable
+ public SensorProps[] getSensorPropForInstance(String instance) {
+ SensorProps[] props = mSensorPropsMap.get(instance);
+
+ //Props should not be null for HIDL configs
+ if (props != null) {
+ return props;
+ }
+
+ final String fqName = IFace.DESCRIPTOR + "/" + instance;
+ IFace face = IFace.Stub.asInterface(Binder.allowBlocking(
+ ServiceManager.waitForDeclaredService(fqName)));
+ try {
+ if (face != null) {
+ props = face.getSensorProps();
+ } else {
+ Slog.e(TAG, "Unable to get declared service: " + fqName);
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "Unable to get sensor properties!");
+ }
+ return props;
+ }
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java b/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
index f214494a5d7b..43c0da9bd8ed 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
@@ -23,18 +23,18 @@ import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorProps;
+import android.os.Binder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
-import android.util.Pair;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.function.Function;
/**
* Provides the sensor props for fingerprint sensor, if available.
@@ -68,23 +68,10 @@ public class FingerprintSensorConfigurations implements Parcelable {
/**
* Process AIDL instances to extract sensor props and add it to the sensor map.
* @param aidlInstances available face AIDL instances
- * @param getIFingerprint function that provides the daemon for the specific instance
*/
- public void addAidlSensors(@NonNull String[] aidlInstances,
- @NonNull Function<String, IFingerprint> getIFingerprint) {
+ public void addAidlSensors(@NonNull String[] aidlInstances) {
for (String aidlInstance : aidlInstances) {
- try {
- final String fqName = IFingerprint.DESCRIPTOR + "/" + aidlInstance;
- final IFingerprint fp = getIFingerprint.apply(fqName);
- if (fp != null) {
- SensorProps[] props = fp.getSensorProps();
- mSensorPropsMap.put(aidlInstance, props);
- } else {
- Log.d(TAG, "IFingerprint null for instance " + aidlInstance);
- }
- } catch (RemoteException e) {
- Log.d(TAG, "Unable to get sensor properties!");
- }
+ mSensorPropsMap.put(aidlInstance, null);
}
}
@@ -133,38 +120,31 @@ public class FingerprintSensorConfigurations implements Parcelable {
}
/**
- * Return sensor props for the given instance. If instance is not available,
- * then null is returned.
+ * Checks if {@param instance} exists.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPairForInstance(String instance) {
- if (mSensorPropsMap.containsKey(instance)) {
- return new Pair<>(instance, mSensorPropsMap.get(instance));
- }
-
- return null;
+ public boolean doesInstanceExist(String instance) {
+ return mSensorPropsMap.containsKey(instance);
}
/**
- * Return the first pair of instance and sensor props, which does not correspond to the given
- * If instance is not available, then null is returned.
+ * Return the first HAL instance, which does not correspond to the given {@param instance}.
+ * If another instance is not available, then null is returned.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPairNotForInstance(String instance) {
+ public String getSensorNameNotForInstance(String instance) {
Optional<String> notAVirtualInstance = mSensorPropsMap.keySet().stream().filter(
(instanceName) -> !instanceName.equals(instance)).findFirst();
- return notAVirtualInstance.map(this::getSensorPairForInstance).orElseGet(
- this::getSensorPair);
+ return notAVirtualInstance.orElse(null);
}
/**
- * Returns the first pair of instance and sensor props that has been added to the map.
+ * Returns the first instance that has been added to the map.
*/
@Nullable
- public Pair<String, SensorProps[]> getSensorPair() {
+ public String getSensorInstance() {
Optional<String> optionalInstance = mSensorPropsMap.keySet().stream().findFirst();
- return optionalInstance.map(this::getSensorPairForInstance).orElse(null);
-
+ return optionalInstance.orElse(null);
}
public boolean getResetLockoutRequiresHardwareAuthToken() {
@@ -181,4 +161,31 @@ public class FingerprintSensorConfigurations implements Parcelable {
dest.writeByte((byte) (mResetLockoutRequiresHardwareAuthToken ? 1 : 0));
dest.writeMap(mSensorPropsMap);
}
+
+ /**
+ * Returns fingerprint sensor props for the HAL {@param instance}.
+ */
+ @Nullable
+ public SensorProps[] getSensorPropForInstance(String instance) {
+ SensorProps[] props = mSensorPropsMap.get(instance);
+
+ //Props should not be null for HIDL configs
+ if (props != null) {
+ return props;
+ }
+
+ try {
+ final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;
+ final IFingerprint fp = IFingerprint.Stub.asInterface(Binder.allowBlocking(
+ ServiceManager.waitForDeclaredService(fqName)));
+ if (fp != null) {
+ props = fp.getSensorProps();
+ } else {
+ Log.d(TAG, "IFingerprint null for instance " + instance);
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "Unable to get sensor properties!");
+ }
+ return props;
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 363e252b8f27..d91b051c671a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12451,7 +12451,7 @@ public final class Settings {
/** @hide */
public static final int PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY = 1;
/** @hide */
- public static final int PRIVATE_SPACE_AUTO_LOCK_NEVER = 2;
+ public static final int PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART = 2;
/**
* The different auto lock options for private space.
@@ -12461,7 +12461,7 @@ public final class Settings {
@IntDef(prefix = {"PRIVATE_SPACE_AUTO_LOCK_"}, value = {
PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK,
PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY,
- PRIVATE_SPACE_AUTO_LOCK_NEVER,
+ PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PrivateSpaceAutoLockOption {
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
index e6d8fd0e2f2b..8a3f6ceb852b 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
@@ -71,9 +71,11 @@ class QuickAccessWalletServiceInfo {
@Nullable
static QuickAccessWalletServiceInfo tryCreate(@NonNull Context context) {
- String defaultAppPackageName = getDefaultWalletApp(context);
+ String defaultAppPackageName = null;
- if (defaultAppPackageName == null) {
+ if (isWalletRoleAvailable(context)) {
+ defaultAppPackageName = getDefaultWalletApp(context);
+ } else {
ComponentName defaultPaymentApp = getDefaultPaymentApp(context);
if (defaultPaymentApp == null) {
return null;
@@ -103,14 +105,21 @@ class QuickAccessWalletServiceInfo {
final long token = Binder.clearCallingIdentity();
try {
RoleManager roleManager = context.getSystemService(RoleManager.class);
- if (roleManager.isRoleAvailable(RoleManager.ROLE_WALLET)) {
- List<String> roleHolders = roleManager.getRoleHolders(RoleManager.ROLE_WALLET);
- return roleHolders.isEmpty() ? null : roleHolders.get(0);
- }
+ List<String> roleHolders = roleManager.getRoleHolders(RoleManager.ROLE_WALLET);
+ return roleHolders.isEmpty() ? null : roleHolders.get(0);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private static boolean isWalletRoleAvailable(Context context) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ RoleManager roleManager = context.getSystemService(RoleManager.class);
+ return roleManager.isRoleAvailable(RoleManager.ROLE_WALLET);
} finally {
Binder.restoreCallingIdentity(token);
}
- return null;
}
private static ComponentName getDefaultPaymentApp(Context context) {
diff --git a/core/java/android/view/BatchedInputEventReceiver.java b/core/java/android/view/BatchedInputEventReceiver.java
index ca2e56d383e5..2e39f73f6233 100644
--- a/core/java/android/view/BatchedInputEventReceiver.java
+++ b/core/java/android/view/BatchedInputEventReceiver.java
@@ -29,6 +29,7 @@ public class BatchedInputEventReceiver extends InputEventReceiver {
private Choreographer mChoreographer;
private boolean mBatchingEnabled;
private boolean mBatchedInputScheduled;
+ private final String mTag;
private final Handler mHandler;
private final Runnable mConsumeBatchedInputEvents = new Runnable() {
@Override
@@ -43,6 +44,7 @@ public class BatchedInputEventReceiver extends InputEventReceiver {
super(inputChannel, looper);
mChoreographer = choreographer;
mBatchingEnabled = true;
+ mTag = inputChannel.getName();
traceBoolVariable("mBatchingEnabled", mBatchingEnabled);
traceBoolVariable("mBatchedInputScheduled", mBatchedInputScheduled);
mHandler = new Handler(looper);
@@ -123,7 +125,12 @@ public class BatchedInputEventReceiver extends InputEventReceiver {
private final class BatchedInputRunnable implements Runnable {
@Override
public void run() {
- doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, mTag);
+ doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
}
}
private final BatchedInputRunnable mBatchedInputRunnable = new BatchedInputRunnable();
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 147d56253dcf..17d14042e468 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -16,8 +16,10 @@
package android.view;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.annotation.XmlRes;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -39,6 +41,7 @@ import android.os.Parcelable;
import android.os.PointerIconType;
import android.util.Log;
import android.util.SparseArray;
+import android.view.flags.Flags;
import com.android.internal.util.XmlUtils;
@@ -637,4 +640,15 @@ public final class PointerIcon implements Parcelable {
default: return Integer.toString(type);
}
}
+
+ /**
+ * Sets whether drop shadow will draw in the native code.
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(Flags.FLAG_ENABLE_VECTOR_CURSORS)
+ public void setDrawNativeDropShadow(boolean drawNativeDropShadow) {
+ mDrawNativeDropShadow = drawNativeDropShadow;
+ }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 49d4af8a3e61..0d9e471e77af 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10173,13 +10173,18 @@ public final class ViewRootImpl implements ViewParent,
final class ConsumeBatchedInputRunnable implements Runnable {
@Override
public void run() {
- mConsumeBatchedInputScheduled = false;
- if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) {
- // If we consumed a batch here, we want to go ahead and schedule the
- // consumption of batched input events on the next frame. Otherwise, we would
- // wait until we have more input events pending and might get starved by other
- // things occurring in the process.
- scheduleConsumeBatchedInput();
+ Trace.traceBegin(TRACE_TAG_VIEW, mTag);
+ try {
+ mConsumeBatchedInputScheduled = false;
+ if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) {
+ // If we consumed a batch here, we want to go ahead and schedule the
+ // consumption of batched input events on the next frame. Otherwise, we would
+ // wait until we have more input events pending and might get starved by other
+ // things occurring in the process.
+ scheduleConsumeBatchedInput();
+ }
+ } finally {
+ Trace.traceEnd(TRACE_TAG_VIEW);
}
}
}
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index c14d8d805d29..8063be64f36d 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -45,8 +45,8 @@ public class BinderInternal {
static ArrayList<Runnable> sGcWatchers = new ArrayList<>();
static Runnable[] sTmpWatchers = new Runnable[1];
static long sLastGcTime;
- static final BinderProxyLimitListenerDelegate sBinderProxyLimitListenerDelegate =
- new BinderProxyLimitListenerDelegate();
+ static final BinderProxyCountEventListenerDelegate sBinderProxyCountEventListenerDelegate =
+ new BinderProxyCountEventListenerDelegate();
static final class GcWatcher {
@Override
@@ -226,15 +226,24 @@ public class BinderInternal {
* @param low The threshold a binder count must drop below before the callback
* can be called again. (This is to avoid many repeated calls to the
* callback in a brief period of time)
+ * @param warning The threshold between {@code high} and {@code low} where if the binder count
+ * exceeds that, the warning callback would be triggered.
*/
- public static final native void nSetBinderProxyCountWatermarks(int high, int low);
+ public static final native void nSetBinderProxyCountWatermarks(int high, int low, int warning);
/**
* Interface for callback invocation when the Binder Proxy limit is reached. onLimitReached will
* be called with the uid of the app causing too many Binder Proxies
*/
- public interface BinderProxyLimitListener {
+ public interface BinderProxyCountEventListener {
public void onLimitReached(int uid);
+
+ /**
+ * Call when the number of binder proxies from the uid of the app reaches
+ * the warning threshold.
+ */
+ default void onWarningThresholdReached(int uid) {
+ }
}
/**
@@ -243,7 +252,17 @@ public class BinderInternal {
* @param uid The uid of the bad behaving app sending too many binders
*/
public static void binderProxyLimitCallbackFromNative(int uid) {
- sBinderProxyLimitListenerDelegate.notifyClient(uid);
+ sBinderProxyCountEventListenerDelegate.notifyLimitReached(uid);
+ }
+
+ /**
+ * Callback used by native code to trigger a callback in java code. The callback will be
+ * triggered when too many binder proxies from a uid hits the warning limit.
+ * @param uid The uid of the bad behaving app sending too many binders
+ */
+ @SuppressWarnings("unused")
+ public static void binderProxyWarningCallbackFromNative(int uid) {
+ sBinderProxyCountEventListenerDelegate.notifyWarningReached(uid);
}
/**
@@ -252,41 +271,45 @@ public class BinderInternal {
* @param handler must not be null, callback will be posted through the handler;
*
*/
- public static void setBinderProxyCountCallback(BinderProxyLimitListener listener,
+ public static void setBinderProxyCountCallback(BinderProxyCountEventListener listener,
@NonNull Handler handler) {
Preconditions.checkNotNull(handler,
"Must provide NonNull Handler to setBinderProxyCountCallback when setting "
- + "BinderProxyLimitListener");
- sBinderProxyLimitListenerDelegate.setListener(listener, handler);
+ + "BinderProxyCountEventListener");
+ sBinderProxyCountEventListenerDelegate.setListener(listener, handler);
}
/**
* Clear the Binder Proxy callback
*/
public static void clearBinderProxyCountCallback() {
- sBinderProxyLimitListenerDelegate.setListener(null, null);
+ sBinderProxyCountEventListenerDelegate.setListener(null, null);
}
- static private class BinderProxyLimitListenerDelegate {
- private BinderProxyLimitListener mBinderProxyLimitListener;
+ private static class BinderProxyCountEventListenerDelegate {
+ private BinderProxyCountEventListener mBinderProxyCountEventListener;
private Handler mHandler;
- void setListener(BinderProxyLimitListener listener, Handler handler) {
+ void setListener(BinderProxyCountEventListener listener, Handler handler) {
synchronized (this) {
- mBinderProxyLimitListener = listener;
+ mBinderProxyCountEventListener = listener;
mHandler = handler;
}
}
- void notifyClient(final int uid) {
+ void notifyLimitReached(final int uid) {
+ synchronized (this) {
+ if (mBinderProxyCountEventListener != null) {
+ mHandler.post(() -> mBinderProxyCountEventListener.onLimitReached(uid));
+ }
+ }
+ }
+
+ void notifyWarningReached(final int uid) {
synchronized (this) {
- if (mBinderProxyLimitListener != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mBinderProxyLimitListener.onLimitReached(uid);
- }
- });
+ if (mBinderProxyCountEventListener != null) {
+ mHandler.post(() ->
+ mBinderProxyCountEventListener.onWarningThresholdReached(uid));
}
}
}
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 9df93f9a50f7..e12becd87e12 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -407,8 +407,10 @@ public class ParsingPackageUtils {
*/
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) {
+ // The signature parsing will be done later in method parseBaseApk.
+ int liteParseFlags = flags & ~PARSE_COLLECT_CERTIFICATES;
final ParseResult<PackageLite> liteResult =
- ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
+ ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, liteParseFlags);
if (liteResult.isError()) {
return input.error(liteResult);
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index d2d5186eb8a1..2068bd7bc8ea 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -88,6 +88,7 @@ static struct binderinternal_offsets_t
jclass mClass;
jmethodID mForceGc;
jmethodID mProxyLimitCallback;
+ jmethodID mProxyWarningCallback;
} gBinderInternalOffsets;
@@ -1240,7 +1241,7 @@ static void android_os_BinderInternal_handleGc(JNIEnv* env, jobject clazz)
gCollectedAtRefs = gNumLocalRefsCreated + gNumDeathRefsCreated;
}
-static void android_os_BinderInternal_proxyLimitcallback(int uid)
+static void android_os_BinderInternal_proxyLimitCallback(int uid)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
@@ -1254,6 +1255,20 @@ static void android_os_BinderInternal_proxyLimitcallback(int uid)
}
}
+static void android_os_BinderInternal_proxyWarningCallback(int uid)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
+ gBinderInternalOffsets.mProxyWarningCallback,
+ uid);
+
+ if (env->ExceptionCheck()) {
+ ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
+ binder_report_exception(env, excep.get(),
+ "*** Uncaught exception in binderProxyWarningCallbackFromNative");
+ }
+}
+
static void android_os_BinderInternal_setBinderProxyCountEnabled(JNIEnv* env, jobject clazz,
jboolean enable)
{
@@ -1278,9 +1293,10 @@ static jint android_os_BinderInternal_getBinderProxyCount(JNIEnv* env, jobject c
}
static void android_os_BinderInternal_setBinderProxyCountWatermarks(JNIEnv* env, jobject clazz,
- jint high, jint low)
+ jint high, jint low,
+ jint warning)
{
- BpBinder::setBinderProxyCountWatermarks(high, low);
+ BpBinder::setBinderProxyCountWatermarks(high, low, warning);
}
// ----------------------------------------------------------------------------
@@ -1295,7 +1311,7 @@ static const JNINativeMethod gBinderInternalMethods[] = {
{ "nSetBinderProxyCountEnabled", "(Z)V", (void*)android_os_BinderInternal_setBinderProxyCountEnabled },
{ "nGetBinderProxyPerUidCounts", "()Landroid/util/SparseIntArray;", (void*)android_os_BinderInternal_getBinderProxyPerUidCounts },
{ "nGetBinderProxyCount", "(I)I", (void*)android_os_BinderInternal_getBinderProxyCount },
- { "nSetBinderProxyCountWatermarks", "(II)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
+ { "nSetBinderProxyCountWatermarks", "(III)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
};
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
@@ -1307,6 +1323,8 @@ static int int_register_android_os_BinderInternal(JNIEnv* env)
gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
gBinderInternalOffsets.mProxyLimitCallback = GetStaticMethodIDOrDie(env, clazz, "binderProxyLimitCallbackFromNative", "(I)V");
+ gBinderInternalOffsets.mProxyWarningCallback =
+ GetStaticMethodIDOrDie(env, clazz, "binderProxyWarningCallbackFromNative", "(I)V");
jclass SparseIntArrayClass = FindClassOrDie(env, "android/util/SparseIntArray");
gSparseIntArrayOffsets.classObject = MakeGlobalRefOrDie(env, SparseIntArrayClass);
@@ -1315,7 +1333,8 @@ static int int_register_android_os_BinderInternal(JNIEnv* env)
gSparseIntArrayOffsets.put = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject, "put",
"(II)V");
- BpBinder::setLimitCallback(android_os_BinderInternal_proxyLimitcallback);
+ BpBinder::setBinderProxyCountEventCallback(android_os_BinderInternal_proxyLimitCallback,
+ android_os_BinderInternal_proxyWarningCallback);
return RegisterMethodsOrDie(
env, kBinderInternalPathName,
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 24031cad0a3e..48082048691c 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -134,6 +134,8 @@ android_test {
":BinderDeathRecipientHelperApp1",
":BinderDeathRecipientHelperApp2",
":com.android.cts.helpers.aosp",
+ ":BinderProxyCountingTestApp",
+ ":BinderProxyCountingTestService",
],
}
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 05b309b2cd52..bf2a5b875dba 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -22,6 +22,8 @@
<option name="test-file-name" value="FrameworksCoreTests.apk" />
<option name="test-file-name" value="BinderDeathRecipientHelperApp1.apk" />
<option name="test-file-name" value="BinderDeathRecipientHelperApp2.apk" />
+ <option name="test-file-name" value="BinderProxyCountingTestApp.apk" />
+ <option name="test-file-name" value="BinderProxyCountingTestService.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
index a971730f389d..c8407b80cfac 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
+++ b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
@@ -16,6 +16,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.coretests.binderproxycountingtestapp">
+ <queries>
+ <package android:name="com.android.frameworks.coretests.binderproxycountingtestservice" />
+ </queries>
<application>
<service android:name=".BpcTestAppCmdService"
android:exported="true"/>
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
index 5aae1203e559..a7e97d3cd54e 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
+++ b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
@@ -17,14 +17,15 @@
package com.android.frameworks.coretests.binderproxycountingtestapp;
import android.app.Service;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.database.ContentObserver;
+import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.provider.Settings;
import android.util.Log;
import com.android.frameworks.coretests.aidl.IBinderProxyCountingService;
@@ -49,24 +50,20 @@ public class BpcTestAppCmdService extends Service {
private IBpcTestAppCmdService.Stub mBinder = new IBpcTestAppCmdService.Stub() {
- private ArrayList<BroadcastReceiver> mBrList = new ArrayList();
+ private ArrayList<ContentObserver> mCoList = new ArrayList();
private ArrayList<ITestRemoteCallback> mTrcList = new ArrayList();
+ private Handler mHandler = new Handler();
@Override
public void createSystemBinders(int count) {
int i = 0;
while (i++ < count) {
- BroadcastReceiver br = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
-
- }
- };
- IntentFilter filt = new IntentFilter(Intent.ACTION_POWER_DISCONNECTED);
- synchronized (mBrList) {
- mBrList.add(br);
+ final ContentObserver co = new ContentObserver(mHandler) {};
+ synchronized (mCoList) {
+ mCoList.add(co);
}
- registerReceiver(br, filt);
+ getContentResolver().registerContentObserver(
+ Settings.System.CONTENT_URI, false, co);
}
}
@@ -74,11 +71,11 @@ public class BpcTestAppCmdService extends Service {
public void releaseSystemBinders(int count) {
int i = 0;
while (i++ < count) {
- BroadcastReceiver br;
- synchronized (mBrList) {
- br = mBrList.remove(0);
+ ContentObserver co;
+ synchronized (mCoList) {
+ co = mCoList.remove(0);
}
- unregisterReceiver(br);
+ getContentResolver().unregisterContentObserver(co);
}
}
@@ -117,9 +114,9 @@ public class BpcTestAppCmdService extends Service {
@Override
public void releaseAllBinders() {
- synchronized (mBrList) {
- while (mBrList.size() > 0) {
- unregisterReceiver(mBrList.remove(0));
+ synchronized (mCoList) {
+ while (mCoList.size() > 0) {
+ getContentResolver().unregisterContentObserver(mCoList.remove(0));
}
}
synchronized (mTrcList) {
@@ -179,4 +176,4 @@ public class BpcTestAppCmdService extends Service {
public IBinder onBind(Intent intent) {
return mBinder;
}
-} \ No newline at end of file
+}
diff --git a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
index 6bed2a2ec53f..0f1accc4a7e9 100644
--- a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
+++ b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
@@ -55,8 +55,8 @@ public class BpcTestServiceCmdService extends Service {
}
@Override
- public void setBinderProxyWatermarks(int high, int low) {
- BinderInternal.nSetBinderProxyCountWatermarks(high, low);
+ public void setBinderProxyWatermarks(int high, int low, int warning) {
+ BinderInternal.nSetBinderProxyCountWatermarks(high, low, warning);
}
@Override
@@ -68,12 +68,23 @@ public class BpcTestServiceCmdService extends Service {
public void setBinderProxyCountCallback(IBpcCallbackObserver observer) {
if (observer != null) {
BinderInternal.setBinderProxyCountCallback(
- new BinderInternal.BinderProxyLimitListener() {
+ new BinderInternal.BinderProxyCountEventListener() {
@Override
public void onLimitReached(int uid) {
try {
synchronized (observer) {
- observer.onCallback(uid);
+ observer.onLimitReached(uid);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onWarningThresholdReached(int uid) {
+ try {
+ synchronized (observer) {
+ observer.onWarningThresholdReached(uid);
}
} catch (Exception e) {
Log.e(TAG, e.toString());
@@ -98,4 +109,4 @@ public class BpcTestServiceCmdService extends Service {
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
}
-} \ No newline at end of file
+}
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
index c4ebd56bed6c..ada7d92c89e1 100644
--- a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
@@ -17,5 +17,6 @@
package com.android.frameworks.coretests.aidl;
interface IBpcCallbackObserver {
- void onCallback(int uid);
-} \ No newline at end of file
+ void onLimitReached(int uid);
+ void onWarningThresholdReached(int uid);
+}
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
index abdab41ce537..cdcda9d93bd2 100644
--- a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
@@ -20,7 +20,7 @@ import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
interface IBpcTestServiceCmdService {
void forceGc();
int getBinderProxyCount(int uid);
- void setBinderProxyWatermarks(int high, int low);
+ void setBinderProxyWatermarks(int high, int low, int warning);
void enableBinderProxyLimit(boolean enable);
void setBinderProxyCountCallback(IBpcCallbackObserver observer);
-} \ No newline at end of file
+}
diff --git a/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java b/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
index b61104d6f389..7d7f8ed25869 100644
--- a/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
+++ b/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
@@ -18,13 +18,10 @@ package android.hardware.face;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
-import android.hardware.biometrics.face.IFace;
-import android.hardware.biometrics.face.SensorProps;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -37,8 +34,6 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.function.Function;
-
@Presubmit
@SmallTest
public class FaceSensorConfigurationsTest {
@@ -48,10 +43,6 @@ public class FaceSensorConfigurationsTest {
private Context mContext;
@Mock
private Resources mResources;
- @Mock
- private IFace mFace;
- @Mock
- private Function<String, IFace> mGetIFace;
private final String[] mAidlInstances = new String[]{"default", "virtual"};
private String[] mHidlConfigStrings = new String[]{"0:2:15", "0:8:15"};
@@ -59,15 +50,13 @@ public class FaceSensorConfigurationsTest {
@Before
public void setUp() throws RemoteException {
- when(mGetIFace.apply(anyString())).thenReturn(mFace);
- when(mFace.getSensorProps()).thenReturn(new SensorProps[]{});
when(mContext.getResources()).thenReturn(mResources);
}
@Test
public void testAidlInstanceSensorProps() {
mFaceSensorConfigurations = new FaceSensorConfigurations(false);
- mFaceSensorConfigurations.addAidlConfigs(mAidlInstances, mGetIFace);
+ mFaceSensorConfigurations.addAidlConfigs(mAidlInstances);
assertThat(mFaceSensorConfigurations.hasSensorConfigurations()).isTrue();
assertThat(!mFaceSensorConfigurations.isSingleSensorConfigurationPresent()).isTrue();
diff --git a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
index f058c160373c..b2f8299a8a35 100644
--- a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
+++ b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
@@ -18,13 +18,10 @@ package android.hardware.fingerprint;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
-import android.hardware.biometrics.fingerprint.IFingerprint;
-import android.hardware.biometrics.fingerprint.SensorProps;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -37,8 +34,6 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.function.Function;
-
@Presubmit
@SmallTest
public class FingerprintSensorConfigurationsTest {
@@ -48,10 +43,6 @@ public class FingerprintSensorConfigurationsTest {
private Context mContext;
@Mock
private Resources mResources;
- @Mock
- private IFingerprint mFingerprint;
- @Mock
- private Function<String, IFingerprint> mGetIFingerprint;
private final String[] mAidlInstances = new String[]{"default", "virtual"};
private String[] mHidlConfigStrings = new String[]{"0:2:15", "0:8:15"};
@@ -59,8 +50,6 @@ public class FingerprintSensorConfigurationsTest {
@Before
public void setUp() throws RemoteException {
- when(mGetIFingerprint.apply(anyString())).thenReturn(mFingerprint);
- when(mFingerprint.getSensorProps()).thenReturn(new SensorProps[]{});
when(mContext.getResources()).thenReturn(mResources);
}
@@ -68,7 +57,7 @@ public class FingerprintSensorConfigurationsTest {
public void testAidlInstanceSensorProps() {
mFingerprintSensorConfigurations = new FingerprintSensorConfigurations(
true /* resetLockoutRequiresHardwareAuthToken */);
- mFingerprintSensorConfigurations.addAidlSensors(mAidlInstances, mGetIFingerprint);
+ mFingerprintSensorConfigurations.addAidlSensors(mAidlInstances);
assertThat(mFingerprintSensorConfigurations.hasSensorConfigurations()).isTrue();
assertThat(!mFingerprintSensorConfigurations.isSingleSensorConfigurationPresent())
diff --git a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
index bcd9521019e4..84d299592f26 100644
--- a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
@@ -88,9 +88,10 @@ public class BinderProxyCountingTest {
private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
private static final int TOO_MANY_BINDERS_TIMEOUT_SEC = 2;
+ private static final int TOO_MANY_BINDERS_WITH_KILL_TIMEOUT_SEC = 30;
- // Keep in sync with sBinderProxyCountLimit in BpBinder.cpp
- private static final int BINDER_PROXY_LIMIT = 2500;
+ // Keep in sync with BINDER_PROXY_HIGH_WATERMARK in ActivityManagerService.java
+ private static final int BINDER_PROXY_LIMIT = 6000;
private static Context sContext;
private static UiDevice sUiDevice;
@@ -175,18 +176,26 @@ public class BinderProxyCountingTest {
}
}
- private CountDownLatch createBinderLimitLatch() throws RemoteException {
- final CountDownLatch latch = new CountDownLatch(1);
+ private CountDownLatch[] createBinderLimitLatch() throws RemoteException {
+ final CountDownLatch[] latches = new CountDownLatch[] {
+ new CountDownLatch(1), new CountDownLatch(1)
+ };
sBpcTestServiceCmdService.setBinderProxyCountCallback(
new IBpcCallbackObserver.Stub() {
@Override
- public void onCallback(int uid) {
+ public void onLimitReached(int uid) {
if (uid == sTestPkgUid) {
- latch.countDown();
+ latches[0].countDown();
+ }
+ }
+ @Override
+ public void onWarningThresholdReached(int uid) {
+ if (uid == sTestPkgUid) {
+ latches[1].countDown();
}
}
});
- return latch;
+ return latches;
}
/**
@@ -227,6 +236,7 @@ public class BinderProxyCountingTest {
@Test
public void testBinderProxyLimitBoundary() throws Exception {
final int binderProxyLimit = 2000;
+ final int binderProxyWarning = 1900;
final int rearmThreshold = 1800;
try {
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
@@ -238,19 +248,33 @@ public class BinderProxyCountingTest {
// Get the baseline of binders naturally held by the test Package
int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
- final CountDownLatch binderLimitLatch = createBinderLimitLatch();
- sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+ final CountDownLatch[] binderLatches = createBinderLimitLatch();
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold,
+ binderProxyWarning);
+
+ // Create Binder Proxies up to the warning;
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - baseBinderCount);
+ if (binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ + " when proxy warning should not have been triggered");
+ }
+
+ // Create one more Binder to trigger the warning
+ sBpcTestAppCmdService.createTestBinders(1);
+ if (!binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger the warning");
+ }
// Create Binder Proxies up to the limit
- sBpcTestAppCmdService.createTestBinders(binderProxyLimit - baseBinderCount);
- if (binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(binderProxyLimit - binderProxyWarning - 1);
+ if (binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ " when proxy limit should not have been reached");
}
// Create one more Binder to cross the limit
sBpcTestAppCmdService.createTestBinders(1);
- if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
@@ -274,12 +298,20 @@ public class BinderProxyCountingTest {
sBpcTestServiceCmdService.forceGc();
int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
for (int testLimit : testLimits) {
- final CountDownLatch binderLimitLatch = createBinderLimitLatch();
+ final CountDownLatch[] binderLatches = createBinderLimitLatch();
// Change the BinderProxyLimit
- sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10);
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10,
+ testLimit - 10);
+
+ // Trigger the new Binder Proxy warning
+ sBpcTestAppCmdService.createTestBinders(testLimit - 9 - baseBinderCount);
+ if (!binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger the warning");
+ }
+
// Exceed the new Binder Proxy Limit
- sBpcTestAppCmdService.createTestBinders(testLimit + 1);
- if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(10);
+ if (!binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
@@ -297,6 +329,7 @@ public class BinderProxyCountingTest {
public void testRearmCallbackThreshold() throws Exception {
final int binderProxyLimit = 2000;
final int exceedBinderProxyLimit = binderProxyLimit + 10;
+ final int binderProxyWarning = 1900;
final int rearmThreshold = 1800;
try {
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
@@ -305,11 +338,19 @@ public class BinderProxyCountingTest {
sBpcTestServiceCmdService.enableBinderProxyLimit(true);
sBpcTestServiceCmdService.forceGc();
- final CountDownLatch firstBinderLimitLatch = createBinderLimitLatch();
- sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+ int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ final CountDownLatch[] firstBinderLatches = createBinderLimitLatch();
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold,
+ binderProxyWarning);
+ // Trigger the Binder Proxy Waring
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - baseBinderCount + 1);
+ if (!firstBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger warning");
+ }
+
// Exceed the Binder Proxy Limit
- sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit);
- if (!firstBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - binderProxyWarning);
+ if (!firstBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
@@ -321,11 +362,20 @@ public class BinderProxyCountingTest {
sBpcTestServiceCmdService.forceGc();
currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
- final CountDownLatch secondBinderLimitLatch = createBinderLimitLatch();
+ final CountDownLatch[] secondBinderLatches = createBinderLimitLatch();
+
+ // Exceed the Binder Proxy warning which should not cause a callback since there has
+ // been no rearm
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - currentBinderCount + 1);
+ if (secondBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ + " when the callback has not been rearmed yet");
+ }
+
// Exceed the Binder Proxy limit which should not cause a callback since there has
// been no rearm
- sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
- if (secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - binderProxyWarning);
+ if (secondBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ " when the callback has not been rearmed yet");
}
@@ -337,10 +387,16 @@ public class BinderProxyCountingTest {
sBpcTestServiceCmdService.forceGc();
currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ // Trigger the Binder Proxy Waring
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - currentBinderCount + 1);
+ if (!secondBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger warning");
+ }
+
// Exceed the Binder Proxy limit for the last time
sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
- if (!secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!secondBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
sBpcTestAppCmdService.releaseTestBinders(currentBinderCount);
@@ -373,7 +429,7 @@ public class BinderProxyCountingTest {
// is not unexpected
}
- if (!binderDeathLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!binderDeathLatch.await(TOO_MANY_BINDERS_WITH_KILL_TIMEOUT_SEC, TimeUnit.SECONDS)) {
sBpcTestAppCmdService.releaseSystemBinders(exceedBinderProxyLimit);
fail("Timed out waiting for uid " + sTestPkgUid + " to die.");
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index ad3be3d0b022..59c841f63498 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -686,7 +686,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
}
- private void dispatchOnBackCancelled(IOnBackInvokedCallback callback) {
+ private void tryDispatchOnBackCancelled(IOnBackInvokedCallback callback) {
+ if (!mOnBackStartDispatched) {
+ Log.e(TAG, "Skipping dispatching onBackCancelled. Start was never dispatched.");
+ return;
+ }
if (callback == null) {
return;
}
@@ -745,7 +749,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (touchTracker.getTriggerBack()) {
dispatchOrAnimateOnBackInvoked(callback, touchTracker);
} else {
- dispatchOnBackCancelled(callback);
+ tryDispatchOnBackCancelled(callback);
}
}
finishBackNavigation(touchTracker.getTriggerBack());
@@ -824,7 +828,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (mCurrentTracker.getTriggerBack()) {
dispatchOrAnimateOnBackInvoked(mActiveCallback, mCurrentTracker);
} else {
- dispatchOnBackCancelled(mActiveCallback);
+ tryDispatchOnBackCancelled(mActiveCallback);
}
}
@@ -876,7 +880,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (mCurrentTracker.isInInitialState()) {
if (mBackGestureStarted) {
mBackGestureStarted = false;
- dispatchOnBackCancelled(mActiveCallback);
+ tryDispatchOnBackCancelled(mActiveCallback);
finishBackNavigation(false);
ProtoLog.d(WM_SHELL_BACK_PREVIEW,
"resetTouchTracker -> reset an unfinished gesture");
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 2919782a758a..d839eae27171 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -557,6 +557,23 @@ public class BackAnimationControllerTest extends ShellTestCase {
}
@Test
+ public void skipsCancelWithoutStart() throws RemoteException {
+ final int type = BackNavigationInfo.TYPE_CALLBACK;
+ final ResultListener result = new ResultListener();
+ createNavigationInfo(new BackNavigationInfo.Builder()
+ .setType(type)
+ .setOnBackInvokedCallback(mAppCallback)
+ .setOnBackNavigationDone(new RemoteCallback(result)));
+ doMotionEvent(MotionEvent.ACTION_CANCEL, 0);
+ mShellExecutor.flushAll();
+
+ verify(mAppCallback, never()).onBackStarted(any());
+ verify(mAppCallback, never()).onBackProgressed(any());
+ verify(mAppCallback, never()).onBackInvoked();
+ verify(mAppCallback, never()).onBackCancelled();
+ }
+
+ @Test
public void testBackToActivity() throws RemoteException {
final CrossActivityBackAnimation animation = new CrossActivityBackAnimation(
mContext, mAnimationBackground, mRootTaskDisplayAreaOrganizer);
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
index e7fec692bd63..65a5317ed0cb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
@@ -73,6 +73,10 @@ interface AudioRepository {
suspend fun setVolume(audioStream: AudioStream, volume: Int)
suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean)
+
+ suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode)
+
+ suspend fun isAffectedByMute(audioStream: AudioStream): Boolean
}
class AudioRepositoryImpl(
@@ -169,6 +173,16 @@ class AudioRepositoryImpl(
)
}
+ override suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode) {
+ withContext(backgroundCoroutineContext) { audioManager.ringerMode = mode.value }
+ }
+
+ override suspend fun isAffectedByMute(audioStream: AudioStream): Boolean {
+ return withContext(backgroundCoroutineContext) {
+ audioManager.isStreamAffectedByMute(audioStream.value)
+ }
+ }
+
private fun getMinVolume(stream: AudioStream): Int =
try {
audioManager.getStreamMinVolume(stream.value)
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
index 778653b9bd44..33f917e701c2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
@@ -49,8 +49,14 @@ class AudioVolumeInteractor(
suspend fun setVolume(audioStream: AudioStream, volume: Int) =
audioRepository.setVolume(audioStream, volume)
- suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean) =
+ suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean) {
+ if (audioStream.value == AudioManager.STREAM_RING) {
+ val mode =
+ if (isMuted) AudioManager.RINGER_MODE_VIBRATE else AudioManager.RINGER_MODE_NORMAL
+ audioRepository.setRingerMode(audioStream, RingerMode(mode))
+ }
audioRepository.setMuted(audioStream, isMuted)
+ }
/** Checks if the volume can be changed via the UI. */
fun canChangeVolume(audioStream: AudioStream): Flow<Boolean> {
@@ -66,9 +72,8 @@ class AudioVolumeInteractor(
}
}
- fun isMutable(audioStream: AudioStream): Boolean =
- // Alarm stream doesn't support muting
- audioStream.value != AudioManager.STREAM_ALARM
+ suspend fun isAffectedByMute(audioStream: AudioStream): Boolean =
+ audioRepository.isAffectedByMute(audioStream)
private suspend fun processVolume(
audioStreamModel: AudioStreamModel,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt
index dbdf970467b5..24cc8a4cfcec 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt
@@ -711,7 +711,6 @@ private class AnimatedDialog(
dialog.setDismissOverride(this::onDialogDismissed)
if (featureFlags.isPredictiveBackQsDialogAnim) {
- // TODO(b/265923095) Improve animations for QS dialogs on configuration change
dialog.registerAnimationOnBackInvoked(targetView = dialogContentWithBackground)
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
index dd32851a97cf..4d327e1d8beb 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
@@ -37,7 +37,7 @@ fun interface BackAnimationSpec {
/** Create a [BackAnimationSpec] from [displayMetrics] and design specs. */
fun BackAnimationSpec.Companion.createFloatingSurfaceAnimationSpec(
- displayMetrics: DisplayMetrics,
+ displayMetricsProvider: () -> DisplayMetrics,
maxMarginXdp: Float,
maxMarginYdp: Float,
minScale: Float,
@@ -45,18 +45,19 @@ fun BackAnimationSpec.Companion.createFloatingSurfaceAnimationSpec(
translateYEasing: Interpolator = Interpolators.LINEAR,
scaleEasing: Interpolator = Interpolators.STANDARD_DECELERATE,
): BackAnimationSpec {
- val screenWidthPx = displayMetrics.widthPixels
- val screenHeightPx = displayMetrics.heightPixels
+ return BackAnimationSpec { backEvent, progressY, result ->
+ val displayMetrics = displayMetricsProvider()
+ val screenWidthPx = displayMetrics.widthPixels
+ val screenHeightPx = displayMetrics.heightPixels
- val maxMarginXPx = maxMarginXdp.dpToPx(displayMetrics)
- val maxMarginYPx = maxMarginYdp.dpToPx(displayMetrics)
- val maxTranslationXByScale = (screenWidthPx - screenWidthPx * minScale) / 2
- val maxTranslationX = maxTranslationXByScale - maxMarginXPx
- val maxTranslationYByScale = (screenHeightPx - screenHeightPx * minScale) / 2
- val maxTranslationY = maxTranslationYByScale - maxMarginYPx
- val minScaleReversed = 1f - minScale
+ val maxMarginXPx = maxMarginXdp.dpToPx(displayMetrics)
+ val maxMarginYPx = maxMarginYdp.dpToPx(displayMetrics)
+ val maxTranslationXByScale = (screenWidthPx - screenWidthPx * minScale) / 2
+ val maxTranslationX = maxTranslationXByScale - maxMarginXPx
+ val maxTranslationYByScale = (screenHeightPx - screenHeightPx * minScale) / 2
+ val maxTranslationY = maxTranslationYByScale - maxMarginYPx
+ val minScaleReversed = 1f - minScale
- return BackAnimationSpec { backEvent, progressY, result ->
val direction = if (backEvent.swipeEdge == BackEvent.EDGE_LEFT) 1 else -1
val progressX = backEvent.progress
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt
index b8d446961a88..b05729669f7c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt
@@ -23,10 +23,10 @@ import android.util.DisplayMetrics
* https://carbon.googleplex.com/predictive-back-for-apps/pages/st-1-dismiss-app
*/
fun BackAnimationSpec.Companion.dismissAppForSysUi(
- displayMetrics: DisplayMetrics,
+ displayMetricsProvider: () -> DisplayMetrics,
): BackAnimationSpec =
BackAnimationSpec.createFloatingSurfaceAnimationSpec(
- displayMetrics = displayMetrics,
+ displayMetricsProvider = displayMetricsProvider,
maxMarginXdp = 8f,
maxMarginYdp = 8f,
minScale = 0.8f,
@@ -37,10 +37,10 @@ fun BackAnimationSpec.Companion.dismissAppForSysUi(
* https://carbon.googleplex.com/predictive-back-for-apps/pages/st-2-cross-task
*/
fun BackAnimationSpec.Companion.crossTaskForSysUi(
- displayMetrics: DisplayMetrics,
+ displayMetricsProvider: () -> DisplayMetrics,
): BackAnimationSpec =
BackAnimationSpec.createFloatingSurfaceAnimationSpec(
- displayMetrics = displayMetrics,
+ displayMetricsProvider = displayMetricsProvider,
maxMarginXdp = 8f,
maxMarginYdp = 8f,
minScale = 0.8f,
@@ -51,10 +51,10 @@ fun BackAnimationSpec.Companion.crossTaskForSysUi(
* https://carbon.googleplex.com/predictive-back-for-apps/pages/st-3-inner-area-dismiss
*/
fun BackAnimationSpec.Companion.innerAreaDismissForSysUi(
- displayMetrics: DisplayMetrics,
+ displayMetricsProvider: () -> DisplayMetrics,
): BackAnimationSpec =
BackAnimationSpec.createFloatingSurfaceAnimationSpec(
- displayMetrics = displayMetrics,
+ displayMetricsProvider = displayMetricsProvider,
maxMarginXdp = 0f,
maxMarginYdp = 0f,
minScale = 0.9f,
@@ -65,10 +65,10 @@ fun BackAnimationSpec.Companion.innerAreaDismissForSysUi(
* https://carbon.googleplex.com/predictive-back-for-apps/pages/st-4-floating-system-surfaces
*/
fun BackAnimationSpec.Companion.floatingSystemSurfacesForSysUi(
- displayMetrics: DisplayMetrics,
+ displayMetricsProvider: () -> DisplayMetrics,
): BackAnimationSpec =
BackAnimationSpec.createFloatingSurfaceAnimationSpec(
- displayMetrics = displayMetrics,
+ displayMetricsProvider = displayMetricsProvider,
maxMarginXdp = 8f,
maxMarginYdp = 8f,
minScale = 0.9f,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt b/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt
index 0f63548b6f0c..9dd23289d8b5 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt
@@ -39,7 +39,7 @@ fun Dialog.registerAnimationOnBackInvoked(
targetView: View,
backAnimationSpec: BackAnimationSpec =
BackAnimationSpec.floatingSystemSurfacesForSysUi(
- displayMetrics = targetView.resources.displayMetrics,
+ displayMetricsProvider = { targetView.resources.displayMetrics },
),
) {
targetView.registerOnBackInvokedCallbackOnViewAttached(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index a1d8c29c2a39..bdd888f45182 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -8,12 +8,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.FixedSizeEdgeDetector
import com.android.compose.animation.scene.LowestZIndexScenePicker
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayout
@@ -21,12 +24,13 @@ import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.transitions
-import com.android.compose.animation.scene.updateSceneTransitionLayoutState
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
+import com.android.systemui.scene.ui.composable.SceneTransitionLayoutDataSource
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
object Communal {
@@ -63,27 +67,35 @@ val sceneTransitions = transitions {
fun CommunalContainer(
modifier: Modifier = Modifier,
viewModel: CommunalViewModel,
+ dataSourceDelegator: SceneDataSourceDelegator,
dialogFactory: SystemUIDialogFactory,
) {
- val currentScene: SceneKey by viewModel.currentScene.collectAsState(CommunalScenes.Blank)
- val sceneTransitionLayoutState =
- updateSceneTransitionLayoutState(
- currentScene,
- onChangeScene = { viewModel.onSceneChanged(it) },
+ val coroutineScope = rememberCoroutineScope()
+ val currentSceneKey: SceneKey by viewModel.currentScene.collectAsState(CommunalScenes.Blank)
+ val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false)
+ val state: MutableSceneTransitionLayoutState = remember {
+ MutableSceneTransitionLayoutState(
+ initialScene = currentSceneKey,
transitions = sceneTransitions,
enableInterruptions = false,
)
- val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false)
+ }
+
+ DisposableEffect(state) {
+ val dataSource = SceneTransitionLayoutDataSource(state, coroutineScope)
+ dataSourceDelegator.setDelegate(dataSource)
+ onDispose { dataSourceDelegator.setDelegate(null) }
+ }
// This effect exposes the SceneTransitionLayout's observable transition state to the rest of
// the system, and unsets it when the view is disposed to avoid a memory leak.
- DisposableEffect(viewModel, sceneTransitionLayoutState) {
- viewModel.setTransitionState(sceneTransitionLayoutState.observableTransitionState())
+ DisposableEffect(viewModel, state) {
+ viewModel.setTransitionState(state.observableTransitionState())
onDispose { viewModel.setTransitionState(null) }
}
SceneTransitionLayout(
- state = sceneTransitionLayoutState,
+ state = state,
modifier = modifier.fillMaxSize(),
swipeSourceDetector =
FixedSizeEdgeDetector(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index 1178cc843d60..4bef9efe79d1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -16,7 +16,6 @@
package com.android.systemui.keyguard.ui.composable
-import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
@@ -24,9 +23,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
-import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.SceneTransitionLayout
-import com.android.compose.animation.scene.transitions
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
@@ -45,16 +42,12 @@ constructor(
private val blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
private val clockInteractor: KeyguardClockInteractor,
) {
-
- private val sceneKeyByBlueprint: Map<ComposableLockscreenSceneBlueprint, SceneKey> by lazy {
- blueprints.associateWith { blueprint -> SceneKey(blueprint.id) }
- }
- private val sceneKeyByBlueprintId: Map<String, SceneKey> by lazy {
- sceneKeyByBlueprint.entries.associate { (blueprint, sceneKey) -> blueprint.id to sceneKey }
+ private val blueprintByBlueprintId: Map<String, ComposableLockscreenSceneBlueprint> by lazy {
+ blueprints.associateBy { it.id }
}
@Composable
- fun Content(
+ fun SceneScope.Content(
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
@@ -66,19 +59,7 @@ constructor(
onDispose { clockInteractor.clockEventController.unregisterListeners() }
}
- // Switch smoothly between blueprints, any composable tagged with element() will be
- // transition-animated between any two blueprints, if they both display the same element.
- SceneTransitionLayout(
- currentScene = checkNotNull(sceneKeyByBlueprintId[blueprintId]),
- onChangeScene = {},
- transitions =
- transitions { sceneKeyByBlueprintId.values.forEach { sceneKey -> to(sceneKey) } },
- modifier = modifier,
- enableInterruptions = false,
- ) {
- sceneKeyByBlueprint.entries.forEach { (blueprint, sceneKey) ->
- scene(sceneKey) { with(blueprint) { Content(Modifier.fillMaxSize()) } }
- }
- }
+ val blueprint = blueprintByBlueprintId[blueprintId] ?: return
+ with(blueprint) { Content(modifier) }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index 7acb4d5498db..c241f9ca7253 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -66,9 +66,5 @@ private fun SceneScope.LockscreenScene(
key = QuickSettings.SharedValues.TilesSquishiness,
)
- lockscreenContent
- .get()
- .Content(
- modifier = modifier.fillMaxSize(),
- )
+ with(lockscreenContent.get()) { Content(modifier = modifier.fillMaxSize()) }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 320c455a8201..c008a1a4d192 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -16,10 +16,15 @@
package com.android.systemui.keyguard.ui.composable.blueprint
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.unit.IntRect
@@ -28,6 +33,7 @@ import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.composable.section.TopAreaSection
@@ -52,6 +58,7 @@ constructor(
private val bottomAreaSection: BottomAreaSection,
private val settingsMenuSection: SettingsMenuSection,
private val topAreaSection: TopAreaSection,
+ private val notificationSection: NotificationSection,
) : ComposableLockscreenSceneBlueprint {
override val id: String = "default"
@@ -59,6 +66,8 @@ constructor(
@Composable
override fun SceneScope.Content(modifier: Modifier) {
val isUdfpsVisible = viewModel.isUdfpsVisible
+ val shouldUseSplitNotificationShade by
+ viewModel.shouldUseSplitNotificationShade.collectAsState()
LockscreenLongPress(
viewModel = viewModel.longPress,
@@ -68,10 +77,27 @@ constructor(
content = {
// Constrained to above the lock icon.
Column(
- modifier = Modifier.fillMaxWidth(),
+ modifier = Modifier.fillMaxSize(),
) {
with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
- with(topAreaSection) { DefaultClockLayoutWithNotifications() }
+
+ Box {
+ with(topAreaSection) { DefaultClockLayout() }
+ if (shouldUseSplitNotificationShade) {
+ with(notificationSection) {
+ Notifications(
+ Modifier.fillMaxWidth(0.5f)
+ .fillMaxHeight()
+ .align(alignment = Alignment.TopEnd)
+ )
+ }
+ }
+ }
+ if (!shouldUseSplitNotificationShade) {
+ with(notificationSection) {
+ Notifications(Modifier.weight(weight = 1f))
+ }
+ }
if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
with(ambientIndicationSectionOptional.get()) {
AmbientIndication(modifier = Modifier.fillMaxWidth())
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
index 64c2cb3670c8..091a43923a6e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
@@ -16,10 +16,15 @@
package com.android.systemui.keyguard.ui.composable.blueprint
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.unit.IntRect
@@ -28,6 +33,7 @@ import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.composable.section.TopAreaSection
@@ -52,6 +58,7 @@ constructor(
private val bottomAreaSection: BottomAreaSection,
private val settingsMenuSection: SettingsMenuSection,
private val topAreaSection: TopAreaSection,
+ private val notificationSection: NotificationSection,
) : ComposableLockscreenSceneBlueprint {
override val id: String = "shortcuts-besides-udfps"
@@ -59,6 +66,8 @@ constructor(
@Composable
override fun SceneScope.Content(modifier: Modifier) {
val isUdfpsVisible = viewModel.isUdfpsVisible
+ val shouldUseSplitNotificationShade by
+ viewModel.shouldUseSplitNotificationShade.collectAsState()
LockscreenLongPress(
viewModel = viewModel.longPress,
@@ -68,11 +77,27 @@ constructor(
content = {
// Constrained to above the lock icon.
Column(
- modifier = Modifier.fillMaxWidth(),
+ modifier = Modifier.fillMaxSize(),
) {
with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
- with(topAreaSection) { DefaultClockLayoutWithNotifications() }
+ Box {
+ with(topAreaSection) { DefaultClockLayout() }
+ if (shouldUseSplitNotificationShade) {
+ with(notificationSection) {
+ Notifications(
+ Modifier.fillMaxWidth(0.5f)
+ .fillMaxHeight()
+ .align(alignment = Alignment.TopEnd)
+ )
+ }
+ }
+ }
+ if (!shouldUseSplitNotificationShade) {
+ with(notificationSection) {
+ Notifications(Modifier.weight(weight = 1f))
+ }
+ }
if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
with(ambientIndicationSectionOptional.get()) {
AmbientIndication(modifier = Modifier.fillMaxWidth())
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
index fe774a0d6db2..09d76a341442 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
@@ -86,6 +86,7 @@ constructor(
val burnIn = rememberBurnIn(clockInteractor)
val resources = LocalContext.current.resources
val currentClockState = clockViewModel.currentClock.collectAsState()
+ val areNotificationsVisible by viewModel.areNotificationsVisible.collectAsState()
LockscreenLongPress(
viewModel = viewModel.longPress,
modifier = modifier,
@@ -145,7 +146,7 @@ constructor(
with(mediaCarouselSection) { MediaCarousel() }
- if (viewModel.areNotificationsVisible) {
+ if (areNotificationsVisible) {
with(notificationSection) {
Notifications(
modifier = Modifier.fillMaxWidth().weight(weight = 1f)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index 6b86a484069b..fa0a1c4663b1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -17,12 +17,25 @@
package com.android.systemui.keyguard.ui.composable.section
import android.view.ViewGroup
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.SceneScope
+import com.android.compose.modifiers.thenIf
+import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.MigrateClocksToBlueprint
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.notifications.ui.composable.NotificationStack
+import com.android.systemui.res.R
+import com.android.systemui.shade.LargeScreenHeaderHelper
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
@@ -39,6 +52,7 @@ constructor(
sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
stackScrollLayout: NotificationStackScrollLayout,
sharedNotificationContainerBinder: SharedNotificationContainerBinder,
+ private val lockscreenContentViewModel: LockscreenContentViewModel,
) {
init {
@@ -65,9 +79,27 @@ constructor(
@Composable
fun SceneScope.Notifications(modifier: Modifier = Modifier) {
+ val shouldUseSplitNotificationShade by
+ lockscreenContentViewModel.shouldUseSplitNotificationShade.collectAsState()
+ val areNotificationsVisible by
+ lockscreenContentViewModel.areNotificationsVisible.collectAsState()
+ val splitShadeTopMargin: Dp =
+ if (Flags.centralizedStatusBarHeightFix()) {
+ LargeScreenHeaderHelper.getLargeScreenHeaderHeight(LocalContext.current).dp
+ } else {
+ dimensionResource(id = R.dimen.large_screen_shade_header_height)
+ }
+
+ if (!areNotificationsVisible) {
+ return
+ }
+
NotificationStack(
viewModel = viewModel,
- modifier = modifier,
+ modifier =
+ modifier.fillMaxWidth().thenIf(shouldUseSplitNotificationShade) {
+ Modifier.padding(top = splitShadeTopMargin)
+ },
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index b4472fc15ac4..f8e63411ed52 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -16,30 +16,20 @@
package com.android.systemui.keyguard.ui.composable.section
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
-import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.dimensionResource
-import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.modifiers.thenIf
-import com.android.systemui.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.largeClockScene
import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.smallClockScene
@@ -48,8 +38,6 @@ import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.splitSh
import com.android.systemui.keyguard.ui.composable.blueprint.ClockTransition
import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
-import com.android.systemui.res.R
-import com.android.systemui.shade.LargeScreenHeaderHelper
import javax.inject.Inject
class TopAreaSection
@@ -58,19 +46,16 @@ constructor(
private val clockViewModel: KeyguardClockViewModel,
private val smartSpaceSection: SmartSpaceSection,
private val mediaCarouselSection: MediaCarouselSection,
- private val notificationSection: NotificationSection,
private val clockSection: DefaultClockSection,
private val clockInteractor: KeyguardClockInteractor,
) {
@Composable
- fun DefaultClockLayoutWithNotifications(
+ fun DefaultClockLayout(
modifier: Modifier = Modifier,
) {
- val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsState()
val currentClockLayout by clockViewModel.currentClockLayout.collectAsState()
val hasCustomPositionUpdatedAnimation by
clockViewModel.hasCustomPositionUpdatedAnimation.collectAsState()
-
val currentScene =
when (currentClockLayout) {
KeyguardClockViewModel.ClockLayout.SPLIT_SHADE_LARGE_CLOCK ->
@@ -81,144 +66,83 @@ constructor(
KeyguardClockViewModel.ClockLayout.SMALL_CLOCK -> smallClockScene
}
- val splitShadeTopMargin: Dp =
- if (Flags.centralizedStatusBarHeightFix()) {
- LargeScreenHeaderHelper.getLargeScreenHeaderHeight(LocalContext.current).dp
- } else {
- dimensionResource(id = R.dimen.large_screen_shade_header_height)
- }
- val burnIn = rememberBurnIn(clockInteractor)
-
- LaunchedEffect(isLargeClockVisible) {
- if (isLargeClockVisible) {
- burnIn.onSmallClockTopChanged(null)
- }
- }
-
SceneTransitionLayout(
- modifier = modifier.fillMaxSize(),
+ modifier = modifier,
currentScene = currentScene,
onChangeScene = {},
transitions = ClockTransition.defaultClockTransitions,
enableInterruptions = false,
) {
scene(splitShadeLargeClockScene) {
- Box(modifier = Modifier.fillMaxSize()) {
- Column(
- modifier = Modifier.fillMaxSize(),
- horizontalAlignment = Alignment.CenterHorizontally,
- ) {
- with(smartSpaceSection) {
- SmartSpace(
- burnInParams = burnIn.parameters,
- onTopChanged = burnIn.onSmartspaceTopChanged,
- )
- }
-
- with(clockSection) {
- LargeClock(
- modifier =
- Modifier.fillMaxSize().thenIf(
- !hasCustomPositionUpdatedAnimation
- ) {
- // If we do not have a custom position animation, we want
- // the clock to be on one half of the screen.
- Modifier.offset {
- IntOffset(
- x =
- -clockSection
- .getClockCenteringDistance()
- .toInt(),
- y = 0,
- )
- }
- }
- )
- }
- }
- }
-
- Row(
- modifier = Modifier.fillMaxSize(),
- ) {
- Spacer(modifier = Modifier.weight(weight = 1f))
- with(notificationSection) {
- Notifications(
- modifier =
- Modifier.fillMaxHeight()
- .weight(weight = 1f)
- .padding(top = splitShadeTopMargin)
- )
- }
- }
+ LargeClockWithSmartSpace(
+ shouldOffSetClockToOneHalf = !hasCustomPositionUpdatedAnimation
+ )
}
scene(splitShadeSmallClockScene) {
- Row(
- modifier = Modifier.fillMaxSize(),
- ) {
- Column(
- modifier = Modifier.fillMaxHeight().weight(weight = 1f),
- horizontalAlignment = Alignment.CenterHorizontally,
- ) {
- with(clockSection) {
- SmallClock(
- burnInParams = burnIn.parameters,
- onTopChanged = burnIn.onSmallClockTopChanged,
- modifier = Modifier.wrapContentSize()
- )
- }
- with(smartSpaceSection) {
- SmartSpace(
- burnInParams = burnIn.parameters,
- onTopChanged = burnIn.onSmartspaceTopChanged,
- )
- }
- with(mediaCarouselSection) { MediaCarousel() }
- }
- with(notificationSection) {
- Notifications(
- modifier =
- Modifier.fillMaxHeight()
- .weight(weight = 1f)
- .padding(top = splitShadeTopMargin)
- )
- }
- }
+ SmallClockWithSmartSpace(modifier = Modifier.fillMaxWidth(0.5f))
}
- scene(smallClockScene) {
- Column {
- with(clockSection) {
- SmallClock(
- burnInParams = burnIn.parameters,
- onTopChanged = burnIn.onSmallClockTopChanged,
- modifier = Modifier.wrapContentSize()
- )
- }
- with(smartSpaceSection) {
- SmartSpace(
- burnInParams = burnIn.parameters,
- onTopChanged = burnIn.onSmartspaceTopChanged,
- )
- }
- with(mediaCarouselSection) { MediaCarousel() }
- with(notificationSection) {
- Notifications(modifier = Modifier.fillMaxWidth().weight(weight = 1f))
- }
- }
+ scene(smallClockScene) { SmallClockWithSmartSpace() }
+
+ scene(largeClockScene) { LargeClockWithSmartSpace() }
+ }
+ }
+
+ @Composable
+ private fun SceneScope.SmallClockWithSmartSpace(modifier: Modifier = Modifier) {
+ val burnIn = rememberBurnIn(clockInteractor)
+
+ Column(modifier = modifier) {
+ with(clockSection) {
+ SmallClock(
+ burnInParams = burnIn.parameters,
+ onTopChanged = burnIn.onSmallClockTopChanged,
+ modifier = Modifier.wrapContentSize()
+ )
+ }
+ with(smartSpaceSection) {
+ SmartSpace(
+ burnInParams = burnIn.parameters,
+ onTopChanged = burnIn.onSmartspaceTopChanged,
+ )
}
+ with(mediaCarouselSection) { MediaCarousel() }
+ }
+ }
- scene(largeClockScene) {
- Column {
- with(smartSpaceSection) {
- SmartSpace(
- burnInParams = burnIn.parameters,
- onTopChanged = burnIn.onSmartspaceTopChanged,
- )
- }
- with(clockSection) { LargeClock(modifier = Modifier.fillMaxSize()) }
- }
+ @Composable
+ private fun SceneScope.LargeClockWithSmartSpace(shouldOffSetClockToOneHalf: Boolean = false) {
+ val burnIn = rememberBurnIn(clockInteractor)
+ val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsState()
+
+ LaunchedEffect(isLargeClockVisible) {
+ if (isLargeClockVisible) {
+ burnIn.onSmallClockTopChanged(null)
+ }
+ }
+
+ Column {
+ with(smartSpaceSection) {
+ SmartSpace(
+ burnInParams = burnIn.parameters,
+ onTopChanged = burnIn.onSmartspaceTopChanged,
+ )
+ }
+ with(clockSection) {
+ LargeClock(
+ modifier =
+ Modifier.fillMaxSize().thenIf(shouldOffSetClockToOneHalf) {
+ // If we do not have a custom position animation, we want
+ // the clock to be on one half of the screen.
+ Modifier.offset {
+ IntOffset(
+ x = -clockSection.getClockCenteringDistance().toInt(),
+ y = 0,
+ )
+ }
+ }
+ )
}
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
index 324534fb766c..7986051de3e0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
@@ -105,7 +105,7 @@ public class UdfpsKeyguardViewLegacyControllerBaseTest extends SysuiTestCase {
when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(false);
when(mView.getUnpausedAlpha()).thenReturn(255);
when(mShadeExpansionStateManager.addExpansionListener(any())).thenReturn(
- new ShadeExpansionChangeEvent(0, false, false, 0));
+ new ShadeExpansionChangeEvent(0, false, false));
mController = createUdfpsKeyguardViewController();
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index 43266bfcbc55..a944afb70f38 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -88,7 +88,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
testScope.runTest {
val scene by collectLastValue(communalInteractor.desiredScene)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
fakeKeyguardTransitionRepository.sendTransitionSteps(
@@ -158,7 +158,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
val scene by collectLastValue(communalInteractor.desiredScene)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
fakeKeyguardTransitionRepository.sendTransitionSteps(
@@ -179,7 +179,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
val scene by collectLastValue(communalInteractor.desiredScene)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
fakeKeyguardTransitionRepository.sendTransitionSteps(
@@ -207,7 +207,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
fun dockingOnLockscreen_forcesCommunal() =
with(kosmos) {
testScope.runTest {
- communalInteractor.onSceneChanged(CommunalScenes.Blank)
+ communalInteractor.changeScene(CommunalScenes.Blank)
val scene by collectLastValue(communalInteractor.desiredScene)
// device is docked while on the lockscreen
@@ -229,7 +229,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
fun dockingOnLockscreen_doesNotForceCommunalIfDreamStarts() =
with(kosmos) {
testScope.runTest {
- communalInteractor.onSceneChanged(CommunalScenes.Blank)
+ communalInteractor.changeScene(CommunalScenes.Blank)
val scene by collectLastValue(communalInteractor.desiredScene)
// device is docked while on the lockscreen
@@ -261,7 +261,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
testScope.runTest {
// Device is dreaming and on communal.
fakeKeyguardRepository.setDreaming(true)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -278,7 +278,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
testScope.runTest {
// Device is not dreaming and on communal.
fakeKeyguardRepository.setDreaming(false)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
// Scene stays as Communal
advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
@@ -293,7 +293,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
testScope.runTest {
// Device is dreaming and on communal.
fakeKeyguardRepository.setDreaming(true)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -316,7 +316,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
testScope.runTest {
// Device is on communal, but not dreaming.
fakeKeyguardRepository.setDreaming(false)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -338,7 +338,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
testScope.runTest {
// Device is dreaming and on communal.
fakeKeyguardRepository.setDreaming(true)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -367,7 +367,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
// Device is dreaming and on communal.
fakeKeyguardRepository.setDreaming(true)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
index 43acf3197fb1..2d78a9b9d808 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
@@ -22,36 +22,26 @@ import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
-import com.android.systemui.scene.data.repository.sceneContainerRepository
-import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
+import com.android.systemui.scene.shared.model.sceneDataSource
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class CommunalRepositoryImplTest : SysuiTestCase() {
- private lateinit var underTest: CommunalRepositoryImpl
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
- private val sceneContainerRepository = kosmos.sceneContainerRepository
-
- @Before
- fun setUp() {
- underTest = createRepositoryImpl(false)
- }
-
- private fun createRepositoryImpl(sceneContainerEnabled: Boolean): CommunalRepositoryImpl {
- return CommunalRepositoryImpl(
- testScope.backgroundScope,
- kosmos.fakeSceneContainerFlags.apply { enabled = sceneContainerEnabled },
- sceneContainerRepository,
+ private val underTest by lazy {
+ CommunalRepositoryImpl(
+ kosmos.applicationCoroutineScope,
+ kosmos.sceneDataSource,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 8e9d7690f215..e7ccde26e161 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -482,7 +482,7 @@ class CommunalInteractorTest : SysuiTestCase() {
assertThat(desiredScene()).isEqualTo(CommunalScenes.Blank)
val targetScene = CommunalScenes.Communal
- communalRepository.setDesiredScene(targetScene)
+ communalRepository.changeScene(targetScene)
desiredScene = collectLastValue(underTest.desiredScene)
runCurrent()
assertThat(desiredScene()).isEqualTo(targetScene)
@@ -493,9 +493,9 @@ class CommunalInteractorTest : SysuiTestCase() {
testScope.runTest {
val targetScene = CommunalScenes.Communal
- underTest.onSceneChanged(targetScene)
+ underTest.changeScene(targetScene)
- val desiredScene = collectLastValue(communalRepository.desiredScene)
+ val desiredScene = collectLastValue(communalRepository.currentScene)
runCurrent()
assertThat(desiredScene()).isEqualTo(targetScene)
}
@@ -508,7 +508,7 @@ class CommunalInteractorTest : SysuiTestCase() {
val desiredScene by collectLastValue(underTest.desiredScene)
- underTest.onSceneChanged(CommunalScenes.Communal)
+ underTest.changeScene(CommunalScenes.Communal)
assertThat(desiredScene).isEqualTo(CommunalScenes.Communal)
kosmos.setCommunalAvailable(false)
@@ -659,7 +659,7 @@ class CommunalInteractorTest : SysuiTestCase() {
runCurrent()
assertThat(isCommunalShowing()).isEqualTo(false)
- underTest.onSceneChanged(CommunalScenes.Communal)
+ underTest.changeScene(CommunalScenes.Communal)
isCommunalShowing = collectLastValue(underTest.isCommunalShowing)
runCurrent()
@@ -683,12 +683,12 @@ class CommunalInteractorTest : SysuiTestCase() {
assertThat(isCommunalShowing).isFalse()
// Verify scene changes (without the flag) to communal sets the value to true
- underTest.onSceneChanged(CommunalScenes.Communal)
+ underTest.changeScene(CommunalScenes.Communal)
runCurrent()
assertThat(isCommunalShowing).isTrue()
// Verify scene changes (without the flag) to blank sets the value back to false
- underTest.onSceneChanged(CommunalScenes.Blank)
+ underTest.changeScene(CommunalScenes.Blank)
runCurrent()
assertThat(isCommunalShowing).isFalse()
}
@@ -704,7 +704,7 @@ class CommunalInteractorTest : SysuiTestCase() {
assertThat(isCommunalShowing).isFalse()
// Verify scene changes without the flag doesn't have any impact
- underTest.onSceneChanged(CommunalScenes.Communal)
+ underTest.changeScene(CommunalScenes.Communal)
runCurrent()
assertThat(isCommunalShowing).isFalse()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
index 50b8da62b3f0..3a23e14e2777 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
@@ -158,7 +158,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
kosmos.setCommunalAvailable(true)
communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
- communalInteractor.onSceneChanged(CommunalScenes.Blank)
+ communalInteractor.changeScene(CommunalScenes.Blank)
assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_NOT_STARTED)
}
@@ -171,7 +171,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
goToCommunal()
communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)
- communalInteractor.onSceneChanged(CommunalScenes.Blank)
+ communalInteractor.changeScene(CommunalScenes.Blank)
assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
}
@@ -184,13 +184,13 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
goToCommunal()
communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
- communalInteractor.onSceneChanged(CommunalScenes.Blank)
+ communalInteractor.changeScene(CommunalScenes.Blank)
assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
}
private suspend fun goToCommunal() {
kosmos.setCommunalAvailable(true)
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 5827671e22b8..6a86801cba90 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -376,7 +376,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
// Ensure correct expansion passed in.
ShadeExpansionChangeEvent event =
new ShadeExpansionChangeEvent(
- expansion, /* expanded= */ false, /* tracking= */ true, dragDownAmount);
+ expansion, /* expanded= */ false, /* tracking= */ true);
verify(mScrimController).expand(event);
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
index 97052a84a60f..7cdd4781631f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
@@ -59,7 +59,7 @@ public class BouncerlessScrimControllerTest extends SysuiTestCase {
final BouncerlessScrimController scrimController =
new BouncerlessScrimController(mExecutor, mPowerManager);
scrimController.addCallback(mCallback);
- scrimController.expand(new ShadeExpansionChangeEvent(.5f, true, false, 0.0f));
+ scrimController.expand(new ShadeExpansionChangeEvent(.5f, true, false));
mExecutor.runAllReady();
verify(mPowerManager).wakeUp(anyLong(), eq(PowerManager.WAKE_REASON_GESTURE), any());
verify(mCallback).onWakeup();
@@ -71,7 +71,7 @@ public class BouncerlessScrimControllerTest extends SysuiTestCase {
new BouncerlessScrimController(mExecutor, mPowerManager);
scrimController.addCallback(mCallback);
final ShadeExpansionChangeEvent expansionEvent =
- new ShadeExpansionChangeEvent(0.5f, false, false, 0.0f);
+ new ShadeExpansionChangeEvent(0.5f, false, false);
scrimController.expand(expansionEvent);
mExecutor.runAllReady();
verify(mCallback).onExpansion(eq(expansionEvent));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
index ad2ae8b41af9..e6b30176d3ee 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
@@ -20,6 +20,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -149,6 +150,38 @@ class BouncerToGoneFlowsTest : SysuiTestCase() {
}
@Test
+ fun showAllNotifications_isTrue_whenLeaveShadeOpen() =
+ testScope.runTest {
+ val showAllNotifications by
+ collectLastValue(underTest.showAllNotifications(500.milliseconds, PRIMARY_BOUNCER))
+
+ sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true)
+
+ keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ keyguardTransitionRepository.sendTransitionStep(step(0.1f))
+
+ assertThat(showAllNotifications).isTrue()
+ keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(showAllNotifications).isFalse()
+ }
+
+ @Test
+ fun showAllNotifications_isFalse_whenLeaveShadeIsNotOpen() =
+ testScope.runTest {
+ val showAllNotifications by
+ collectLastValue(underTest.showAllNotifications(500.milliseconds, PRIMARY_BOUNCER))
+
+ sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(false)
+
+ keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ keyguardTransitionRepository.sendTransitionStep(step(0.1f))
+
+ assertThat(showAllNotifications).isFalse()
+ keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+ assertThat(showAllNotifications).isFalse()
+ }
+
+ @Test
fun scrimBehindAlpha_doNotLeaveShadeOpen() =
testScope.runTest {
val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
index 751ac1d8b458..e9a825721f5f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
@@ -21,6 +21,7 @@ import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardClockSwitch
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.authController
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
@@ -96,7 +97,7 @@ class LockscreenContentViewModelTest : SysuiTestCase() {
shadeRepository.setShadeMode(ShadeMode.Split)
kosmos.fakeKeyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE)
- assertThat(underTest.areNotificationsVisible).isTrue()
+ assertThat(collectLastValue(underTest.areNotificationsVisible).invoke()).isTrue()
}
}
@Test
@@ -104,7 +105,7 @@ class LockscreenContentViewModelTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
kosmos.fakeKeyguardClockRepository.setClockSize(KeyguardClockSwitch.SMALL)
- assertThat(underTest.areNotificationsVisible).isTrue()
+ assertThat(collectLastValue(underTest.areNotificationsVisible).invoke()).isTrue()
}
}
@@ -113,7 +114,7 @@ class LockscreenContentViewModelTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
kosmos.fakeKeyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE)
- assertThat(underTest.areNotificationsVisible).isFalse()
+ assertThat(collectLastValue(underTest.areNotificationsVisible).invoke()).isFalse()
}
}
@@ -122,7 +123,8 @@ class LockscreenContentViewModelTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
shadeRepository.setShadeMode(ShadeMode.Split)
- assertThat(underTest.shouldUseSplitNotificationShade).isTrue()
+ assertThat(collectLastValue(underTest.shouldUseSplitNotificationShade).invoke())
+ .isTrue()
}
}
@@ -131,16 +133,8 @@ class LockscreenContentViewModelTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
shadeRepository.setShadeMode(ShadeMode.Single)
- assertThat(underTest.shouldUseSplitNotificationShade).isFalse()
- }
- }
-
- @Test
- fun sceneKey() =
- with(kosmos) {
- testScope.runTest {
- shadeRepository.setShadeMode(ShadeMode.Single)
- assertThat(underTest.shouldUseSplitNotificationShade).isFalse()
+ assertThat(collectLastValue(underTest.shouldUseSplitNotificationShade).invoke())
+ .isFalse()
}
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
index 16b68ccf097b..ad40f8eab4f6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
@@ -52,6 +52,7 @@ class PanelExpansionInteractorImplTest : SysuiTestCase() {
private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
private val sceneInteractor = kosmos.sceneInteractor
+ private val shadeAnimationInteractor = kosmos.shadeAnimationInteractor
private val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(Scenes.Lockscreen)
@@ -112,6 +113,40 @@ class PanelExpansionInteractorImplTest : SysuiTestCase() {
changeScene(Scenes.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
assertThat(panelExpansion).isEqualTo(1f)
}
+
+ @Test
+ @EnableSceneContainer
+ fun shouldHideStatusBarIconsWhenExpanded_goneScene() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ shadeAnimationInteractor.setIsLaunchingActivity(false)
+ changeScene(Scenes.Gone)
+
+ assertThat(underTest.shouldHideStatusBarIconsWhenExpanded()).isFalse()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun shouldHideStatusBarIconsWhenExpanded_lockscreenScene() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ shadeAnimationInteractor.setIsLaunchingActivity(false)
+ changeScene(Scenes.Lockscreen)
+
+ assertThat(underTest.shouldHideStatusBarIconsWhenExpanded()).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun shouldHideStatusBarIconsWhenExpanded_activityLaunch() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ changeScene(Scenes.Gone)
+ shadeAnimationInteractor.setIsLaunchingActivity(true)
+
+ assertThat(underTest.shouldHideStatusBarIconsWhenExpanded()).isFalse()
+ }
+
private fun TestScope.setUnlocked(isUnlocked: Boolean) {
val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
deviceEntryRepository.setUnlocked(isUnlocked)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt
index 31dacdd61151..52caa787bb2f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt
@@ -18,15 +18,32 @@ package com.android.systemui.shade.domain.startable
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.shade.ShadeExpansionChangeEvent
+import com.android.systemui.shade.ShadeExpansionListener
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.testKosmos
+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.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -34,11 +51,15 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class ShadeStartableTest : SysuiTestCase() {
-
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val shadeInteractor = kosmos.shadeInteractor
+ private val sceneInteractor = kosmos.sceneInteractor
+ private val shadeExpansionStateManager = kosmos.shadeExpansionStateManager
+ private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
+ private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
private val fakeConfigurationRepository = kosmos.fakeConfigurationRepository
+ private val fakeSceneDataSource = kosmos.fakeSceneDataSource
private val underTest = kosmos.shadeStartable
@@ -59,4 +80,89 @@ class ShadeStartableTest : SysuiTestCase() {
fakeConfigurationRepository.onAnyConfigurationChange()
assertThat(shadeMode).isEqualTo(ShadeMode.Single)
}
+
+ @Test
+ @EnableSceneContainer
+ fun hydrateShadeExpansionStateManager() =
+ testScope.runTest {
+ val expansionListener = mock<ShadeExpansionListener>()
+ var latestChangeEvent: ShadeExpansionChangeEvent? = null
+ whenever(expansionListener.onPanelExpansionChanged(any())).thenAnswer {
+ latestChangeEvent = it.arguments[0] as ShadeExpansionChangeEvent
+ Unit
+ }
+ shadeExpansionStateManager.addExpansionListener(expansionListener)
+
+ underTest.start()
+
+ setUnlocked(true)
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(Scenes.Gone)
+ )
+ sceneInteractor.setTransitionState(transitionState)
+
+ changeScene(Scenes.Gone, transitionState)
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+
+ assertThat(latestChangeEvent)
+ .isEqualTo(
+ ShadeExpansionChangeEvent(
+ fraction = 0f,
+ expanded = false,
+ tracking = false,
+ )
+ )
+
+ changeScene(Scenes.Shade, transitionState) { progress ->
+ assertThat(latestChangeEvent?.fraction).isEqualTo(progress)
+ }
+ }
+
+ private fun TestScope.setUnlocked(isUnlocked: Boolean) {
+ val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
+ deviceEntryRepository.setUnlocked(isUnlocked)
+ runCurrent()
+
+ assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
+ }
+
+ private fun TestScope.changeScene(
+ toScene: SceneKey,
+ transitionState: MutableStateFlow<ObservableTransitionState>,
+ assertDuringProgress: ((progress: Float) -> Unit) = {},
+ ) {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val progressFlow = MutableStateFlow(0f)
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = checkNotNull(currentScene),
+ toScene = toScene,
+ progress = progressFlow,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ )
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 0.2f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 0.6f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 1f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ transitionState.value = ObservableTransitionState.Idle(toScene)
+ fakeSceneDataSource.changeScene(toScene)
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ assertThat(currentScene).isEqualTo(toScene)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
index 5358a6dbb476..fa79e7fc9026 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
@@ -201,11 +201,38 @@ class AudioVolumeInteractorTest : SysuiTestCase() {
}
@Test
- fun alarmStream_isNotMutable() {
+ fun streamNotAffectedByMute_isNotMutable() {
with(kosmos) {
- val isMutable = underTest.isMutable(AudioStream(AudioManager.STREAM_ALARM))
+ testScope.runTest {
+ audioRepository.setIsAffectedByMute(audioStream, false)
+ val isMutable = underTest.isAffectedByMute(audioStream)
+
+ assertThat(isMutable).isFalse()
+ }
+ }
+ }
+
+ @Test
+ fun muteRingerStream_ringerMode_vibrate() {
+ with(kosmos) {
+ testScope.runTest {
+ val ringerMode by collectLastValue(audioRepository.ringerMode)
+ underTest.setMuted(AudioStream(AudioManager.STREAM_RING), true)
- assertThat(isMutable).isFalse()
+ assertThat(ringerMode).isEqualTo(RingerMode(AudioManager.RINGER_MODE_VIBRATE))
+ }
+ }
+ }
+
+ @Test
+ fun unMuteRingerStream_ringerMode_normal() {
+ with(kosmos) {
+ testScope.runTest {
+ val ringerMode by collectLastValue(audioRepository.ringerMode)
+ underTest.setMuted(AudioStream(AudioManager.STREAM_RING), false)
+
+ assertThat(ringerMode).isEqualTo(RingerMode(AudioManager.RINGER_MODE_NORMAL))
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
index 8e925573d40a..2cc1ad335535 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
@@ -84,8 +84,17 @@ class BottomBarViewModelTest : SysuiTestCase() {
runCurrent()
- verify(activityStarter).startActivity(capture(intentCaptor), eq(true),
- capture(activityStartedCaptor))
+ verify(activityStarter)
+ .startActivityDismissingKeyguard(
+ /* intent = */ capture(intentCaptor),
+ /* onlyProvisioned = */ eq(false),
+ /* dismissShade = */ eq(true),
+ /* disallowEnterPictureInPictureWhileLaunching = */ eq(false),
+ /* callback = */ capture(activityStartedCaptor),
+ /* flags = */ eq(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
+ /* animationController = */ eq(null),
+ /* userHandle = */ eq(null),
+ )
assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_SOUND_SETTINGS)
activityStartedCaptor.value.onActivityStarted(ActivityManager.START_SUCCESS)
diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml
index ef1a21f2fdf6..c988b4afcf74 100644
--- a/packages/SystemUI/res/layout/screenshot_shelf.xml
+++ b/packages/SystemUI/res/layout/screenshot_shelf.xml
@@ -28,7 +28,7 @@
android:elevation="4dp"
android:background="@drawable/action_chip_container_background"
android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
- android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom"
+ android:layout_marginBottom="@dimen/screenshot_shelf_vertical_margin"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/actions_container"
app:layout_constraintEnd_toEndOf="@+id/actions_container"
@@ -38,14 +38,14 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
- android:paddingEnd="@dimen/overlay_action_container_padding_end"
+ android:paddingHorizontal="@dimen/overlay_action_container_padding_end"
android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
android:elevation="4dp"
android:scrollbars="none"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintWidth_percent="1.0"
app:layout_constraintWidth_max="wrap"
- app:layout_constraintStart_toEndOf="@+id/screenshot_preview_border"
+ app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="@id/actions_container_background">
<LinearLayout
@@ -65,16 +65,16 @@
android:id="@+id/screenshot_preview_border"
android:layout_width="0dp"
android:layout_height="0dp"
- android:layout_marginStart="16dp"
+ android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
android:layout_marginTop="@dimen/overlay_border_width_neg"
android:layout_marginEnd="@dimen/overlay_border_width_neg"
- android:layout_marginBottom="14dp"
+ android:layout_marginBottom="@dimen/screenshot_shelf_vertical_margin"
android:elevation="8dp"
android:background="@drawable/overlay_border"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/screenshot_preview"
app:layout_constraintEnd_toEndOf="@id/screenshot_preview"
- app:layout_constraintBottom_toBottomOf="parent"/>
+ app:layout_constraintBottom_toTopOf="@id/actions_container"/>
<ImageView
android:id="@+id/screenshot_preview"
android:layout_width="@dimen/overlay_x_scale"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 29f4942e8b4a..d2efccd546b6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -448,6 +448,7 @@
<dimen name="overlay_action_container_padding_end">8dp</dimen>
<dimen name="overlay_dismiss_button_tappable_size">48dp</dimen>
<dimen name="overlay_dismiss_button_margin">8dp</dimen>
+ <dimen name="screenshot_shelf_vertical_margin">8dp</dimen>
<!-- must be kept aligned with overlay_border_width_neg, below;
overlay_border_width = overlay_border_width_neg * -1 -->
<dimen name="overlay_border_width">4dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 8f1a5f79687c..985f6c8bc59f 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -454,6 +454,7 @@ public class LockIconViewController implements Dumpable {
final float scaleFactor = mAuthController.getScaleFactor();
final int scaledPadding = (int) (mDefaultPaddingPx * scaleFactor);
if (KeyguardBottomAreaRefactor.isEnabled() || MigrateClocksToBlueprint.isEnabled()) {
+ // positioning in this case is handled by [DefaultDeviceEntrySection]
mView.getLockIcon().setPadding(scaledPadding, scaledPadding, scaledPadding,
scaledPadding);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index b26be0c74ece..0cc3be2abf2c 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -99,9 +99,10 @@ public class SystemUIService extends Service {
if (Build.IS_DEBUGGABLE) {
// b/71353150 - looking for leaked binder proxies
BinderInternal.nSetBinderProxyCountEnabled(true);
- BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
+ BinderInternal.nSetBinderProxyCountWatermarks(
+ /* high= */ 1000, /* low= */ 900, /* warning= */ 950);
BinderInternal.setBinderProxyCountCallback(
- new BinderInternal.BinderProxyLimitListener() {
+ new BinderInternal.BinderProxyCountEventListener() {
@Override
public void onLimitReached(int uid) {
Slog.w(SystemUIApplication.TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index 1f5a0bf328af..be75e1035ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -36,7 +36,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.expresslog.Counter;
import com.android.systemui.Flags;
import com.android.systemui.util.settings.SecureSettings;
@@ -418,18 +417,11 @@ class MenuView extends FrameLayout implements
onPositionChanged();
}
- void incrementTexMetricForAllTargets(String metric) {
+ void incrementTexMetric(String metric) {
if (!Flags.floatingMenuDragToEdit()) {
return;
}
- for (AccessibilityTarget target : mTargetFeatures) {
- incrementTexMetric(metric, target.getUid());
- }
- }
-
- @VisibleForTesting
- void incrementTexMetric(String metric, int uid) {
- Counter.logIncrementWithUid(metric, uid);
+ Counter.logIncrement(metric);
}
private InstantInsetLayerDrawable getContainerViewInsetLayer() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 85bf784d623b..86279befc2ba 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -105,14 +105,14 @@ class MenuViewLayer extends FrameLayout implements
*
* <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg.
*/
- static final String TEX_METRIC_DISMISS = "accessibility.value_fab_shortcut_action_dismiss";
+ static final String TEX_METRIC_DISMISS = "accessibility.value_fab_shortcut_dismiss";
/**
* Counter indicating the FAB was dragged to the Edit action button.
*
* <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg.
*/
- static final String TEX_METRIC_EDIT = "accessibility.value_fab_shortcut_action_edit";
+ static final String TEX_METRIC_EDIT = "accessibility.value_fab_shortcut_edit";
private final WindowManager mWindowManager;
private final MenuView mMenuView;
@@ -492,11 +492,11 @@ class MenuViewLayer extends FrameLayout implements
} else {
hideMenuAndShowMessage();
}
- mMenuView.incrementTexMetricForAllTargets(TEX_METRIC_DISMISS);
+ mMenuView.incrementTexMetric(TEX_METRIC_DISMISS);
} else if (id == R.id.action_edit
&& Flags.floatingMenuDragToEdit()) {
gotoEditScreen();
- mMenuView.incrementTexMetricForAllTargets(TEX_METRIC_EDIT);
+ mMenuView.incrementTexMetric(TEX_METRIC_EDIT);
}
mDismissView.hide();
mDragToInteractView.hide();
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index ef686f91b36a..4d328d6cb13f 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -72,7 +72,7 @@ constructor(
.filterNotNull()
// TODO(b/322787129): Also set a custom transition animation here to avoid the regular
// slide-in animation when setting the scene programmatically
- .onEach { nextScene -> communalInteractor.onSceneChanged(nextScene) }
+ .onEach { nextScene -> communalInteractor.changeScene(nextScene) }
.launchIn(applicationScope)
// TODO(b/322787129): re-enable once custom animations are in place
@@ -129,7 +129,7 @@ constructor(
.sample(keyguardInteractor.isDreaming, ::Pair)
.collect { (shouldTimeout, isDreaming) ->
if (isDreaming && shouldTimeout) {
- communalInteractor.onSceneChanged(CommunalScenes.Blank)
+ communalInteractor.changeScene(CommunalScenes.Blank)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/Communal.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/Communal.kt
new file mode 100644
index 000000000000..5e41a1b8a9b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/Communal.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.dagger
+
+import javax.inject.Qualifier
+
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Communal
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
index 82d943796e2a..72dcb26b089a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
@@ -23,11 +23,19 @@ import com.android.systemui.communal.data.repository.CommunalRepositoryModule
import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryModule
import com.android.systemui.communal.data.repository.CommunalTutorialRepositoryModule
import com.android.systemui.communal.data.repository.CommunalWidgetRepositoryModule
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.widgets.CommunalWidgetModule
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.communal.widgets.EditWidgetsActivityStarterImpl
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.scene.shared.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneDataSource
+import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
import dagger.Binds
import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.CoroutineScope
@Module(
includes =
@@ -47,4 +55,24 @@ interface CommunalModule {
fun bindEditWidgetsActivityStarter(
starter: EditWidgetsActivityStarterImpl
): EditWidgetsActivityStarter
+
+ @Binds
+ @Communal
+ fun bindCommunalSceneDataSource(@Communal delegator: SceneDataSourceDelegator): SceneDataSource
+
+ companion object {
+ @Provides
+ @Communal
+ @SysUISingleton
+ fun providesCommunalSceneDataSourceDelegator(
+ @Application applicationScope: CoroutineScope
+ ): SceneDataSourceDelegator {
+ val config =
+ SceneContainerConfig(
+ sceneKeys = listOf(CommunalScenes.Blank, CommunalScenes.Communal),
+ initialSceneKey = CommunalScenes.Blank
+ )
+ return SceneDataSourceDelegator(applicationScope, config)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
index 201ce832cc41..8bfd8d91dfca 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
@@ -18,11 +18,12 @@ package com.android.systemui.communal.data.repository
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
+import com.android.systemui.communal.dagger.Communal
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.scene.data.repository.SceneContainerRepository
-import com.android.systemui.scene.shared.flag.SceneContainerFlags
+import com.android.systemui.scene.shared.model.SceneDataSource
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -30,7 +31,6 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
@@ -38,16 +38,15 @@ import kotlinx.coroutines.flow.stateIn
/** Encapsulates the state of communal mode. */
interface CommunalRepository {
/**
- * Target scene as requested by the underlying [SceneTransitionLayout] or through
- * [setDesiredScene].
+ * Target scene as requested by the underlying [SceneTransitionLayout] or through [changeScene].
*/
- val desiredScene: StateFlow<SceneKey>
+ val currentScene: StateFlow<SceneKey>
/** Exposes the transition state of the communal [SceneTransitionLayout]. */
val transitionState: StateFlow<ObservableTransitionState>
/** Updates the requested scene. */
- fun setDesiredScene(desiredScene: SceneKey)
+ fun changeScene(toScene: SceneKey, transitionKey: TransitionKey? = null)
/**
* Updates the transition state of the hub [SceneTransitionLayout].
@@ -63,12 +62,10 @@ class CommunalRepositoryImpl
@Inject
constructor(
@Background backgroundScope: CoroutineScope,
- sceneContainerFlags: SceneContainerFlags,
- sceneContainerRepository: SceneContainerRepository,
+ @Communal private val sceneDataSource: SceneDataSource,
) : CommunalRepository {
- private val _desiredScene: MutableStateFlow<SceneKey> = MutableStateFlow(CommunalScenes.Default)
- override val desiredScene: StateFlow<SceneKey> = _desiredScene.asStateFlow()
+ override val currentScene: StateFlow<SceneKey> = sceneDataSource.currentScene
private val defaultTransitionState = ObservableTransitionState.Idle(CommunalScenes.Default)
private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
@@ -81,8 +78,8 @@ constructor(
initialValue = defaultTransitionState,
)
- override fun setDesiredScene(desiredScene: SceneKey) {
- _desiredScene.value = desiredScene
+ override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) {
+ sceneDataSource.changeScene(toScene, transitionKey)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index ada984db9a39..246d5d92f8b0 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -25,6 +25,7 @@ import android.os.UserManager
import android.provider.Settings
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.communal.data.repository.CommunalMediaRepository
import com.android.systemui.communal.data.repository.CommunalPrefsRepository
@@ -80,6 +81,7 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
/** Encapsulates business-logic related to communal mode. */
@OptIn(ExperimentalCoroutinesApi::class)
@@ -142,13 +144,12 @@ constructor(
)
/**
- * Target scene as requested by the underlying [SceneTransitionLayout] or through
- * [onSceneChanged].
+ * Target scene as requested by the underlying [SceneTransitionLayout] or through [changeScene].
*
* If [isCommunalAvailable] is false, will return [CommunalScenes.Blank]
*/
val desiredScene: Flow<SceneKey> =
- communalRepository.desiredScene.combine(isCommunalAvailable) { scene, available ->
+ communalRepository.currentScene.combine(isCommunalAvailable) { scene, available ->
if (available) scene else CommunalScenes.Blank
}
@@ -239,10 +240,14 @@ constructor(
* This will not be true while transitioning to the hub and will turn false immediately when a
* swipe to exit the hub starts.
*/
- val isIdleOnCommunal: Flow<Boolean> =
- communalRepository.transitionState.map {
- it is ObservableTransitionState.Idle && it.scene == CommunalScenes.Communal
- }
+ val isIdleOnCommunal: StateFlow<Boolean> =
+ communalRepository.transitionState
+ .map { it is ObservableTransitionState.Idle && it.scene == CommunalScenes.Communal }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = false,
+ )
/**
* Flow that emits a boolean if any portion of the communal UI is visible at all.
@@ -254,9 +259,12 @@ constructor(
!(it is ObservableTransitionState.Idle && it.scene == CommunalScenes.Blank)
}
- /** Callback received whenever the [SceneTransitionLayout] finishes a scene transition. */
- fun onSceneChanged(newScene: SceneKey) {
- communalRepository.setDesiredScene(newScene)
+ /**
+ * Asks for an asynchronous scene witch to [newScene], which will use the corresponding
+ * installed transition or the one specified by [transitionKey], if provided.
+ */
+ fun changeScene(newScene: SceneKey, transitionKey: TransitionKey? = null) {
+ communalRepository.changeScene(newScene, transitionKey)
}
fun setEditModeOpen(isOpen: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 531f19874b2a..095222a4b47a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -49,8 +49,8 @@ abstract class BaseCommunalViewModel(
communalInteractor.signalUserInteraction()
}
- fun onSceneChanged(scene: SceneKey) {
- communalInteractor.onSceneChanged(scene)
+ fun changeScene(scene: SceneKey) {
+ communalInteractor.changeScene(scene)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index 902133ddce1d..5f4b394a05b9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -31,7 +31,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.lifecycle.lifecycleScope
-import com.android.app.tracing.coroutines.launch
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.compose.theme.PlatformTheme
import com.android.internal.logging.UiEventLogger
@@ -150,7 +149,7 @@ constructor(
private fun onEditDone() {
try {
- communalViewModel.onSceneChanged(CommunalScenes.Communal)
+ communalViewModel.changeScene(CommunalScenes.Communal)
checkNotNull(windowManagerService).lockNow(/* options */ null)
finish()
} catch (e: RemoteException) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 19af371d1dfa..1ed4b503b43d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -49,6 +49,7 @@ import com.android.systemui.common.data.CommonDataLayerModule;
import com.android.systemui.communal.dagger.CommunalModule;
import com.android.systemui.complication.dagger.ComplicationComponent;
import com.android.systemui.controls.dagger.ControlsModule;
+import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.SystemUser;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -89,6 +90,7 @@ import com.android.systemui.qs.footer.dagger.FooterActionsModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.recordissue.RecordIssueModule;
import com.android.systemui.retail.dagger.RetailModeModule;
+import com.android.systemui.scene.shared.model.SceneContainerConfig;
import com.android.systemui.scene.shared.model.SceneDataSource;
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator;
import com.android.systemui.scene.ui.view.WindowRootViewComponent;
@@ -165,6 +167,8 @@ import java.util.concurrent.Executor;
import javax.inject.Named;
+import kotlinx.coroutines.CoroutineScope;
+
/**
* A dagger module for injecting components of System UI that are required by System UI.
*
@@ -402,6 +406,13 @@ public abstract class SystemUIModule {
@ClassKey(SystemUISecondaryUserService.class)
abstract Service bindsSystemUISecondaryUserService(SystemUISecondaryUserService service);
+ @Provides
+ @SysUISingleton
+ static SceneDataSourceDelegator providesSceneDataSourceDelegator(
+ @Application CoroutineScope applicationScope, SceneContainerConfig config) {
+ return new SceneDataSourceDelegator(applicationScope, config);
+ }
+
@Binds
abstract SceneDataSource bindSceneDataSource(SceneDataSourceDelegator delegator);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index 7f3b5eba96c6..926f7f1aee48 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -172,19 +172,18 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
final float screenTravelPercentage = Math.abs(e1.getY() - e2.getY())
/ mTouchSession.getBounds().height();
setPanelExpansion(mBouncerInitiallyShowing
- ? screenTravelPercentage : 1 - screenTravelPercentage, dragDownAmount);
+ ? screenTravelPercentage : 1 - screenTravelPercentage);
return true;
}
};
- private void setPanelExpansion(float expansion, float dragDownAmount) {
+ private void setPanelExpansion(float expansion) {
mCurrentExpansion = expansion;
ShadeExpansionChangeEvent event =
new ShadeExpansionChangeEvent(
/* fraction= */ mCurrentExpansion,
/* expanded= */ mExpanded,
- /* tracking= */ true,
- /* dragDownPxAmount= */ dragDownAmount);
+ /* tracking= */ true);
mCurrentScrimController.expand(event);
}
@@ -333,7 +332,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
animation -> {
float expansionFraction = (float) animation.getAnimatedValue();
float dragDownAmount = expansionFraction * expansionHeight;
- setPanelExpansion(expansionFraction, dragDownAmount);
+ setPanelExpansion(expansionFraction);
});
if (!mBouncerInitiallyShowing
&& targetExpansion == KeyguardBouncerConstants.EXPANSION_VISIBLE) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt
index 1b832d4ab98d..037c23b579c3 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt
@@ -57,7 +57,7 @@ constructor(
!keyguardUpdateMonitor.isEncryptedOrLockdown(userTracker.userId)
if (showGlanceableHub) {
toGlanceableHubTransitionViewModel.startTransition()
- communalInteractor.onSceneChanged(CommunalScenes.Communal)
+ communalInteractor.changeScene(CommunalScenes.Communal)
} else {
toLockscreenTransitionViewModel.startTransition()
}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
index 17059097e053..f4998a7b8789 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
@@ -18,10 +18,10 @@ package com.android.systemui.haptics.qs
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launch
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.qs.tileimpl.QSTileViewImpl
import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.launch
class QSLongPressEffectViewBinder {
@@ -31,16 +31,18 @@ class QSLongPressEffectViewBinder {
fun bind(
tile: QSTileViewImpl,
+ tileSpec: String?,
effect: QSLongPressEffect?,
) {
if (effect == null) return
handle =
tile.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
effect.scope = this
+ val tag = "${tileSpec ?: "unknownTileSpec"}#LongPressEffect"
- launch {
+ launch("$tag#progress") {
effect.effectProgress.collect { progress ->
progress?.let {
if (it == 0f) {
@@ -51,7 +53,7 @@ class QSLongPressEffectViewBinder {
}
}
- launch {
+ launch("$tag#action") {
effect.actionType.collect { action ->
action?.let {
when (it) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index fa845c7cf784..3da3e2f9cbcc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -29,6 +29,9 @@ import androidx.constraintlayout.widget.ConstraintSet.END
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.transitions
import com.android.internal.jank.InteractionJankMonitor
import com.android.keyguard.KeyguardStatusView
import com.android.keyguard.KeyguardStatusViewController
@@ -109,6 +112,7 @@ constructor(
private var rootViewHandle: DisposableHandle? = null
private var indicationAreaHandle: DisposableHandle? = null
+ private val sceneKey = SceneKey("root-view-scene-key")
var keyguardStatusViewController: KeyguardStatusViewController? = null
get() {
@@ -219,12 +223,25 @@ constructor(
blueprints.mapNotNull { it as? ComposableLockscreenSceneBlueprint }.toSet()
return ComposeView(context).apply {
setContent {
- LockscreenContent(
- viewModel = viewModel,
- blueprints = sceneBlueprints,
- clockInteractor = clockInteractor
- )
- .Content(modifier = Modifier.fillMaxSize())
+ // STL is used solely to provide a SceneScope to enable us to invoke SceneScope
+ // composables.
+ SceneTransitionLayout(
+ currentScene = sceneKey,
+ onChangeScene = {},
+ transitions = transitions {},
+ ) {
+ scene(sceneKey) {
+ with(
+ LockscreenContent(
+ viewModel = viewModel,
+ blueprints = sceneBlueprints,
+ clockInteractor = clockInteractor
+ )
+ ) {
+ Content(modifier = Modifier.fillMaxSize())
+ }
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 88eadd7be066..b3d9a7670c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -92,7 +92,8 @@ constructor(
walletController.setupWalletChangeObservers(
callback,
QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
- QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE,
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE
)
withContext(backgroundDispatcher) {
@@ -104,7 +105,8 @@ constructor(
awaitClose {
walletController.unregisterWalletChangeObservers(
QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
- QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE,
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
index fa6efa504623..f763e6223a81 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
@@ -17,14 +17,17 @@
package com.android.systemui.keyguard.domain.backup
+import android.app.backup.BackupDataInputStream
import android.app.backup.SharedPreferencesBackupHelper
import android.content.Context
+import android.util.Log
+import com.android.app.tracing.traceSection
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
import com.android.systemui.settings.UserFileManagerImpl
/** Handles backup & restore for keyguard quick affordances. */
class KeyguardQuickAffordanceBackupHelper(
- context: Context,
+ private val context: Context,
userId: Int,
) :
SharedPreferencesBackupHelper(
@@ -34,4 +37,17 @@ class KeyguardQuickAffordanceBackupHelper(
fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME,
)
.getPath()
- )
+ ) {
+
+ override fun restoreEntity(data: BackupDataInputStream?) {
+ Log.d(TAG, "Starting restore for ${data?.key} for user ${context.userId}")
+ traceSection("$TAG File restore: ${data?.key}") {
+ super.restoreEntity(data)
+ }
+ Log.d(TAG, "Finished restore for ${data?.key} for user ${context.userId}")
+ }
+
+ companion object {
+ private const val TAG = "KeyguardQuickAffordanceBackupHelper"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
index d9f12c34c4f1..5906cfdda57e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.ui.binder
import android.content.Context
+import android.util.DisplayMetrics
import android.view.View
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
@@ -109,7 +110,7 @@ object KeyguardPreviewClockViewBinder {
private fun applyClockDefaultConstraints(context: Context, constraints: ConstraintSet) {
constraints.apply {
constrainWidth(R.id.lockscreen_clock_view_large, ConstraintSet.WRAP_CONTENT)
- constrainHeight(R.id.lockscreen_clock_view_large, ConstraintSet.WRAP_CONTENT)
+ constrainHeight(R.id.lockscreen_clock_view_large, ConstraintSet.MATCH_CONSTRAINT)
val largeClockTopMargin =
context.resources.getDimensionPixelSize(R.dimen.status_bar_height) +
context.resources.getDimensionPixelSize(
@@ -129,7 +130,29 @@ object KeyguardPreviewClockViewBinder {
ConstraintSet.END
)
- connect(R.id.lockscreen_clock_view_large, BOTTOM, R.id.lock_icon_view, TOP)
+ // In preview, we'll show UDFPS icon for UDFPS devices
+ // and nothing for non-UDFPS devices,
+ // but we need position of device entry icon to constrain clock
+ if (getConstraint(R.id.lock_icon_view) != null) {
+ connect(R.id.lockscreen_clock_view_large, BOTTOM, R.id.lock_icon_view, TOP)
+ } else {
+ // Copied calculation codes from applyConstraints in DefaultDeviceEntrySection
+ val bottomPaddingPx =
+ context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
+ val defaultDensity =
+ DisplayMetrics.DENSITY_DEVICE_STABLE.toFloat() /
+ DisplayMetrics.DENSITY_DEFAULT.toFloat()
+ val lockIconRadiusPx = (defaultDensity * 36).toInt()
+ val clockBottomMargin = bottomPaddingPx + 2 * lockIconRadiusPx
+ connect(
+ R.id.lockscreen_clock_view_large,
+ BOTTOM,
+ PARENT_ID,
+ BOTTOM,
+ clockBottomMargin
+ )
+ }
+
constrainWidth(R.id.lockscreen_clock_view, WRAP_CONTENT)
constrainHeight(
R.id.lockscreen_clock_view,
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 4d9354dd1572..33052befadfc 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
@@ -82,7 +82,6 @@ import kotlinx.coroutines.launch
/** Bind occludingAppDeviceEntryMessageViewModel to run whenever the keyguard view is attached. */
@OptIn(ExperimentalCoroutinesApi::class)
object KeyguardRootViewBinder {
-
@SuppressLint("ClickableViewAccessibility")
@JvmStatic
fun bind(
@@ -102,14 +101,6 @@ object KeyguardRootViewBinder {
): DisposableHandle {
var onLayoutChangeListener: OnLayoutChange? = null
val childViews = mutableMapOf<Int, View>()
- val statusViewId = R.id.keyguard_status_view
- val burnInLayerId = R.id.burn_in_layer
- val aodNotificationIconContainerId = R.id.aod_notification_icon_container
- val largeClockId = R.id.lockscreen_clock_view_large
- val indicationArea = R.id.keyguard_indication_area
- val startButton = R.id.start_button
- val endButton = R.id.end_button
- val lockIcon = R.id.lock_icon_view
if (KeyguardBottomAreaRefactor.isEnabled) {
view.setOnTouchListener { _, event ->
@@ -214,7 +205,7 @@ object KeyguardRootViewBinder {
val px = state.value ?: return@collect
when {
state.isToOrFrom(KeyguardState.AOD) -> {
- childViews[largeClockId]?.translationX = px
+ // Large Clock is not translated in the x direction
childViews[burnInLayerId]?.translationX = px
childViews[aodNotificationIconContainerId]?.translationX =
px
@@ -436,7 +427,7 @@ object KeyguardRootViewBinder {
oldRight: Int,
oldBottom: Int
) {
- childViews[R.id.nssl_placeholder]?.let { notificationListPlaceholder ->
+ childViews[nsslPlaceholderId]?.let { notificationListPlaceholder ->
// After layout, ensure the notifications are positioned correctly
viewModel.onNotificationContainerBoundsChanged(
notificationListPlaceholder.top.toFloat(),
@@ -460,14 +451,14 @@ object KeyguardRootViewBinder {
)
}
} else {
- childViews[R.id.keyguard_status_view]?.top ?: 0
+ childViews[statusViewId]?.top ?: 0
}
)
}
}
private fun isUserVisible(view: View): Boolean {
- return view.id != R.id.burn_in_layer &&
+ return view.id != burnInLayerId &&
view.visibility == VISIBLE &&
view.width > 0 &&
view.height > 0
@@ -589,6 +580,17 @@ object KeyguardRootViewBinder {
private fun ViewPropertyAnimator.animateInIconTranslation(): ViewPropertyAnimator =
setInterpolator(Interpolators.DECELERATE_QUINT).translationY(0f)
+ private val statusViewId = R.id.keyguard_status_view
+ private val burnInLayerId = R.id.burn_in_layer
+ private val aodNotificationIconContainerId = R.id.aod_notification_icon_container
+ private val largeClockId = R.id.lockscreen_clock_view_large
+ private val smallClockId = R.id.lockscreen_clock_view
+ private val indicationArea = R.id.keyguard_indication_area
+ private val startButton = R.id.start_button
+ private val endButton = R.id.end_button
+ private val lockIcon = R.id.lock_icon_view
+ private val nsslPlaceholderId = R.id.nssl_placeholder
+
private const val ID = "occluding_app_device_entry_unlock_msg"
private const val AOD_ICONS_APPEAR_DURATION: Long = 200
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 4c846e424f4b..29041d1665c3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -34,6 +34,7 @@ import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.DeviceEntryIconViewBinder
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
@@ -72,7 +73,7 @@ constructor(
override fun addViews(constraintLayout: ConstraintLayout) {
if (
!KeyguardBottomAreaRefactor.isEnabled &&
- !DeviceEntryUdfpsRefactor.isEnabled &&
+ !MigrateClocksToBlueprint.isEnabled &&
!DeviceEntryUdfpsRefactor.isEnabled
) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt
index c921fa7d7a19..8c6be989d8d9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt
@@ -81,6 +81,10 @@ constructor(
)
}
+ /** See [BouncerToGoneFlows#showAllNotifications] */
+ val showAllNotifications: Flow<Boolean> =
+ bouncerToGoneFlows.showAllNotifications(TO_GONE_DURATION, ALTERNATE_BOUNCER)
+
/** Scrim alpha values */
val scrimAlpha: Flow<ScrimAlpha> =
bouncerToGoneFlows.scrimAlpha(TO_GONE_DURATION, ALTERNATE_BOUNCER)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
index 924fc5d0333f..fe88b8169c89 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
@@ -32,6 +32,7 @@ import javax.inject.Inject
import kotlin.time.Duration
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
@@ -63,6 +64,31 @@ constructor(
}
}
+ /**
+ * When the shade is expanded, make sure that all notifications can be seen immediately during a
+ * transition to GONE. This matters especially when the user has chosen to not show
+ * notifications on the lockscreen and then pulls down the shade, which presents them with an
+ * immediate auth prompt, followed by a notification animation.
+ */
+ fun showAllNotifications(duration: Duration, from: KeyguardState): Flow<Boolean> {
+ var leaveShadeOpen = false
+ return animationFlow
+ .setup(
+ duration = duration,
+ from = from,
+ to = GONE,
+ )
+ .sharedFlow(
+ duration = duration,
+ onStart = { leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() },
+ onStep = { if (leaveShadeOpen) 1f else 0f },
+ onFinish = { 0f },
+ onCancel = { 0f },
+ )
+ .map { it == 1f }
+ .distinctUntilChanged()
+ }
+
private fun createScrimAlphaFlow(
duration: Duration,
fromState: KeyguardState,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index 1f80441492bc..36896f916e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -18,8 +18,10 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.content.res.Resources
import com.android.keyguard.KeyguardClockSwitch
+import com.android.keyguard.KeyguardClockSwitch.SMALL
import com.android.systemui.biometrics.AuthController
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.res.R
@@ -29,6 +31,7 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -42,6 +45,7 @@ constructor(
private val authController: AuthController,
val longPress: KeyguardLongPressViewModel,
val shadeInteractor: ShadeInteractor,
+ @Application private val applicationScope: CoroutineScope,
) {
private val clockSize = clockInteractor.clockSize
@@ -50,11 +54,26 @@ constructor(
val isLargeClockVisible: Boolean
get() = clockSize.value == KeyguardClockSwitch.LARGE
- val areNotificationsVisible: Boolean
- get() = !isLargeClockVisible || shouldUseSplitNotificationShade
+ val shouldUseSplitNotificationShade: StateFlow<Boolean> =
+ shadeInteractor.shadeMode
+ .map { it == ShadeMode.Split }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
- val shouldUseSplitNotificationShade: Boolean
- get() = shadeInteractor.shadeMode.value == ShadeMode.Split
+ val areNotificationsVisible: StateFlow<Boolean> =
+ combine(clockSize, shouldUseSplitNotificationShade) {
+ clockSize,
+ shouldUseSplitNotificationShade ->
+ clockSize == SMALL || shouldUseSplitNotificationShade
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
fun getSmartSpacePaddingTop(resources: Resources): Int {
return if (isLargeClockVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index 53f448826e80..05878265dd6d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -60,6 +60,10 @@ constructor(
private var leaveShadeOpen: Boolean = false
private var willRunDismissFromKeyguard: Boolean = false
+ /** See [BouncerToGoneFlows#showAllNotifications] */
+ val showAllNotifications: Flow<Boolean> =
+ bouncerToGoneFlows.showAllNotifications(TO_GONE_DURATION, PRIMARY_BOUNCER)
+
val notificationAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
duration = 200.milliseconds,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 1aef9206d99f..8d3500a4f9f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -29,6 +29,7 @@ import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.external.QSExternalModule;
+import com.android.systemui.qs.panels.dagger.PanelsModule;
import com.android.systemui.qs.pipeline.dagger.QSPipelineModule;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.qs.tiles.di.QSTilesModule;
@@ -44,21 +45,22 @@ import com.android.systemui.statusbar.policy.SafetyController;
import com.android.systemui.statusbar.policy.WalletController;
import com.android.systemui.util.settings.SecureSettings;
-import java.util.Map;
-
-import javax.inject.Named;
-
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.Multibinds;
+import java.util.Map;
+
+import javax.inject.Named;
+
/**
* Module for QS dependencies
*/
@Module(subcomponents = {QSFragmentComponent.class, QSSceneComponent.class},
includes = {
MediaModule.class,
+ PanelsModule.class,
QSExternalModule.class,
QSFlagsModule.class,
QSHostModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
new file mode 100644
index 000000000000..1307296dd2b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.dagger
+
+import com.android.systemui.qs.panels.data.repository.IconTilesRepository
+import com.android.systemui.qs.panels.data.repository.IconTilesRepositoryImpl
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface PanelsModule {
+ @Binds fun bindIconTilesRepository(impl: IconTilesRepositoryImpl): IconTilesRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt
new file mode 100644
index 000000000000..92f87e78f090
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+
+/** Repository for retrieving the list of [TileSpec] to be displayed as icons. */
+interface IconTilesRepository {
+ val iconTilesSpecs: Flow<Set<TileSpec>>
+}
+
+@SysUISingleton
+class IconTilesRepositoryImpl @Inject constructor() : IconTilesRepository {
+
+ /** Set of toggleable tiles that are suitable for being shown as an icon. */
+ override val iconTilesSpecs: Flow<Set<TileSpec>> =
+ flowOf(
+ setOf(
+ TileSpec.create("airplane"),
+ TileSpec.create("battery"),
+ TileSpec.create("cameratoggle"),
+ TileSpec.create("cast"),
+ TileSpec.create("color_correction"),
+ TileSpec.create("inversion"),
+ TileSpec.create("saver"),
+ TileSpec.create("dnd"),
+ TileSpec.create("flashlight"),
+ TileSpec.create("location"),
+ TileSpec.create("mictoggle"),
+ TileSpec.create("nfc"),
+ TileSpec.create("night"),
+ TileSpec.create("rotation")
+ )
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt
new file mode 100644
index 000000000000..367c67093605
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.panels.data.repository.IconTilesRepository
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Interactor for retrieving the list of [TileSpec] to be displayed as icons. */
+@SysUISingleton
+class IconTilesInteractor @Inject constructor(private val repo: IconTilesRepository) {
+ val iconTilesSpecs: Flow<Set<TileSpec>> = repo.iconTilesSpecs
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 2360f27fc115..30044856a7d4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -620,7 +620,7 @@ open class QSTileViewImpl @JvmOverloads constructor(
showRippleEffect = false
setOnTouchListener(longPressEffect)
if (!longPressEffectViewBinder.isBound) {
- longPressEffectViewBinder.bind(this, longPressEffect)
+ longPressEffectViewBinder.bind(this, state.spec, longPressEffect)
}
} else {
// Long-press effects might have been enabled before but the new state does not
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index 1b7322592b41..e1b742e1e7f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -182,12 +182,19 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
@Override
public boolean isAvailable() {
+ if (isWalletRoleAvailable()) {
+ return !mPackageManager.hasSystemFeature(FEATURE_CHROME_OS);
+ }
return mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
&& !mPackageManager.hasSystemFeature(FEATURE_CHROME_OS)
&& mSecureSettings.getStringForUser(NFC_PAYMENT_DEFAULT_COMPONENT,
UserHandle.USER_CURRENT) != null;
}
+ private boolean isWalletRoleAvailable() {
+ return mHost.getUserId() == UserHandle.USER_SYSTEM && mController.isWalletRoleAvailable();
+ }
+
@Nullable
@Override
public Intent getLongClickIntent() {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
index 69dce83b7136..2fbcba977a91 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
@@ -20,9 +20,6 @@ package com.android.systemui.scene.shared.model
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -36,14 +33,10 @@ import kotlinx.coroutines.flow.stateIn
* Delegates calls to a runtime-provided [SceneDataSource] or to a no-op implementation if a
* delegate isn't set.
*/
-@SysUISingleton
-class SceneDataSourceDelegator
-@Inject
-constructor(
- @Application private val applicationScope: CoroutineScope,
+class SceneDataSourceDelegator(
+ applicationScope: CoroutineScope,
config: SceneContainerConfig,
) : SceneDataSource {
-
private val noOpDelegate = NoOpSceneDataSource(config.initialSceneKey)
private val delegateMutable = MutableStateFlow<SceneDataSource>(noOpDelegate)
@@ -82,6 +75,7 @@ constructor(
) : SceneDataSource {
override val currentScene: StateFlow<SceneKey> =
MutableStateFlow(initialSceneKey).asStateFlow()
+
override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) = Unit
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index b796a206b5b4..047ecb42287b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -29,8 +29,6 @@ import static com.android.systemui.screenshot.LogConfig.logTag;
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER;
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT;
-import static java.util.Objects.requireNonNull;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.MainThread;
@@ -41,7 +39,6 @@ import android.app.ActivityOptions;
import android.app.ExitTransitionCoordinator;
import android.app.ICompatCameraControlCallback;
import android.app.Notification;
-import android.app.assist.AssistContent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -73,7 +70,6 @@ import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import android.window.WindowContext;
@@ -81,11 +77,11 @@ import com.android.internal.app.ChooserActivity;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
import com.android.settingslib.applications.InterestingConfigChanges;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.clipboardoverlay.ClipboardOverlayController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.res.R;
import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
import com.android.systemui.screenshot.scroll.LongScreenshotActivity;
@@ -218,17 +214,10 @@ public class ScreenshotController {
// ScreenshotNotificationSmartActionsProvider.
static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type";
static final String EXTRA_ID = "android:screenshot_id";
- static final String ACTION_TYPE_DELETE = "Delete";
- static final String ACTION_TYPE_SHARE = "Share";
- static final String ACTION_TYPE_EDIT = "Edit";
static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
- static final String EXTRA_OVERRIDE_TRANSITION = "android:screenshot_override_transition";
static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
static final String EXTRA_ACTION_INTENT_FILLIN = "android:screenshot_action_intent_fillin";
- static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
- static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
- static final String EXTRA_DISALLOW_ENTER_PIP = "android:screenshot_disallow_enter_pip";
// From WizardManagerHelper.java
private static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete";
@@ -247,10 +236,10 @@ public class ScreenshotController {
private final Executor mMainExecutor;
private final ExecutorService mBgExecutor;
private final BroadcastSender mBroadcastSender;
+ private final BroadcastDispatcher mBroadcastDispatcher;
private final WindowManager mWindowManager;
private final WindowManager.LayoutParams mWindowLayoutParams;
- private final AccessibilityManager mAccessibilityManager;
@Nullable
private final ScreenshotSoundController mScreenshotSoundController;
private final ScrollCaptureClient mScrollCaptureClient;
@@ -278,7 +267,7 @@ public class ScreenshotController {
private Animator mScreenshotAnimation;
private RequestCallback mCurrentRequestCallback;
private String mPackageName = "";
- private BroadcastReceiver mCopyBroadcastReceiver;
+ private final BroadcastReceiver mCopyBroadcastReceiver;
// When false, the screenshot is taken without showing the ui. Note that this only applies to
// external displays, as on the default one the UI should **always** be shown.
@@ -300,6 +289,8 @@ public class ScreenshotController {
@AssistedInject
ScreenshotController(
Context context,
+ DisplayManager displayManager,
+ WindowManager windowManager,
FeatureFlags flags,
ScreenshotViewProxy.Factory viewProxyFactory,
ScreenshotActionsProvider.Factory actionsProviderFactory,
@@ -315,6 +306,7 @@ public class ScreenshotController {
ActivityManager activityManager,
TimeoutHandler timeoutHandler,
BroadcastSender broadcastSender,
+ BroadcastDispatcher broadcastDispatcher,
ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider,
ActionIntentExecutor actionExecutor,
UserManager userManager,
@@ -337,16 +329,17 @@ public class ScreenshotController {
mScreenshotNotificationSmartActionsProvider = screenshotNotificationSmartActionsProvider;
mBgExecutor = Executors.newSingleThreadExecutor();
mBroadcastSender = broadcastSender;
+ mBroadcastDispatcher = broadcastDispatcher;
mScreenshotHandler = timeoutHandler;
mScreenshotHandler.setDefaultTimeoutMillis(SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS);
mDisplayId = displayId;
- mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
+ mDisplayManager = displayManager;
+ mWindowManager = windowManager;
final Context displayContext = context.createDisplayContext(getDisplay());
mContext = (WindowContext) displayContext.createWindowContext(TYPE_SCREENSHOT, null);
- mWindowManager = mContext.getSystemService(WindowManager.class);
mFlags = flags;
mActionExecutor = actionExecutor;
mUserManager = userManager;
@@ -363,8 +356,6 @@ public class ScreenshotController {
mViewProxy.requestDismissal(SCREENSHOT_INTERACTION_TIMEOUT);
});
- mAccessibilityManager = AccessibilityManager.getInstance(mContext);
-
// Setup the window that we are going to use
mWindowLayoutParams = FloatingWindowUtil.getFloatingWindowParams();
mWindowLayoutParams.setTitle("ScreenshotAnimation");
@@ -390,9 +381,9 @@ public class ScreenshotController {
}
}
};
- mContext.registerReceiver(mCopyBroadcastReceiver, new IntentFilter(
- ClipboardOverlayController.COPY_OVERLAY_ACTION),
- ClipboardOverlayController.SELF_PERMISSION, null, Context.RECEIVER_NOT_EXPORTED);
+ mBroadcastDispatcher.registerReceiver(mCopyBroadcastReceiver, new IntentFilter(
+ ClipboardOverlayController.COPY_OVERLAY_ACTION), null, null,
+ Context.RECEIVER_NOT_EXPORTED, ClipboardOverlayController.SELF_PERMISSION);
mShowUIOnExternalDisplay = showUIOnExternalDisplay;
}
@@ -442,16 +433,6 @@ public class ScreenshotController {
prepareViewForNewScreenshot(screenshot, oldPackageName);
- if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && screenshot.getTaskId() >= 0) {
- mAssistContentRequester.requestAssistContent(screenshot.getTaskId(),
- new AssistContentRequester.Callback() {
- @Override
- public void onAssistContentAvailable(AssistContent assistContent) {
- screenshot.setContextUrl(assistContent.getWebUri());
- }
- });
- }
-
if (!shouldShowUi()) {
saveScreenshotInWorkerThread(
screenshot.getUserHandle(), finisher, this::logSuccessOnActionsReady,
@@ -567,7 +548,7 @@ public class ScreenshotController {
* Release the constructed window context.
*/
private void releaseContext() {
- mContext.unregisterReceiver(mCopyBroadcastReceiver);
+ mBroadcastDispatcher.unregisterReceiver(mCopyBroadcastReceiver);
mContext.release();
}
@@ -615,7 +596,7 @@ public class ScreenshotController {
if (DEBUG_WINDOW) {
Log.d(TAG, "setContentView: " + mViewProxy.getView());
}
- setContentView(mViewProxy.getView());
+ mWindow.setContentView(mViewProxy.getView());
}
private void enqueueScrollCaptureRequest(UserHandle owner) {
@@ -697,10 +678,8 @@ public class ScreenshotController {
final ScrollCaptureResponse response = mLastScrollCaptureResponse;
mViewProxy.showScrollChip(response.getPackageName(), /* onClick */ () -> {
- DisplayMetrics displayMetrics = new DisplayMetrics();
- getDisplay().getRealMetrics(displayMetrics);
- Bitmap newScreenshot = mImageCapture.captureDisplay(mDisplayId,
- new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels));
+ Bitmap newScreenshot =
+ mImageCapture.captureDisplay(mDisplayId, getFullScreenRect());
if (newScreenshot != null) {
// delay starting scroll capture to make sure scrim is up before the app moves
@@ -797,10 +776,6 @@ public class ScreenshotController {
}
}
- private void setContentView(View contentView) {
- mWindow.setContentView(contentView);
- }
-
@MainThread
private void attachWindow() {
View decorView = mWindow.getDecorView();
@@ -912,12 +887,10 @@ public class ScreenshotController {
public void onFinish() {
}
};
- Pair<ActivityOptions, ExitTransitionCoordinator> transition =
- ActivityOptions.startSharedElementAnimation(mWindow, callbacks, null,
- Pair.create(mViewProxy.getScreenshotPreview(),
- ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME));
- return transition;
+ return ActivityOptions.startSharedElementAnimation(mWindow, callbacks, null,
+ Pair.create(mViewProxy.getScreenshotPreview(),
+ ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME));
}
/** Reset screenshot view and then call onCompleteRunnable */
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index cb2dba00890b..65e845749f9e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -90,7 +90,6 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.res.R;
import com.android.systemui.screenshot.scroll.ScrollCaptureController;
import com.android.systemui.shared.system.InputChannelCompat;
@@ -789,15 +788,8 @@ public class ScreenshotView extends FrameLayout implements
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED, 0, mPackageName);
prepareSharedTransition();
- Intent shareIntent;
- if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && mScreenshotData != null
- && mScreenshotData.getContextUrl() != null) {
- shareIntent = ActionIntentCreator.INSTANCE.createShareWithText(
- imageData.uri, mScreenshotData.getContextUrl().toString());
- } else {
- shareIntent = ActionIntentCreator.INSTANCE.createShareWithSubject(
- imageData.uri, imageData.subject);
- }
+ Intent shareIntent = ActionIntentCreator.INSTANCE.createShareWithSubject(
+ imageData.uri, imageData.subject);
mCallbacks.onAction(shareIntent, imageData.owner, false);
});
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/data/model/DisplayContentModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/data/model/DisplayContentModel.kt
new file mode 100644
index 000000000000..837a661230cb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/data/model/DisplayContentModel.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot.data.model
+
+import android.app.ActivityTaskManager.RootTaskInfo
+
+/** Information about the tasks on a display. */
+data class DisplayContentModel(
+ /** The id of the display. */
+ val displayId: Int,
+ /** Information about the current System UI state which can affect capture. */
+ val systemUiState: SystemUiState,
+ /** A list of root tasks on the display, ordered from bottom to top along the z-axis */
+ val rootTasks: List<RootTaskInfo>,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/data/model/SystemUiState.kt b/packages/SystemUI/src/com/android/systemui/screenshot/data/model/SystemUiState.kt
new file mode 100644
index 000000000000..78be6bdda292
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/data/model/SystemUiState.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot.data.model
+
+/** Information about SystemUI state relevant to screenshot policy. */
+data class SystemUiState(val shadeExpanded: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepository.kt b/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepository.kt
new file mode 100644
index 000000000000..9c81b322a2b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepository.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.screenshot.data.repository
+
+import com.android.systemui.screenshot.data.model.DisplayContentModel
+
+/** Provides information about tasks related to a display. */
+interface DisplayContentRepository {
+ /** Provides information about the tasks and content presented on a given display. */
+ suspend fun getDisplayContent(displayId: Int): DisplayContentModel
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepositoryImpl.kt
new file mode 100644
index 000000000000..e9599dcb026d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepositoryImpl.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot.data.repository
+
+import android.annotation.SuppressLint
+import android.app.ActivityTaskManager
+import android.app.IActivityTaskManager
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.screenshot.data.model.DisplayContentModel
+import com.android.systemui.screenshot.data.model.SystemUiState
+import com.android.systemui.screenshot.proxy.SystemUiProxy
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+/**
+ * Implements DisplayTaskRepository using [IActivityTaskManager], along with [ProfileTypeRepository]
+ * and [SystemUiProxy].
+ */
+@SuppressLint("MissingPermission")
+class DisplayContentRepositoryImpl
+@Inject
+constructor(
+ private val atmService: IActivityTaskManager,
+ private val systemUiProxy: SystemUiProxy,
+ @Background private val background: CoroutineDispatcher,
+) : DisplayContentRepository {
+
+ override suspend fun getDisplayContent(displayId: Int): DisplayContentModel {
+ return withContext(background) {
+ val rootTasks = atmService.getAllRootTaskInfosOnDisplay(displayId)
+ toDisplayTasksModel(displayId, rootTasks)
+ }
+ }
+
+ private suspend fun toDisplayTasksModel(
+ displayId: Int,
+ rootTasks: List<ActivityTaskManager.RootTaskInfo>,
+ ): DisplayContentModel {
+ return DisplayContentModel(
+ displayId,
+ SystemUiState(systemUiProxy.isNotificationShadeExpanded()),
+ rootTasks
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt
index 39b07e3a396a..bc71ab71b626 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt
@@ -21,6 +21,8 @@ import com.android.systemui.screenshot.ImageCapture
import com.android.systemui.screenshot.RequestProcessor
import com.android.systemui.screenshot.ScreenshotPolicy
import com.android.systemui.screenshot.ScreenshotRequestProcessor
+import com.android.systemui.screenshot.data.repository.DisplayContentRepository
+import com.android.systemui.screenshot.data.repository.DisplayContentRepositoryImpl
import com.android.systemui.screenshot.data.repository.ProfileTypeRepository
import com.android.systemui.screenshot.data.repository.ProfileTypeRepositoryImpl
import dagger.Binds
@@ -45,4 +47,8 @@ interface ScreenshotPolicyModule {
return RequestProcessor(imageCapture, policyProvider.get())
}
}
+
+ @Binds
+ @SysUISingleton
+ fun bindDisplayContentRepository(impl: DisplayContentRepositoryImpl): DisplayContentRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 3169e9ccbbcb..33cf9ba4fa7c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -26,12 +26,14 @@ import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import com.android.compose.theme.PlatformTheme
import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.communal.dagger.Communal
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.ui.compose.CommunalContainer
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
import com.android.systemui.util.kotlin.collectFlow
@@ -52,6 +54,7 @@ constructor(
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val shadeInteractor: ShadeInteractor,
private val powerManager: PowerManager,
+ @Communal private val dataSourceDelegator: SceneDataSourceDelegator,
) {
/** The container view for the hub. This will not be initialized until [initView] is called. */
private var communalContainerView: View? = null
@@ -125,6 +128,7 @@ constructor(
PlatformTheme {
CommunalContainer(
viewModel = communalViewModel,
+ dataSourceDelegator = dataSourceDelegator,
dialogFactory = dialogFactory,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
index c501d88b77ce..6bf5535b0761 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
@@ -27,6 +27,8 @@ import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+
/** The shade view. */
public final class NotificationPanelView extends FrameLayout {
static final boolean DEBUG = false;
@@ -41,14 +43,20 @@ public final class NotificationPanelView extends FrameLayout {
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
- setWillNotDraw(!DEBUG);
- mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
+ if (!SceneContainerFlag.isEnabled()) {
+ setWillNotDraw(!DEBUG);
+ mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
- setBackgroundColor(Color.TRANSPARENT);
+ setBackgroundColor(Color.TRANSPARENT);
+ }
}
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
+ if (SceneContainerFlag.isEnabled()) {
+ super.onRtlPropertiesChanged(layoutDirection);
+ return;
+ }
if (mRtlChangeListener != null) {
mRtlChangeListener.onRtlPropertielsChanged(layoutDirection);
}
@@ -56,14 +64,19 @@ public final class NotificationPanelView extends FrameLayout {
@Override
public boolean shouldDelayChildPressedState() {
+ if (SceneContainerFlag.isEnabled()) {
+ return super.shouldDelayChildPressedState();
+ }
return true;
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
- if (mCurrentPanelAlpha != 255) {
- canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mAlphaPaint);
+ if (!SceneContainerFlag.isEnabled()) {
+ if (mCurrentPanelAlpha != 255) {
+ canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mAlphaPaint);
+ }
}
}
@@ -83,6 +96,9 @@ public final class NotificationPanelView extends FrameLayout {
@Override
public boolean hasOverlappingRendering() {
+ if (SceneContainerFlag.isEnabled()) {
+ return super.hasOverlappingRendering();
+ }
return !mDozing;
}
@@ -102,6 +118,9 @@ public final class NotificationPanelView extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (SceneContainerFlag.isEnabled()) {
+ return super.onInterceptTouchEvent(event);
+ }
return mTouchHandler.onInterceptTouchEvent(event);
}
@@ -113,7 +132,9 @@ public final class NotificationPanelView extends FrameLayout {
@Override
public void dispatchConfigurationChanged(Configuration newConfig) {
super.dispatchConfigurationChanged(newConfig);
- mOnConfigurationChangedListener.onConfigurationChanged(newConfig);
+ if (!SceneContainerFlag.isEnabled()) {
+ mOnConfigurationChangedListener.onConfigurationChanged(newConfig);
+ }
}
/** Callback for right-to-left setting changes. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index e4f5aeb5028c..0ddea307b33a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -982,6 +982,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
});
mAlternateBouncerInteractor = alternateBouncerInteractor;
dumpManager.registerDumpable(this);
+ SceneContainerFlag.assertInLegacyMode();
}
private void unlockAnimationFinished() {
@@ -3555,9 +3556,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
@Override
- public ViewPropertyAnimator fadeOut(long startDelayMs, long durationMs, Runnable endAction) {
+ public void fadeOut(long startDelayMs, long durationMs, Runnable endAction) {
mView.animate().cancel();
- return mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration(
+ mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration(
durationMs).setInterpolator(Interpolators.ALPHA_OUT).withLayer().withEndAction(
endAction);
}
@@ -4121,9 +4122,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
@Override
public void updateExpansionAndVisibility() {
- mShadeExpansionStateManager.onPanelExpansionChanged(
- mExpandedFraction, isExpanded(), isTracking(), mExpansionDragDownAmountPx);
-
+ if (!SceneContainerFlag.isEnabled()) {
+ mShadeExpansionStateManager.onPanelExpansionChanged(
+ mExpandedFraction, isExpanded(), isTracking());
+ }
updateVisibility();
}
@@ -4159,7 +4161,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
/** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */
- boolean handleExternalInterceptTouch(MotionEvent event) {
+ @Override
+ public boolean handleExternalInterceptTouch(MotionEvent event) {
try {
mUseExternalTouch = true;
return mTouchHandler.onInterceptTouchEvent(event);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 59da8f1d5841..324dfdf32a3f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -52,6 +52,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.res.R;
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -132,7 +133,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
private DragDownHelper mDragDownHelper;
private boolean mExpandingBelowNotch;
private final DockManager mDockManager;
- private final NotificationPanelViewController mNotificationPanelViewController;
+ private final ShadeViewController mShadeViewController;
+ private final PanelExpansionInteractor mPanelExpansionInteractor;
private final ShadeExpansionStateManager mShadeExpansionStateManager;
private boolean mIsTrackingBarGesture = false;
@@ -154,7 +156,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
DockManager dockManager,
NotificationShadeDepthController depthController,
NotificationShadeWindowView notificationShadeWindowView,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
+ PanelExpansionInteractor panelExpansionInteractor,
ShadeExpansionStateManager shadeExpansionStateManager,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@@ -187,7 +190,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
mStatusBarStateController = statusBarStateController;
mView = notificationShadeWindowView;
mDockManager = dockManager;
- mNotificationPanelViewController = notificationPanelViewController;
+ mShadeViewController = shadeViewController;
+ mPanelExpansionInteractor = panelExpansionInteractor;
mShadeExpansionStateManager = shadeExpansionStateManager;
mDepthController = depthController;
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
@@ -374,7 +378,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
}
if (!mIsTrackingBarGesture && isDown
- && mNotificationPanelViewController.isFullyCollapsed()) {
+ && mPanelExpansionInteractor.isFullyCollapsed()) {
float x = ev.getRawX();
float y = ev.getRawY();
if (mStatusBarViewController.touchIsWithinView(x, y)) {
@@ -447,7 +451,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
} else {
bouncerShowing = mService.isBouncerShowing();
}
- if (mNotificationPanelViewController.isFullyExpanded()
+ if (mPanelExpansionInteractor.isFullyExpanded()
&& !bouncerShowing
&& !mStatusBarStateController.isDozing()) {
if (mDragDownHelper.isDragDownEnabled()) {
@@ -503,7 +507,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
cancellation.setAction(MotionEvent.ACTION_CANCEL);
mStackScrollLayout.onInterceptTouchEvent(cancellation);
if (!MigrateClocksToBlueprint.isEnabled()) {
- mNotificationPanelViewController.handleExternalInterceptTouch(cancellation);
+ mShadeViewController.handleExternalInterceptTouch(cancellation);
}
cancellation.recycle();
}
@@ -522,7 +526,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
// we still want to finish our drag down gesture when locking the screen
handled |= mDragDownHelper.onTouchEvent(ev) || handled;
}
- if (!handled && mNotificationPanelViewController.handleExternalTouch(ev)) {
+ if (!handled && mShadeViewController.handleExternalTouch(ev)) {
return true;
}
} else {
@@ -611,7 +615,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
// Since NotificationStackScrollLayout is now a sibling of notification_panel, we need
// to also ask NotificationPanelViewController directly, in order to process swipe up
// events originating from notifications
- if (mNotificationPanelViewController.handleExternalInterceptTouch(ev)) {
+ if (mShadeViewController.handleExternalInterceptTouch(ev)) {
mShadeLogger.d("NSWVC: NPVC intercepted");
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index 037dc4d6ea21..07836e44e83d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -127,7 +127,9 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl {
@Override
public void animateCollapseShade(int flags, boolean force, boolean delayed,
float speedUpFactor) {
- if (!force && mStatusBarStateController.getState() != StatusBarState.SHADE) {
+ int statusBarState = mStatusBarStateController.getState();
+ if (!force && statusBarState != StatusBarState.SHADE
+ && statusBarState != StatusBarState.SHADE_LOCKED) {
runPostCollapseActions();
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt
index 71dfafa09d52..d9c1f0a91d0c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt
@@ -23,7 +23,5 @@ data class ShadeExpansionChangeEvent(
/** Whether the panel should be considered expanded */
val expanded: Boolean,
/** Whether the user is actively dragging the panel. */
- val tracking: Boolean,
- /** The amount of pixels that the user has dragged during the expansion. */
- val dragDownPxAmount: Float
+ val tracking: Boolean
)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
index df5ff5a8b1f5..359ddd86f115 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
@@ -18,13 +18,13 @@ package com.android.systemui.shade
import android.annotation.IntDef
import android.os.Trace
-import android.os.Trace.TRACE_TAG_APP as TRACE_TAG
import android.util.Log
import androidx.annotation.FloatRange
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.Compile
import java.util.concurrent.CopyOnWriteArrayList
import javax.inject.Inject
+import android.os.Trace.TRACE_TAG_APP as TRACE_TAG
/**
* A class responsible for managing the notification panel's current state.
@@ -42,7 +42,6 @@ class ShadeExpansionStateManager @Inject constructor() {
@FloatRange(from = 0.0, to = 1.0) private var fraction: Float = 0f
private var expanded: Boolean = false
private var tracking: Boolean = false
- private var dragDownPxAmount: Float = 0f
/**
* Adds a listener that will be notified when the panel expansion fraction has changed and
@@ -53,7 +52,7 @@ class ShadeExpansionStateManager @Inject constructor() {
@Deprecated("Use ShadeInteractor instead")
fun addExpansionListener(listener: ShadeExpansionListener): ShadeExpansionChangeEvent {
expansionListeners.add(listener)
- return ShadeExpansionChangeEvent(fraction, expanded, tracking, dragDownPxAmount)
+ return ShadeExpansionChangeEvent(fraction, expanded, tracking)
}
/** Adds a listener that will be notified when the panel state has changed. */
@@ -76,8 +75,7 @@ class ShadeExpansionStateManager @Inject constructor() {
fun onPanelExpansionChanged(
@FloatRange(from = 0.0, to = 1.0) fraction: Float,
expanded: Boolean,
- tracking: Boolean,
- dragDownPxAmount: Float
+ tracking: Boolean
) {
require(!fraction.isNaN()) { "fraction cannot be NaN" }
val oldState = state
@@ -85,7 +83,6 @@ class ShadeExpansionStateManager @Inject constructor() {
this.fraction = fraction
this.expanded = expanded
this.tracking = tracking
- this.dragDownPxAmount = dragDownPxAmount
var fullyClosed = true
var fullyOpened = false
@@ -111,7 +108,6 @@ class ShadeExpansionStateManager @Inject constructor() {
"f=$fraction " +
"expanded=$expanded " +
"tracking=$tracking " +
- "dragDownPxAmount=$dragDownPxAmount " +
"${if (fullyOpened) " fullyOpened" else ""} " +
if (fullyClosed) " fullyClosed" else ""
)
@@ -124,8 +120,7 @@ class ShadeExpansionStateManager @Inject constructor() {
}
}
- val expansionChangeEvent =
- ShadeExpansionChangeEvent(fraction, expanded, tracking, dragDownPxAmount)
+ val expansionChangeEvent = ShadeExpansionChangeEvent(fraction, expanded, tracking)
expansionListeners.forEach { it.onPanelExpansionChanged(expansionChangeEvent) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 2d3833c55199..648d4b55370e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -162,9 +162,7 @@ abstract class ShadeModule {
@Binds
@SysUISingleton
- abstract fun bindsShadeViewController(
- notificationPanelViewController: NotificationPanelViewController
- ): ShadeViewController
+ abstract fun bindsShadeViewController(shadeSurface: ShadeSurface): ShadeViewController
@Binds
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index d02c2154279b..7346a28dc7a7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -15,7 +15,6 @@
*/
package com.android.systemui.shade
-import android.view.ViewPropertyAnimator
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor
import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
@@ -48,7 +47,7 @@ interface ShadeSurface :
fun cancelAnimation()
/** Animates the view from its current alpha to zero then runs the runnable. */
- fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable): ViewPropertyAnimator
+ fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable)
/** Set whether the bouncer is showing. */
fun setBouncerShowing(bouncerShowing: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt
new file mode 100644
index 000000000000..adb29287e40e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade
+
+import com.android.systemui.statusbar.GestureRecorder
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import javax.inject.Inject
+
+class ShadeSurfaceImpl @Inject constructor() : ShadeSurface, ShadeViewControllerEmptyImpl() {
+ override fun initDependencies(
+ centralSurfaces: CentralSurfaces,
+ recorder: GestureRecorder,
+ hideExpandedRunnable: Runnable,
+ headsUpManager: HeadsUpManager
+ ) {}
+
+ override fun cancelPendingCollapse() {
+ // Do nothing
+ }
+
+ override fun cancelAnimation() {
+ // Do nothing
+ }
+
+ override fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable) {
+ // Do nothing
+ }
+
+ override fun setBouncerShowing(bouncerShowing: Boolean) {
+ // Do nothing
+ }
+
+ override fun setTouchAndAnimationDisabled(disabled: Boolean) {
+ // TODO(b/322197941): determine if still needed
+ }
+
+ override fun setWillPlayDelayedDozeAmountAnimation(willPlay: Boolean) {
+ // TODO(b/322494538): determine if still needed
+ }
+
+ override fun setDozing(dozing: Boolean, animate: Boolean) {
+ // Do nothing
+ }
+
+ override fun setImportantForAccessibility(mode: Int) {
+ // Do nothing
+ }
+
+ override fun resetTranslation() {
+ // Do nothing
+ }
+
+ override fun resetAlpha() {
+ // Do nothing
+ }
+
+ override fun onScreenTurningOn() {
+ // Do nothing
+ }
+
+ override fun onThemeChanged() {
+ // Do nothing
+ }
+
+ override fun updateExpansionAndVisibility() {
+ // Do nothing
+ }
+
+ override fun updateResources() {
+ // Do nothing
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 5b2377f7f610..4e1edd33ecf4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -33,14 +33,12 @@ interface ShadeViewController {
/** Returns whether the shade's top level view is enabled. */
@Deprecated("No longer supported. Do not add new calls to this.") val isViewEnabled: Boolean
- /** Returns whether status bar icons should be hidden when the shade is expanded. */
- fun shouldHideStatusBarIconsWhenExpanded(): Boolean
-
/** If the latency tracker is enabled, begins tracking expand latency. */
@Deprecated("No longer supported. Do not add new calls to this.")
fun startExpandLatencyTracking()
/** Sets the alpha value of the shade to a value between 0 and 255. */
+ @Deprecated("No longer supported. Do not add new calls to this.")
fun setAlpha(alpha: Int, animate: Boolean)
/**
@@ -48,6 +46,7 @@ interface ShadeViewController {
*
* @see .setAlpha
*/
+ @Deprecated("No longer supported. Do not add new calls to this.")
fun setAlphaChangeAnimationEndAction(r: Runnable)
/** Sets Qs ScrimEnabled and updates QS state. */
@@ -61,7 +60,7 @@ interface ShadeViewController {
@Deprecated("Does nothing when scene container is enabled.") fun updateSystemUiStateFlags()
/** Ensures that the touchable region is updated. */
- fun updateTouchableRegion()
+ @Deprecated("No longer supported. Do not add new calls to this.") fun updateTouchableRegion()
/**
* Sends an external (e.g. Status Bar) touch event to the Shade touch handler.
@@ -72,6 +71,8 @@ interface ShadeViewController {
*/
fun handleExternalTouch(event: MotionEvent): Boolean
+ fun handleExternalInterceptTouch(event: MotionEvent): Boolean
+
/**
* Triggered when an input focus transfer gesture has started.
*
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index e037c701a165..0c41efd513ad 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -28,7 +28,7 @@ import javax.inject.Inject
import kotlinx.coroutines.flow.flowOf
/** Empty implementation of ShadeViewController for variants with no shade. */
-class ShadeViewControllerEmptyImpl @Inject constructor() :
+open class ShadeViewControllerEmptyImpl @Inject constructor() :
ShadeViewController,
ShadeBackActionInteractor,
ShadeLockscreenInteractor,
@@ -81,6 +81,10 @@ class ShadeViewControllerEmptyImpl @Inject constructor() :
override fun handleExternalTouch(event: MotionEvent): Boolean {
return false
}
+ override fun handleExternalInterceptTouch(event: MotionEvent): Boolean {
+ return false
+ }
+
override fun startInputFocusTransfer() {}
override fun cancelInputFocusTransfer() {}
override fun finishInputFocusTransfer(velocity: Float) {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt
index 661130317854..dfdf2ad564db 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt
@@ -72,4 +72,8 @@ interface PanelExpansionInteractor {
/** Returns the StatusBarState. Note: System UI was formerly known simply as Status Bar. */
@Deprecated("Use SceneInteractor or ShadeInteractor instead") val barState: Int
+
+ /** Returns whether status bar icons should be hidden when the shade is expanded. */
+ @Deprecated("No longer supported. Do not add new calls to this.")
+ fun shouldHideStatusBarIconsWhenExpanded(): Boolean
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
index 561d0bc8e6ef..58bcd2e0d7eb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
@@ -69,27 +69,21 @@ constructor(
state.fromScene == Scenes.Gone ->
if (state.toScene.isExpandable()) {
// Moving from Gone to a scene that can animate-expand has a
- // panel
- // expansion
- // that tracks with the transition.
+ // panel expansion that tracks with the transition.
state.progress
} else {
// Moving from Gone to a scene that doesn't animate-expand
- // immediately makes
- // the panel fully expanded.
+ // immediately makes the panel fully expanded.
flowOf(1f)
}
state.toScene == Scenes.Gone ->
if (state.fromScene.isExpandable()) {
// Moving to Gone from a scene that can animate-expand has a
- // panel
- // expansion
- // that tracks with the transition.
+ // panel expansion that tracks with the transition.
state.progress.map { 1 - it }
} else {
// Moving to Gone from a scene that doesn't animate-expand
- // immediately makes
- // the panel fully collapsed.
+ // immediately makes the panel fully collapsed.
flowOf(0f)
}
else -> flowOf(1f)
@@ -126,6 +120,15 @@ constructor(
override val barState
get() = statusBarStateController.state
+ @Deprecated("No longer supported. Do not add new calls to this.")
+ override fun shouldHideStatusBarIconsWhenExpanded(): Boolean {
+ if (shadeAnimationInteractor.isLaunchingActivity.value) {
+ return false
+ }
+ // TODO(b/325936094) if a HUN is showing, return false
+ return sceneInteractor.currentScene.value == Scenes.Lockscreen
+ }
+
private fun SceneKey.isExpandable(): Boolean {
return this == Scenes.Shade || this == Scenes.QuickSettings
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
index d8216dcfdec6..f3802da9bc9b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
@@ -23,13 +23,20 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.dagger.ShadeTouchLog
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.shade.TouchLogger.Companion.logTouchesTo
import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.transition.ScrimShadeTransitionController
import com.android.systemui.statusbar.policy.SplitShadeStateController
import javax.inject.Inject
+import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
@@ -43,23 +50,44 @@ constructor(
@ShadeTouchLog private val touchLog: LogBuffer,
private val configurationRepository: ConfigurationRepository,
private val shadeRepository: ShadeRepository,
- private val controller: SplitShadeStateController,
+ private val splitShadeStateController: SplitShadeStateController,
private val scrimShadeTransitionController: ScrimShadeTransitionController,
+ private val sceneInteractorProvider: Provider<SceneInteractor>,
+ private val panelExpansionInteractorProvider: Provider<PanelExpansionInteractor>,
+ private val shadeExpansionStateManager: ShadeExpansionStateManager,
) : CoreStartable {
override fun start() {
hydrateShadeMode()
+ hydrateShadeExpansionStateManager()
logTouchesTo(touchLog)
scrimShadeTransitionController.init()
}
+ private fun hydrateShadeExpansionStateManager() {
+ if (SceneContainerFlag.isEnabled) {
+ combine(
+ panelExpansionInteractorProvider.get().legacyPanelExpansion,
+ sceneInteractorProvider.get().isTransitionUserInputOngoing,
+ ) { panelExpansion, tracking ->
+ shadeExpansionStateManager.onPanelExpansionChanged(
+ fraction = panelExpansion,
+ expanded = panelExpansion > 0f,
+ tracking = tracking,
+ )
+ }.launchIn(applicationScope)
+ }
+ }
+
private fun hydrateShadeMode() {
applicationScope.launch {
configurationRepository.onAnyConfigurationChange
// Force initial collection.
.onStart { emit(Unit) }
.map { applicationContext.resources }
- .map { resources -> controller.shouldUseSplitNotificationShade(resources) }
+ .map { resources ->
+ splitShadeStateController.shouldUseSplitNotificationShade(resources)
+ }
.collect { isSplitShade ->
shadeRepository.setShadeMode(
if (isSplitShade) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
index 151e28903fba..e38e53d67f61 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
@@ -17,28 +17,20 @@
package com.android.systemui.shade.transition
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
-import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.PanelState
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.shade.ShadeExpansionStateManager
-import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.statusbar.phone.ScrimController
-import dagger.Lazy
import java.io.PrintWriter
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
/** Controls the scrim properties during the shade expansion transition on non-lockscreen. */
@SysUISingleton
class ScrimShadeTransitionController
@Inject
constructor(
- @Application private val applicationScope: CoroutineScope,
private val shadeExpansionStateManager: ShadeExpansionStateManager,
- private val panelExpansionInteractor: Lazy<PanelExpansionInteractor>,
private val dumpManager: DumpManager,
private val scrimController: ScrimController,
) {
@@ -47,32 +39,17 @@ constructor(
private var currentPanelState: Int? = null
fun init() {
- if (SceneContainerFlag.isEnabled) {
- applicationScope.launch {
- panelExpansionInteractor.get().legacyPanelExpansion.collect { panelExpansion ->
- onPanelExpansionChanged(
- ShadeExpansionChangeEvent(
- fraction = panelExpansion,
- expanded = panelExpansion > 0f,
- tracking = true,
- dragDownPxAmount = 0f,
- )
- )
- }
- }
- } else {
- val currentState =
- shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
- onPanelExpansionChanged(currentState)
- shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
- }
+ val currentState =
+ shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
+ onPanelExpansionChanged(currentState)
+ shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
dumpManager.registerDumpable(
ScrimShadeTransitionController::class.java.simpleName,
this::dump
)
}
- fun onPanelStateChanged(@PanelState state: Int) {
+ private fun onPanelStateChanged(@PanelState state: Int) {
currentPanelState = state
onStateChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index 8d7fc98164c0..acb5339b1a0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -19,8 +19,6 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
-import com.android.settingslib.WirelessUtils;
-
/** Shows the operator name */
public class OperatorNameView extends TextView {
private boolean mDemoMode;
@@ -41,13 +39,14 @@ public class OperatorNameView extends TextView {
mDemoMode = demoMode;
}
- void update(boolean showOperatorName,
+ void update(
+ boolean showOperatorName,
boolean hasMobile,
+ boolean airplaneMode,
OperatorNameViewController.SubInfo sub
) {
setVisibility(showOperatorName ? VISIBLE : GONE);
- boolean airplaneMode = WirelessUtils.isAirplaneModeOn(mContext);
if (!hasMobile || airplaneMode) {
setText(null);
setVisibility(GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
index 8afc72f08656..6e7d8f485195 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
@@ -16,11 +16,9 @@
package com.android.systemui.statusbar;
-import android.annotation.NonNull;
import android.os.Bundle;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.view.View;
@@ -28,47 +26,60 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.connectivity.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor;
+import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.util.ViewController;
+import com.android.systemui.util.kotlin.JavaAdapter;
import javax.inject.Inject;
+import kotlinx.coroutines.Job;
+
/** Controller for {@link OperatorNameView}. */
public class OperatorNameViewController extends ViewController<OperatorNameView> {
private static final String KEY_SHOW_OPERATOR_NAME = "show_operator_name";
private final DarkIconDispatcher mDarkIconDispatcher;
- private final NetworkController mNetworkController;
private final TunerService mTunerService;
private final TelephonyManager mTelephonyManager;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final CarrierConfigTracker mCarrierConfigTracker;
+ private final AirplaneModeInteractor mAirplaneModeInteractor;
+ private final SubscriptionManagerProxy mSubscriptionManagerProxy;
+ private final JavaAdapter mJavaAdapter;
+
+ private Job mAirplaneModeJob;
private OperatorNameViewController(OperatorNameView view,
DarkIconDispatcher darkIconDispatcher,
- NetworkController networkController,
TunerService tunerService,
TelephonyManager telephonyManager,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- CarrierConfigTracker carrierConfigTracker) {
+ CarrierConfigTracker carrierConfigTracker,
+ AirplaneModeInteractor airplaneModeInteractor,
+ SubscriptionManagerProxy subscriptionManagerProxy,
+ JavaAdapter javaAdapter) {
super(view);
mDarkIconDispatcher = darkIconDispatcher;
- mNetworkController = networkController;
mTunerService = tunerService;
mTelephonyManager = telephonyManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mCarrierConfigTracker = carrierConfigTracker;
+ mAirplaneModeInteractor = airplaneModeInteractor;
+ mSubscriptionManagerProxy = subscriptionManagerProxy;
+ mJavaAdapter = javaAdapter;
}
@Override
protected void onViewAttached() {
mDarkIconDispatcher.addDarkReceiver(mDarkReceiver);
- mNetworkController.addCallback(mSignalCallback);
+ mAirplaneModeJob =
+ mJavaAdapter.alwaysCollectFlow(
+ mAirplaneModeInteractor.isAirplaneMode(),
+ (isAirplaneMode) -> update());
mTunerService.addTunable(mTunable, KEY_SHOW_OPERATOR_NAME);
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
}
@@ -76,7 +87,7 @@ public class OperatorNameViewController extends ViewController<OperatorNameView>
@Override
protected void onViewDetached() {
mDarkIconDispatcher.removeDarkReceiver(mDarkReceiver);
- mNetworkController.removeCallback(mSignalCallback);
+ mAirplaneModeJob.cancel(null);
mTunerService.removeTunable(mTunable);
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
}
@@ -87,11 +98,17 @@ public class OperatorNameViewController extends ViewController<OperatorNameView>
mCarrierConfigTracker
.getShowOperatorNameInStatusBarConfig(defaultSubInfo.getSubId())
&& (mTunerService.getValue(KEY_SHOW_OPERATOR_NAME, 1) != 0);
- mView.update(showOperatorName, mTelephonyManager.isDataCapable(), getDefaultSubInfo());
+ mView.update(
+ showOperatorName,
+ mTelephonyManager.isDataCapable(),
+ mAirplaneModeInteractor.isAirplaneMode().getValue(),
+ getDefaultSubInfo()
+ );
}
private SubInfo getDefaultSubInfo() {
- int defaultSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ int defaultSubId = mSubscriptionManagerProxy.getDefaultDataSubscriptionId();
+
SubscriptionInfo sI = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(defaultSubId);
return new SubInfo(
sI.getSubscriptionId(),
@@ -103,36 +120,44 @@ public class OperatorNameViewController extends ViewController<OperatorNameView>
/** Factory for constructing an {@link OperatorNameViewController}. */
public static class Factory {
private final DarkIconDispatcher mDarkIconDispatcher;
- private final NetworkController mNetworkController;
private final TunerService mTunerService;
private final TelephonyManager mTelephonyManager;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final CarrierConfigTracker mCarrierConfigTracker;
+ private final AirplaneModeInteractor mAirplaneModeInteractor;
+ private final SubscriptionManagerProxy mSubscriptionManagerProxy;
+ private final JavaAdapter mJavaAdapter;
@Inject
public Factory(DarkIconDispatcher darkIconDispatcher,
- NetworkController networkController,
TunerService tunerService,
TelephonyManager telephonyManager,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- CarrierConfigTracker carrierConfigTracker) {
+ CarrierConfigTracker carrierConfigTracker,
+ AirplaneModeInteractor airplaneModeInteractor,
+ SubscriptionManagerProxy subscriptionManagerProxy,
+ JavaAdapter javaAdapter) {
mDarkIconDispatcher = darkIconDispatcher;
- mNetworkController = networkController;
mTunerService = tunerService;
mTelephonyManager = telephonyManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mCarrierConfigTracker = carrierConfigTracker;
+ mAirplaneModeInteractor = airplaneModeInteractor;
+ mSubscriptionManagerProxy = subscriptionManagerProxy;
+ mJavaAdapter = javaAdapter;
}
/** Create an {@link OperatorNameViewController}. */
public OperatorNameViewController create(OperatorNameView view) {
return new OperatorNameViewController(view,
mDarkIconDispatcher,
- mNetworkController,
mTunerService,
mTelephonyManager,
mKeyguardUpdateMonitor,
- mCarrierConfigTracker);
+ mCarrierConfigTracker,
+ mAirplaneModeInteractor,
+ mSubscriptionManagerProxy,
+ mJavaAdapter);
}
}
@@ -149,13 +174,6 @@ public class OperatorNameViewController extends ViewController<OperatorNameView>
(area, darkIntensity, tint) ->
mView.setTextColor(DarkIconDispatcher.getTint(area, mView, tint));
- private final SignalCallback mSignalCallback = new SignalCallback() {
- @Override
- public void setIsAirplaneMode(@NonNull IconState icon) {
- update();
- }
- };
-
private final TunerService.Tunable mTunable = (key, newValue) -> update();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index f960fcafafc6..e5b64970c5b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -35,9 +35,11 @@ import com.android.systemui.dump.DumpHandler;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeSurface;
+import com.android.systemui.shade.ShadeSurfaceImpl;
import com.android.systemui.shade.carrier.ShadeCarrierGroupController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationClickNotifier;
@@ -59,6 +61,8 @@ import com.android.systemui.statusbar.phone.StatusBarIconList;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import javax.inject.Provider;
+
import dagger.Binds;
import dagger.Lazy;
import dagger.Module;
@@ -178,9 +182,20 @@ public interface CentralSurfacesDependenciesModule {
* The {@link com.android.systemui.shade.ShadeViewController} interface is bound in
* {@link com.android.systemui.shade.ShadeModule} so others can access it.
*/
- @Binds
+ @Provides
@SysUISingleton
- ShadeSurface provideShadeSurface(NotificationPanelViewController impl);
+ static ShadeSurface provideShadeSurface(
+ SceneContainerFlags sceneContainerFlags,
+ Provider<ShadeSurfaceImpl> sceneContainerOn,
+ Provider<NotificationPanelViewController> sceneContainerOff) {
+ if (sceneContainerFlags.isEnabled()) {
+ return sceneContainerOn.get();
+ } else {
+ return sceneContainerOff.get();
+ }
+
+ }
+
/** */
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 7c718645bc74..4c66f6617312 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -23,7 +23,9 @@ import androidx.core.animation.ObjectAnimator
import com.android.app.animation.Interpolators
import com.android.app.animation.InterpolatorsAndroidX
import com.android.systemui.Dumpable
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionChangeEvent
@@ -47,11 +49,14 @@ import java.io.PrintWriter
import javax.inject.Inject
import kotlin.math.max
import kotlin.math.min
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
@SysUISingleton
class NotificationWakeUpCoordinator
@Inject
constructor(
+ @Application applicationScope: CoroutineScope,
dumpManager: DumpManager,
private val mHeadsUpManager: HeadsUpManager,
private val statusBarStateController: StatusBarStateController,
@@ -60,6 +65,7 @@ constructor(
private val screenOffAnimationController: ScreenOffAnimationController,
private val logger: NotificationWakeUpCoordinatorLogger,
private val notifsKeyguardInteractor: NotificationsKeyguardInteractor,
+ private val communalInteractor: CommunalInteractor,
) :
OnHeadsUpChangedListener,
StatusBarStateController.StateListener,
@@ -201,6 +207,13 @@ constructor(
}
}
)
+ applicationScope.launch {
+ communalInteractor.isIdleOnCommunal.collect {
+ if (!overrideDozeAmountIfCommunalShowing()) {
+ maybeClearHardDozeAmountOverrideHidingNotifs()
+ }
+ }
+ }
}
fun setStackScroller(stackScrollerController: NotificationStackScrollLayoutController) {
@@ -302,6 +315,10 @@ constructor(
return
}
+ if (overrideDozeAmountIfCommunalShowing()) {
+ return
+ }
+
if (clearHardDozeAmountOverride()) {
return
}
@@ -311,9 +328,12 @@ constructor(
private fun setHardDozeAmountOverride(dozing: Boolean, source: String) {
logger.logSetDozeAmountOverride(dozing = dozing, source = source)
+ val previousOverride = hardDozeAmountOverride
hardDozeAmountOverride = if (dozing) 1f else 0f
hardDozeAmountOverrideSource = source
- updateDozeAmount()
+ if (previousOverride != hardDozeAmountOverride) {
+ updateDozeAmount()
+ }
}
private fun clearHardDozeAmountOverride(): Boolean {
@@ -434,6 +454,11 @@ constructor(
return
}
+ if (overrideDozeAmountIfCommunalShowing()) {
+ this.state = newState
+ return
+ }
+
maybeClearHardDozeAmountOverrideHidingNotifs()
this.state = newState
@@ -471,6 +496,18 @@ constructor(
return false
}
+ private fun overrideDozeAmountIfCommunalShowing(): Boolean {
+ if (communalInteractor.isIdleOnCommunal.value) {
+ if (statusBarStateController.state == StatusBarState.KEYGUARD) {
+ setHardDozeAmountOverride(dozing = true, source = "Override: communal (keyguard)")
+ } else {
+ setHardDozeAmountOverride(dozing = false, source = "Override: communal (shade)")
+ }
+ return true
+ }
+ return false
+ }
+
/**
* If the last [setDozeAmount] call was an override to hide notifications, then this call will
* check for the set of states that may have caused that override, and if none of them still
@@ -483,20 +520,23 @@ constructor(
val onKeyguard = statusBarStateController.state == StatusBarState.KEYGUARD
val dozing = statusBarStateController.isDozing
val bypass = bypassController.bypassEnabled
+ val idleOnCommunal = communalInteractor.isIdleOnCommunal.value
val animating =
screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard()
- // Overrides are set by [overrideDozeAmountIfAnimatingScreenOff] and
- // [overrideDozeAmountIfBypass] based on 'animating' and 'bypass' respectively, so only
- // clear the override if both those conditions are cleared. But also require either
+ // Overrides are set by [overrideDozeAmountIfAnimatingScreenOff],
+ // [overrideDozeAmountIfBypass] and [overrideDozeAmountIfCommunalShowing] based on
+ // 'animating', 'bypass' and 'idleOnCommunal' respectively, so only clear the override
+ // if all of those conditions are cleared. But also require either
// !dozing or !onKeyguard because those conditions should indicate that we intend
// notifications to be visible, and thus it is safe to unhide them.
- val willRemove = (!onKeyguard || !dozing) && !bypass && !animating
+ val willRemove = (!onKeyguard || !dozing) && !bypass && !animating && !idleOnCommunal
logger.logMaybeClearHardDozeAmountOverrideHidingNotifs(
willRemove = willRemove,
onKeyguard = onKeyguard,
dozing = dozing,
bypass = bypass,
animating = animating,
+ idleOnCommunal = idleOnCommunal,
)
if (willRemove) {
clearHardDozeAmountOverride()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index 502e1d9ea639..9619bea5efd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -95,6 +95,7 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) {
onKeyguard: Boolean,
dozing: Boolean,
bypass: Boolean,
+ idleOnCommunal: Boolean,
animating: Boolean,
) {
buffer.log(
@@ -103,7 +104,7 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) {
{
str1 =
"willRemove=$willRemove onKeyguard=$onKeyguard dozing=$dozing" +
- " bypass=$bypass animating=$animating"
+ " bypass=$bypass animating=$animating idleOnCommunal=$idleOnCommunal"
},
{ "maybeClearHardDozeAmountOverrideHidingNotifs() $str1" }
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 725c15333b04..9f576066cc98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -589,8 +589,13 @@ constructor(
combine(
isOnLockscreen,
keyguardInteractor.statusBarState,
- ) { isOnLockscreen, statusBarState ->
- statusBarState == SHADE_LOCKED || !isOnLockscreen
+ merge(
+ primaryBouncerToGoneTransitionViewModel.showAllNotifications,
+ alternateBouncerToGoneTransitionViewModel.showAllNotifications,
+ )
+ .onStart { emit(false) }
+ ) { isOnLockscreen, statusBarState, showAllNotifications ->
+ statusBarState == SHADE_LOCKED || !isOnLockscreen || showAllNotifications
}
return combineTransform(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index b6f653fabdc4..2798dbfc62e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -164,6 +164,7 @@ import com.android.systemui.qs.QSFragmentLegacy;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.res.R;
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.scene.shared.flag.SceneContainerFlags;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.settings.UserTracker;
@@ -1256,11 +1257,13 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mScreenOffAnimationController.initialize(this, mShadeSurface, mLightRevealScrim);
updateLightRevealScrimVisibility();
- mShadeSurface.initDependencies(
- this,
- mGestureRec,
- mShadeController::makeExpandedInvisible,
- mHeadsUpManager);
+ if (!SceneContainerFlag.isEnabled()) {
+ mShadeSurface.initDependencies(
+ this,
+ mGestureRec,
+ mShadeController::makeExpandedInvisible,
+ mHeadsUpManager);
+ }
// Set up the quick settings tile panel
final View container = getNotificationShadeWindowView().findViewById(R.id.qs_frame);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index febe5a25d3aa..afd2415ad7a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -579,7 +579,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null) {
viewRoot.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- OnBackInvokedDispatcher.PRIORITY_OVERLAY, mOnBackInvokedCallback);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback);
mIsBackCallbackRegistered = true;
} else {
if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 617e1076fca3..c52132f66813 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -46,7 +46,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameView;
import com.android.systemui.statusbar.OperatorNameViewController;
@@ -79,6 +79,8 @@ import com.android.systemui.util.CarrierConfigTracker.CarrierConfigChangedListen
import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener;
import com.android.systemui.util.settings.SecureSettings;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -89,8 +91,6 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
-import kotlin.Unit;
-
import kotlinx.coroutines.DisposableHandle;
/**
@@ -115,7 +115,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private PhoneStatusBarView mStatusBar;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardStateController mKeyguardStateController;
- private final ShadeViewController mShadeViewController;
+ private final PanelExpansionInteractor mPanelExpansionInteractor;
private MultiSourceMinAlphaController mEndSideAlphaController;
private LinearLayout mEndSideContent;
private View mClockView;
@@ -227,7 +227,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
CollapsedStatusBarViewBinder collapsedStatusBarViewBinder,
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
- ShadeViewController shadeViewController,
+ PanelExpansionInteractor panelExpansionInteractor,
StatusBarStateController statusBarStateController,
NotificationIconContainerStatusBarViewBinder nicViewBinder,
CommandQueue commandQueue,
@@ -252,7 +252,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mDarkIconManagerFactory = darkIconManagerFactory;
mKeyguardStateController = keyguardStateController;
- mShadeViewController = shadeViewController;
+ mPanelExpansionInteractor = panelExpansionInteractor;
mStatusBarStateController = statusBarStateController;
mNicViewBinder = nicViewBinder;
mCommandQueue = commandQueue;
@@ -603,7 +603,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private boolean shouldHideStatusBar() {
if (!mShadeExpansionStateManager.isClosed()
- && mShadeViewController.shouldHideStatusBarIconsWhenExpanded()) {
+ && mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt
index c6c88230586f..684e38e25acd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt
@@ -23,6 +23,7 @@ import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlo
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
/**
@@ -40,7 +41,7 @@ constructor(
private val mobileConnectionsRepository: MobileConnectionsRepository,
) {
/** True if the device is currently in airplane mode. */
- val isAirplaneMode: Flow<Boolean> = airplaneModeRepository.isAirplaneMode
+ val isAirplaneMode: StateFlow<Boolean> = airplaneModeRepository.isAirplaneMode
/** True if we're configured to force-hide the airplane mode icon and false otherwise. */
val isForceHidden: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
index 068e0a6056f3..860068c137a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
@@ -94,7 +94,8 @@ public class SensitiveNotificationProtectionControllerImpl
int packageUid;
try {
- packageUid = mPackageManager.getPackageUid(info.getPackageName(), 0);
+ packageUid = mPackageManager.getPackageUidAsUser(info.getPackageName(),
+ info.getUserHandle().getIdentifier());
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Package " + info.getPackageName() + " not found");
packageUid = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
index dc004f3603a0..d66fe891589a 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
@@ -24,50 +24,53 @@ import com.android.systemui.user.data.repository.UserRepository
/** Utilities related to user management actions. */
object UserActionsUtil {
- /** Returns `true` if it's possible to add a guest user to the device; `false` otherwise. */
+ /**
+ * Returns `true` if it's possible for the given user to add a guest user to the device; `false`
+ * otherwise.
+ */
fun canCreateGuest(
manager: UserManager,
repository: UserRepository,
isUserSwitcherEnabled: Boolean,
- isAddUsersFromLockScreenEnabled: Boolean,
+ canAddUsersWhenLockedOrDeviceUnlocked: Boolean,
): Boolean {
- if (!isUserSwitcherEnabled) {
- return false
- }
-
- return currentUserCanCreateUsers(manager, repository) ||
- anyoneCanCreateUsers(manager, isAddUsersFromLockScreenEnabled)
+ return canAddMoreUsers(
+ manager,
+ repository,
+ isUserSwitcherEnabled,
+ canAddUsersWhenLockedOrDeviceUnlocked,
+ UserManager.USER_TYPE_FULL_GUEST
+ )
}
- /** Returns `true` if it's possible to add a user to the device; `false` otherwise. */
+ /**
+ * Returns `true` if it's possible for the given user to add a user to the device; `false`
+ * otherwise.
+ */
fun canCreateUser(
manager: UserManager,
repository: UserRepository,
isUserSwitcherEnabled: Boolean,
- isAddUsersFromLockScreenEnabled: Boolean,
+ canAddUsersWhenLockedOrDeviceUnlocked: Boolean,
): Boolean {
- if (!isUserSwitcherEnabled) {
- return false
- }
-
- if (
- !currentUserCanCreateUsers(manager, repository) &&
- !anyoneCanCreateUsers(manager, isAddUsersFromLockScreenEnabled)
- ) {
- return false
- }
-
- return manager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY)
+ return canAddMoreUsers(
+ manager,
+ repository,
+ isUserSwitcherEnabled,
+ canAddUsersWhenLockedOrDeviceUnlocked,
+ UserManager.USER_TYPE_FULL_SECONDARY
+ )
}
/**
- * Returns `true` if it's possible to add a supervised user to the device; `false` otherwise.
+ * Returns `true` if it's possible to add a supervised user to the device given the current
+ * user; false` otherwise.
*/
fun canCreateSupervisedUser(
manager: UserManager,
repository: UserRepository,
isUserSwitcherEnabled: Boolean,
- isAddUsersFromLockScreenEnabled: Boolean,
+ canAddUsersWhenLockedOrDeviceUnlocked: Boolean,
supervisedUserPackageName: String?
): Boolean {
if (supervisedUserPackageName.isNullOrEmpty()) {
@@ -78,17 +81,30 @@ object UserActionsUtil {
manager,
repository,
isUserSwitcherEnabled,
- isAddUsersFromLockScreenEnabled
+ canAddUsersWhenLockedOrDeviceUnlocked
)
}
- fun canManageUsers(
+ fun canManageUsers(repository: UserRepository, isUserSwitcherEnabled: Boolean): Boolean {
+ return isUserSwitcherEnabled && repository.getSelectedUserInfo().isAdmin
+ }
+
+ /**
+ * Returns `true` if it's possible to add a user to the device for the given user type; false
+ * otherwise.
+ */
+ private fun canAddMoreUsers(
+ manager: UserManager,
repository: UserRepository,
isUserSwitcherEnabled: Boolean,
- isAddUsersFromLockScreenEnabled: Boolean,
+ canAddUsersWhenLockedOrDeviceUnlocked: Boolean,
+ userType: String
): Boolean {
- return isUserSwitcherEnabled &&
- (repository.getSelectedUserInfo().isAdmin || isAddUsersFromLockScreenEnabled)
+ if (!isUserSwitcherEnabled || !canAddUsersWhenLockedOrDeviceUnlocked) {
+ return false
+ }
+
+ return currentUserCanCreateUsers(manager, repository) && manager.canAddMoreUsers(userType)
}
/**
@@ -96,28 +112,15 @@ object UserActionsUtil {
*/
private fun currentUserCanCreateUsers(
manager: UserManager,
- repository: UserRepository,
+ repository: UserRepository
): Boolean {
val currentUser = repository.getSelectedUserInfo()
if (!currentUser.isAdmin && currentUser.id != UserHandle.USER_SYSTEM) {
return false
}
-
- return systemCanCreateUsers(manager)
- }
-
- /** Returns `true` if the system can add users to the device; `false` otherwise. */
- private fun systemCanCreateUsers(
- manager: UserManager,
- ): Boolean {
- return !manager.hasBaseUserRestriction(UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM)
- }
-
- /** Returns `true` if it's allowed to add users to the device at all; `false` otherwise. */
- private fun anyoneCanCreateUsers(
- manager: UserManager,
- isAddUsersFromLockScreenEnabled: Boolean,
- ): Boolean {
- return systemCanCreateUsers(manager) && isAddUsersFromLockScreenEnabled
+ return !manager.hasUserRestrictionForUser(
+ UserManager.DISALLOW_ADD_USER,
+ UserHandle.of(currentUser.id)
+ ) && !manager.hasUserRestrictionForUser(UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractor.kt
index a122311e3b34..382bc03daca8 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractor.kt
@@ -170,7 +170,8 @@ constructor(
keyguardInteractor.isKeyguardShowing,
) { _, userInfos, settings, isDeviceLocked ->
buildList {
- if (!isDeviceLocked || settings.isAddUsersFromLockscreen) {
+ val canAccessUserSwitcher = !isDeviceLocked || settings.isAddUsersFromLockscreen
+ if (canAccessUserSwitcher) {
// The device is locked and our setting to allow actions that add users
// from the lock-screen is not enabled. We can finish building the list
// here.
@@ -194,7 +195,10 @@ constructor(
when (it) {
UserActionModel.ENTER_GUEST_MODE -> {
val hasGuestUser = userInfos.any { it.isGuest }
- if (!hasGuestUser && canCreateGuestUser(settings)) {
+ if (
+ !hasGuestUser &&
+ canCreateGuestUser(settings, canAccessUserSwitcher)
+ ) {
add(UserActionModel.ENTER_GUEST_MODE)
}
}
@@ -204,7 +208,7 @@ constructor(
manager,
repository,
settings.isUserSwitcherEnabled,
- settings.isAddUsersFromLockscreen,
+ canAccessUserSwitcher
)
if (canCreateUsers) {
@@ -217,7 +221,7 @@ constructor(
manager,
repository,
settings.isUserSwitcherEnabled,
- settings.isAddUsersFromLockscreen,
+ canAccessUserSwitcher,
supervisedUserPackageName,
)
) {
@@ -229,11 +233,7 @@ constructor(
}
}
if (
- UserActionsUtil.canManageUsers(
- repository,
- settings.isUserSwitcherEnabled,
- settings.isAddUsersFromLockscreen,
- )
+ UserActionsUtil.canManageUsers(repository, settings.isUserSwitcherEnabled)
) {
add(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
}
@@ -820,13 +820,16 @@ constructor(
)
}
- private fun canCreateGuestUser(settings: UserSwitcherSettingsModel): Boolean {
+ private fun canCreateGuestUser(
+ settings: UserSwitcherSettingsModel,
+ canAccessUserSwitcher: Boolean
+ ): Boolean {
return guestUserInteractor.isGuestUserAutoCreated ||
UserActionsUtil.canCreateGuest(
manager,
repository,
settings.isUserSwitcherEnabled,
- settings.isAddUsersFromLockscreen,
+ canAccessUserSwitcher,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
index 0207d6e8e8c2..04d7b1fa6532 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
@@ -36,10 +36,15 @@ constructor(
}
fun onSettingsClicked() {
- activityStarter.startActivity(
- Intent(Settings.ACTION_SOUND_SETTINGS)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
- true,
- ) { volumePanelViewModel.dismissPanel() }
+ activityStarter.startActivityDismissingKeyguard(
+ /* intent = */ Intent(Settings.ACTION_SOUND_SETTINGS),
+ /* onlyProvisioned = */ false,
+ /* dismissShade = */ true,
+ /* disallowEnterPictureInPictureWhileLaunching = */ false,
+ /* callback = */ { volumePanelViewModel.dismissPanel() },
+ /* flags = */ Intent.FLAG_ACTIVITY_REORDER_TO_FRONT,
+ /* animationController = */ null,
+ /* userHandle = */ null,
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
index 3242c2814bc5..57b5d570fbbd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
@@ -98,7 +98,7 @@ constructor(
}
}
- private fun AudioStreamModel.toState(
+ private suspend fun AudioStreamModel.toState(
isEnabled: Boolean,
ringerMode: RingerMode,
): State {
@@ -116,7 +116,7 @@ constructor(
isEnabled = isEnabled,
a11yStep = volumeRange.step,
audioStreamModel = this,
- isMutable = audioVolumeInteractor.isMutable(audioStream),
+ isMutable = audioVolumeInteractor.isAffectedByMute(audioStream),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index 1d9b90ac67af..ff1841819dea 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -91,17 +91,22 @@ public class QuickAccessWalletController {
@Background Executor bgExecutor,
SecureSettings secureSettings,
QuickAccessWalletClient quickAccessWalletClient,
- SystemClock clock) {
+ SystemClock clock,
+ RoleManager roleManager) {
mContext = context;
mExecutor = executor;
mBgExecutor = bgExecutor;
mSecureSettings = secureSettings;
- mRoleManager = mContext.getSystemService(RoleManager.class);
+ mRoleManager = roleManager;
mQuickAccessWalletClient = quickAccessWalletClient;
mClock = clock;
mQawClientCreatedTimeMillis = mClock.elapsedRealtime();
}
+ public boolean isWalletRoleAvailable() {
+ return mRoleManager.isRoleAvailable(RoleManager.ROLE_WALLET);
+ }
+
/**
* Returns true if the Quick Access Wallet service & feature is available.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index de696f4b9a2e..71f6081edc23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -165,7 +165,7 @@ public class MenuViewLayerTest extends SysuiTestCase {
mMenuView = spy(
new MenuView(mSpyContext, mMenuViewModel, menuViewAppearance, mSecureSettings));
// Ensure tests don't actually update metrics.
- doNothing().when(mMenuView).incrementTexMetric(any(), anyInt());
+ doNothing().when(mMenuView).incrementTexMetric(any());
mMenuViewLayer = spy(new MenuViewLayer(mSpyContext, mStubWindowManager,
mStubAccessibilityManager, mMenuViewModel, menuViewAppearance, mMenuView,
@@ -414,33 +414,25 @@ public class MenuViewLayerTest extends SysuiTestCase {
@Test
@EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
public void onDismissAction_incrementsTexMetricDismiss() {
- int uid1 = 1234, uid2 = 5678;
mMenuViewModel.onTargetFeaturesChanged(
- List.of(new TestAccessibilityTarget(mSpyContext, uid1),
- new TestAccessibilityTarget(mSpyContext, uid2)));
+ List.of(new TestAccessibilityTarget(mSpyContext, 1234),
+ new TestAccessibilityTarget(mSpyContext, 5678)));
mMenuViewLayer.dispatchAccessibilityAction(R.id.action_remove_menu);
- ArgumentCaptor<Integer> uidCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(mMenuView, times(2)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_DISMISS),
- uidCaptor.capture());
- assertThat(uidCaptor.getAllValues()).containsExactly(uid1, uid2);
+ verify(mMenuView, times(1)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_DISMISS));
}
@Test
@EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
public void onEditAction_incrementsTexMetricEdit() {
- int uid1 = 1234, uid2 = 5678;
mMenuViewModel.onTargetFeaturesChanged(
- List.of(new TestAccessibilityTarget(mSpyContext, uid1),
- new TestAccessibilityTarget(mSpyContext, uid2)));
+ List.of(new TestAccessibilityTarget(mSpyContext, 1234),
+ new TestAccessibilityTarget(mSpyContext, 5678)));
mMenuViewLayer.dispatchAccessibilityAction(R.id.action_edit);
- ArgumentCaptor<Integer> uidCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(mMenuView, times(2)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_EDIT),
- uidCaptor.capture());
- assertThat(uidCaptor.getAllValues()).containsExactly(uid1, uid2);
+ verify(mMenuView, times(1)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_EDIT));
}
/** Simplified AccessibilityTarget for testing MenuViewLayer. */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
index 58011eb63f69..190babdb22b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
@@ -27,7 +27,7 @@ class BackAnimationSpecTest : SysuiTestCase() {
val maxY = 14.0f
val minScale = 0.9f
- val backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi(displayMetrics)
+ val backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi { displayMetrics }
assertBackTransformation(
backAnimationSpec = backAnimationSpec,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt
index f5c9befef0ef..314abda66401 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt
@@ -30,7 +30,7 @@ class OnBackAnimationCallbackExtensionTest : SysuiTestCase() {
private val onBackAnimationCallback =
onBackAnimationCallbackFrom(
- backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi(displayMetrics),
+ backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi { displayMetrics },
displayMetrics = displayMetrics,
onBackProgressed = onBackProgress,
onBackStarted = onBackStart,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt
new file mode 100644
index 000000000000..8cc3a85ef6c8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.domain.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.panels.data.repository.IconTilesRepositoryImpl
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class IconTilesRepositoryImplTest : SysuiTestCase() {
+
+ private val underTest = IconTilesRepositoryImpl()
+
+ @Test
+ fun iconTilesSpecsIsValid() = runTest {
+ val tilesSpecs by collectLastValue(underTest.iconTilesSpecs)
+ assertThat(tilesSpecs).isEqualTo(ICON_ONLY_TILES_SPECS)
+ }
+
+ companion object {
+ private val ICON_ONLY_TILES_SPECS =
+ setOf(
+ TileSpec.create("airplane"),
+ TileSpec.create("battery"),
+ TileSpec.create("cameratoggle"),
+ TileSpec.create("cast"),
+ TileSpec.create("color_correction"),
+ TileSpec.create("inversion"),
+ TileSpec.create("saver"),
+ TileSpec.create("dnd"),
+ TileSpec.create("flashlight"),
+ TileSpec.create("location"),
+ TileSpec.create("mictoggle"),
+ TileSpec.create("nfc"),
+ TileSpec.create("night"),
+ TileSpec.create("rotation")
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index 2d18f9293ec8..122d9e414d13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -58,7 +58,6 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
@@ -68,6 +67,7 @@ import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
@@ -198,7 +198,8 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
}
@Test
- public void testIsAvailable_qawFeatureAvailable() {
+ public void testIsAvailable_qawFeatureAvailableWalletUnavailable() {
+ when(mController.isWalletRoleAvailable()).thenReturn(false);
when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
when(mSecureSettings.getStringForUser(NFC_PAYMENT_DEFAULT_COMPONENT,
@@ -208,6 +209,16 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
}
@Test
+ public void testIsAvailable_nfcUnavailableWalletAvailable() {
+ when(mController.isWalletRoleAvailable()).thenReturn(true);
+ when(mHost.getUserId()).thenReturn(PRIMARY_USER_ID);
+ when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(false);
+ when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
+
+ assertTrue(mTile.isAvailable());
+ }
+
+ @Test
public void testHandleClick_startQuickAccessUiIntent_noCard() {
setUpWalletCard(/* hasCard= */ false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 07d93508228e..5ca6cf12ba90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.model.sceneDataSourceDelegator
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
import com.android.systemui.testKosmos
@@ -104,7 +105,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
dialogFactory,
keyguardTransitionInteractor,
shadeInteractor,
- powerManager
+ powerManager,
+ kosmos.sceneDataSourceDelegator,
)
testableLooper = TestableLooper.get(this)
@@ -145,6 +147,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
keyguardTransitionInteractor,
shadeInteractor,
powerManager,
+ kosmos.sceneDataSourceDelegator,
)
// First call succeeds.
@@ -268,7 +271,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
}
private fun goToScene(scene: SceneKey) {
- communalRepository.setDesiredScene(scene)
+ communalRepository.changeScene(scene)
testableLooper.processAllMessages()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index e957ca2eca3a..d534974d0551 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -604,6 +604,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
new NotificationsKeyguardInteractor(notifsKeyguardViewStateRepository);
NotificationWakeUpCoordinator coordinator =
new NotificationWakeUpCoordinator(
+ mKosmos.getTestScope().getBackgroundScope(),
mDumpManager,
mock(HeadsUpManager.class),
new StatusBarStateControllerImpl(
@@ -618,7 +619,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mDozeParameters,
mScreenOffAnimationController,
new NotificationWakeUpCoordinatorLogger(logcatLogBuffer()),
- notifsKeyguardInteractor);
+ notifsKeyguardInteractor,
+ mKosmos.getCommunalInteractor());
mConfigurationController = new ConfigurationControllerImpl(mContext);
PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 29a92d969ca4..650c45bf83ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -1061,7 +1061,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo
@Test
public void testPanelClosedWhenClosingQsInSplitShade() {
mShadeExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 1,
- /* expanded= */ true, /* tracking= */ false, /* dragDownPxAmount= */ 0);
+ /* expanded= */ true, /* tracking= */ false);
enableSplitShade(/* enabled= */ true);
mNotificationPanelViewController.setExpandedFraction(1f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index b6996131ea09..7a3b561e2f8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -46,6 +46,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationInsetsController
@@ -68,6 +69,7 @@ import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow
@@ -85,7 +87,6 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-import java.util.Optional
import org.mockito.Mockito.`when` as whenever
@OptIn(ExperimentalCoroutinesApi::class)
@@ -100,7 +101,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Mock private lateinit var dozeServiceHost: DozeServiceHost
@Mock private lateinit var dozeScrimController: DozeScrimController
@Mock private lateinit var dockManager: DockManager
- @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock private lateinit var shadeViewController: ShadeViewController
+ @Mock private lateinit var panelExpansionInteractor: PanelExpansionInteractor
@Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
@Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
@@ -177,7 +179,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
dockManager,
notificationShadeDepthController,
view,
- notificationPanelViewController,
+ shadeViewController,
+ panelExpansionInteractor,
ShadeExpansionStateManager(),
stackScrollLayoutController,
statusBarKeyguardViewManager,
@@ -263,7 +266,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
testScope.runTest {
underTest.setStatusBarViewController(phoneStatusBarViewController)
whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
whenever(phoneStatusBarViewController.sendTouchToView(DOWN_EVENT)).thenReturn(true)
@@ -282,7 +285,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
// Item we're testing
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(false)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(false)
val returnVal = interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)
@@ -295,7 +298,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
testScope.runTest {
underTest.setStatusBarViewController(phoneStatusBarViewController)
whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
// Item we're testing
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(false)
@@ -310,7 +313,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
fun handleDispatchTouchEvent_sbWindowNotShowing_noSendTouchToSbAndReturnsTrue() =
testScope.runTest {
underTest.setStatusBarViewController(phoneStatusBarViewController)
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
// Item we're testing
@@ -327,7 +330,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
testScope.runTest {
underTest.setStatusBarViewController(phoneStatusBarViewController)
whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
@@ -486,7 +489,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
// AND bouncer is not showing
whenever(centralSurfaces.isBouncerShowing()).thenReturn(false)
// AND panel view controller wants it
- whenever(notificationPanelViewController.handleExternalInterceptTouch(DOWN_EVENT))
+ whenever(shadeViewController.handleExternalInterceptTouch(DOWN_EVENT))
.thenReturn(true)
mSetFlagsRule.enableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 2ecca2e5c4ca..0f54e0718233 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -38,6 +38,7 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationInsetsController
@@ -89,7 +90,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
@Mock private lateinit var dozeServiceHost: DozeServiceHost
@Mock private lateinit var dozeScrimController: DozeScrimController
@Mock private lateinit var dockManager: DockManager
- @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock private lateinit var shadeViewController: ShadeViewController
+ @Mock private lateinit var panelExpansionInteractor: PanelExpansionInteractor
@Mock private lateinit var notificationStackScrollLayout: NotificationStackScrollLayout
@Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
@Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@@ -166,7 +168,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
dockManager,
notificationShadeDepthController,
underTest,
- notificationPanelViewController,
+ shadeViewController,
+ panelExpansionInteractor,
ShadeExpansionStateManager(),
notificationStackScrollLayoutController,
statusBarKeyguardViewManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
index 15c04eb2e2bc..89ae42fd9f83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
@@ -42,17 +42,11 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
val tracking = true
val dragDownAmount = 1234f
- shadeExpansionStateManager.onPanelExpansionChanged(
- fraction,
- expanded,
- tracking,
- dragDownAmount
- )
+ shadeExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking)
assertThat(listener.fraction).isEqualTo(fraction)
assertThat(listener.expanded).isEqualTo(expanded)
assertThat(listener.tracking).isEqualTo(tracking)
- assertThat(listener.dragDownAmountPx).isEqualTo(dragDownAmount)
}
@Test
@@ -61,12 +55,7 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
val expanded = true
val tracking = true
val dragDownAmount = 1234f
- shadeExpansionStateManager.onPanelExpansionChanged(
- fraction,
- expanded,
- tracking,
- dragDownAmount
- )
+ shadeExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking)
val listener = TestShadeExpansionListener()
val currentState = shadeExpansionStateManager.addExpansionListener(listener)
@@ -75,7 +64,6 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
assertThat(listener.fraction).isEqualTo(fraction)
assertThat(listener.expanded).isEqualTo(expanded)
assertThat(listener.tracking).isEqualTo(tracking)
- assertThat(listener.dragDownAmountPx).isEqualTo(dragDownAmount)
}
@Test
@@ -100,8 +88,7 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 0.5f,
expanded = true,
- tracking = false,
- dragDownPxAmount = 0f
+ tracking = false
)
assertThat(listener.state).isEqualTo(STATE_OPENING)
@@ -115,8 +102,7 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 0.5f,
expanded = true,
- tracking = true,
- dragDownPxAmount = 0f
+ tracking = true
)
assertThat(listener.state).isEqualTo(STATE_OPENING)
@@ -132,8 +118,7 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 0.5f,
expanded = false,
- tracking = false,
- dragDownPxAmount = 0f
+ tracking = false
)
assertThat(listener.state).isEqualTo(STATE_CLOSED)
@@ -149,8 +134,7 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 0.5f,
expanded = false,
- tracking = true,
- dragDownPxAmount = 0f
+ tracking = true
)
assertThat(listener.state).isEqualTo(STATE_OPEN)
@@ -166,8 +150,7 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 1f,
expanded = true,
- tracking = false,
- dragDownPxAmount = 0f
+ tracking = false
)
assertThat(listener.previousState).isEqualTo(STATE_OPENING)
@@ -182,8 +165,7 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 1f,
expanded = true,
- tracking = true,
- dragDownPxAmount = 0f
+ tracking = true
)
assertThat(listener.state).isEqualTo(STATE_OPENING)
@@ -199,8 +181,7 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 1f,
expanded = false,
- tracking = false,
- dragDownPxAmount = 0f
+ tracking = false
)
assertThat(listener.state).isEqualTo(STATE_CLOSED)
@@ -216,8 +197,7 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
shadeExpansionStateManager.onPanelExpansionChanged(
fraction = 1f,
expanded = false,
- tracking = true,
- dragDownPxAmount = 0f
+ tracking = true
)
assertThat(listener.state).isEqualTo(STATE_OPEN)
@@ -229,13 +209,11 @@ class ShadeExpansionStateManagerTest : SysuiTestCase() {
var fraction: Float = 0f
var expanded: Boolean = false
var tracking: Boolean = false
- var dragDownAmountPx: Float = 0f
override fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) {
this.fraction = event.fraction
this.expanded = event.expanded
this.tracking = event.tracking
- this.dragDownAmountPx = event.dragDownPxAmount
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
index dea905aad132..f2abb909e004 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
@@ -3,23 +3,18 @@ package com.android.systemui.shade.transition
import android.platform.test.annotations.DisableFlags
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.compose.animation.scene.ObservableTransitionState
-import com.android.compose.animation.scene.SceneKey
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.FakeSceneDataSource
-import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.shade.ShadeExpansionStateManager
@@ -27,15 +22,8 @@ import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.shade.domain.interactor.panelExpansionInteractor
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -74,9 +62,7 @@ class ScrimShadeTransitionControllerTest : SysuiTestCase() {
sceneInteractor = kosmos.sceneInteractor
fakeSceneDataSource = kosmos.fakeSceneDataSource
underTest = ScrimShadeTransitionController(
- applicationScope,
shadeExpansionStateManager,
- { panelExpansionInteractor },
dumpManager,
scrimController,
)
@@ -99,96 +85,20 @@ class ScrimShadeTransitionControllerTest : SysuiTestCase() {
verify(scrimController).setRawPanelExpansionFraction(DEFAULT_EXPANSION_EVENT.fraction)
}
- @Test
- @EnableSceneContainer
- fun sceneChanges_forwardsToScrimTransitionController() =
- testScope.runTest {
- var rawExpansion: Float? = null
- whenever(scrimController.setRawPanelExpansionFraction(any())).then {
- (it.arguments[0] as Float?).also { rawExp -> rawExpansion = rawExp }
- }
- setUnlocked(true)
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(Scenes.Gone)
- )
- sceneInteractor.setTransitionState(transitionState)
-
- changeScene(Scenes.Gone, transitionState)
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- Truth.assertThat(currentScene).isEqualTo(Scenes.Gone)
-
- Truth.assertThat(rawExpansion)
- .isEqualTo(0f)
-
- changeScene(Scenes.Shade, transitionState) { progress ->
- Truth.assertThat(rawExpansion)
- .isEqualTo(progress)
- }
- }
-
private fun startLegacyPanelExpansion() {
shadeExpansionStateManager.onPanelExpansionChanged(
DEFAULT_EXPANSION_EVENT.fraction,
DEFAULT_EXPANSION_EVENT.expanded,
DEFAULT_EXPANSION_EVENT.tracking,
- DEFAULT_EXPANSION_EVENT.dragDownPxAmount,
)
}
- private fun TestScope.setUnlocked(isUnlocked: Boolean) {
- val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
- deviceEntryRepository.setUnlocked(isUnlocked)
- runCurrent()
-
- Truth.assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
- }
-
- private fun TestScope.changeScene(
- toScene: SceneKey,
- transitionState: MutableStateFlow<ObservableTransitionState>,
- assertDuringProgress: ((progress: Float) -> Unit) = {},
- ) {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- val progressFlow = MutableStateFlow(0f)
- transitionState.value =
- ObservableTransitionState.Transition(
- fromScene = checkNotNull(currentScene),
- toScene = toScene,
- progress = progressFlow,
- isInitiatedByUserInput = true,
- isUserInputOngoing = flowOf(true),
- )
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- progressFlow.value = 0.2f
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- progressFlow.value = 0.6f
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- progressFlow.value = 1f
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- transitionState.value = ObservableTransitionState.Idle(toScene)
- fakeSceneDataSource.changeScene(toScene)
- runCurrent()
- assertDuringProgress(progressFlow.value)
-
- Truth.assertThat(currentScene).isEqualTo(toScene)
- }
-
companion object {
val DEFAULT_EXPANSION_EVENT =
ShadeExpansionChangeEvent(
fraction = 0.5f,
expanded = true,
- tracking = true,
- dragDownPxAmount = 10f
+ tracking = true
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 68bc72b09f94..fc0c85e30d5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -23,18 +23,18 @@ import android.view.Choreographer
import android.view.View
import android.view.ViewRootImpl
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.statusbar.policy.FakeConfigurationController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.util.WallpaperController
import com.android.systemui.util.mockito.eq
import com.google.common.truth.Truth.assertThat
@@ -142,7 +142,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun onPanelExpansionChanged_apliesBlur_ifShade() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
verify(shadeAnimation).animateTo(eq(maxBlur))
}
@@ -150,7 +150,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun onPanelExpansionChanged_animatesBlurIn_ifShade() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 0.01f, expanded = false, tracking = false, dragDownPxAmount = 0f))
+ fraction = 0.01f, expanded = false, tracking = false))
verify(shadeAnimation).animateTo(eq(maxBlur))
}
@@ -160,7 +160,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
clearInvocations(shadeAnimation)
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 0f, expanded = false, tracking = false, dragDownPxAmount = 0f))
+ fraction = 0f, expanded = false, tracking = false))
verify(shadeAnimation).animateTo(eq(0))
}
@@ -168,7 +168,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun onPanelExpansionChanged_animatesBlurOut_ifFlick() {
val event =
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f)
+ fraction = 1f, expanded = true, tracking = false)
onPanelExpansionChanged_apliesBlur_ifShade()
clearInvocations(shadeAnimation)
notificationShadeDepthController.onPanelExpansionChanged(event)
@@ -189,7 +189,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
clearInvocations(shadeAnimation)
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 0.6f, expanded = true, tracking = true, dragDownPxAmount = 0f))
+ fraction = 0.6f, expanded = true, tracking = true))
verify(shadeAnimation).animateTo(eq(maxBlur))
}
@@ -197,7 +197,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun onPanelExpansionChanged_respectsMinPanelPullDownFraction() {
val event =
ShadeExpansionChangeEvent(
- fraction = 0.5f, expanded = true, tracking = true, dragDownPxAmount = 0f)
+ fraction = 0.5f, expanded = true, tracking = true)
notificationShadeDepthController.panelPullDownMinFraction = 0.5f
notificationShadeDepthController.onPanelExpansionChanged(event)
assertThat(notificationShadeDepthController.shadeExpansion).isEqualTo(0f)
@@ -225,7 +225,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
notificationShadeDepthController.qsPanelExpansion = 1f
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
}
@@ -236,7 +236,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
notificationShadeDepthController.qsPanelExpansion = 0.25f
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController)
.setNotificationShadeZoom(eq(ShadeInterpolation.getNotificationScrimAlpha(0.25f)))
@@ -248,7 +248,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController).setNotificationShadeZoom(0f)
@@ -260,7 +260,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController).setNotificationShadeZoom(floatThat { it > 0 })
@@ -273,7 +273,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
val expanded = true
val tracking = false
val dragDownPxAmount = 0f
- val event = ShadeExpansionChangeEvent(rawFraction, expanded, tracking, dragDownPxAmount)
+ val event = ShadeExpansionChangeEvent(rawFraction, expanded, tracking)
val inOrder = Mockito.inOrder(wallpaperController)
notificationShadeDepthController.onPanelExpansionChanged(event)
@@ -338,7 +338,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun updateBlurCallback_setsBlur_whenExpanded() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
@@ -348,7 +348,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun updateBlurCallback_ignoreShadeBlurUntilHidden_overridesZoom() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = true
notificationShadeDepthController.updateBlurCallback.doFrame(0)
@@ -367,7 +367,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun ignoreBlurForUnlock_ignores() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = false
@@ -384,7 +384,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun ignoreBlurForUnlock_doesNotIgnore() {
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = false
@@ -416,7 +416,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
// And shade is blurred
notificationShadeDepthController.onPanelExpansionChanged(
ShadeExpansionChangeEvent(
- fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+ fraction = 1f, expanded = true, tracking = false))
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.updateBlurCallback.doFrame(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
new file mode 100644
index 000000000000..9c59f9bf49d8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.telephony.ServiceState
+import android.telephony.SubscriptionInfo
+import android.telephony.TelephonyManager
+import android.telephony.telephonyManager
+import androidx.test.filters.SmallTest
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.CarrierConfigTracker
+import com.android.systemui.util.kotlin.JavaAdapter
+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 junit.framework.Assert.assertTrue
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class OperatorNameViewControllerTest : SysuiTestCase() {
+ private lateinit var underTest: OperatorNameViewController
+ private lateinit var airplaneModeInteractor: AirplaneModeInteractor
+
+ private val kosmos = Kosmos()
+ private val testScope = TestScope()
+
+ private val view = OperatorNameView(mContext)
+ private val javaAdapter = JavaAdapter(testScope.backgroundScope)
+
+ @Mock private lateinit var darkIconDispatcher: DarkIconDispatcher
+ @Mock private lateinit var tunerService: TunerService
+ private var telephonyManager = kosmos.telephonyManager
+ private val keyguardUpdateMonitor = kosmos.keyguardUpdateMonitor
+ @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
+ private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
+
+ private val airplaneModeRepository = FakeAirplaneModeRepository()
+ private val connectivityRepository = FakeConnectivityRepository()
+ private val mobileConnectionsRepository = FakeMobileConnectionsRepository()
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+
+ airplaneModeInteractor =
+ AirplaneModeInteractor(
+ airplaneModeRepository,
+ connectivityRepository,
+ mobileConnectionsRepository,
+ )
+
+ underTest =
+ OperatorNameViewController.Factory(
+ darkIconDispatcher,
+ tunerService,
+ telephonyManager,
+ keyguardUpdateMonitor,
+ carrierConfigTracker,
+ airplaneModeInteractor,
+ subscriptionManagerProxy,
+ javaAdapter,
+ )
+ .create(view)
+ }
+
+ @Test
+ fun updateFromSubInfo_showsCarrieName() =
+ testScope.runTest {
+ whenever(telephonyManager.isDataCapable).thenReturn(true)
+
+ val mockSubInfo =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(1)
+ whenever(it.carrierName).thenReturn("test_carrier")
+ }
+ whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+ .thenReturn(mockSubInfo)
+ whenever(keyguardUpdateMonitor.getSimState(any()))
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+ whenever(keyguardUpdateMonitor.getServiceState(any()))
+ .thenReturn(ServiceState().also { it.state = ServiceState.STATE_IN_SERVICE })
+ subscriptionManagerProxy.defaultDataSubId = 1
+ airplaneModeRepository.setIsAirplaneMode(false)
+
+ underTest.onViewAttached()
+ runCurrent()
+
+ assertThat(view.text).isEqualTo("test_carrier")
+ }
+
+ @Test
+ fun notDataCapable_doesNotShowOperatorName() =
+ testScope.runTest {
+ whenever(telephonyManager.isDataCapable).thenReturn(false)
+
+ val mockSubInfo =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(1)
+ whenever(it.carrierName).thenReturn("test_carrier")
+ }
+ whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+ .thenReturn(mockSubInfo)
+ whenever(keyguardUpdateMonitor.getSimState(any()))
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+ whenever(keyguardUpdateMonitor.getServiceState(any()))
+ .thenReturn(ServiceState().also { it.state = ServiceState.STATE_IN_SERVICE })
+ subscriptionManagerProxy.defaultDataSubId = 1
+ airplaneModeRepository.setIsAirplaneMode(false)
+
+ underTest.onViewAttached()
+ runCurrent()
+
+ assertTrue(view.text.isNullOrEmpty())
+ }
+
+ @Test
+ fun airplaneMode_doesNotShowOperatorName() =
+ testScope.runTest {
+ whenever(telephonyManager.isDataCapable).thenReturn(false)
+ val mockSubInfo =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(1)
+ whenever(it.carrierName).thenReturn("test_carrier")
+ }
+ whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+ .thenReturn(mockSubInfo)
+ whenever(keyguardUpdateMonitor.getSimState(any()))
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+ whenever(keyguardUpdateMonitor.getServiceState(any()))
+ .thenReturn(ServiceState().also { it.state = ServiceState.STATE_IN_SERVICE })
+ subscriptionManagerProxy.defaultDataSubId = 1
+ airplaneModeRepository.setIsAirplaneMode(true)
+
+ underTest.onViewAttached()
+ runCurrent()
+
+ assertTrue(view.text.isNullOrEmpty())
+ }
+
+ @Test
+ fun notInService_doesNotShowOperatorName() =
+ testScope.runTest {
+ // Data capable
+ whenever(telephonyManager.isDataCapable).thenReturn(true)
+
+ // Valid subscription
+ val mockSubInfo =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(1)
+ whenever(it.carrierName).thenReturn("test_carrier")
+ }
+ whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+ .thenReturn(mockSubInfo)
+ whenever(keyguardUpdateMonitor.getSimState(any()))
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+
+ // Not in service
+ whenever(keyguardUpdateMonitor.getServiceState(any()))
+ .thenReturn(ServiceState().also { it.state = ServiceState.STATE_OUT_OF_SERVICE })
+ // Subscription is default for data
+ subscriptionManagerProxy.defaultDataSubId = 1
+ // Not airplane mode
+ airplaneModeRepository.setIsAirplaneMode(false)
+
+ underTest.onViewAttached()
+ runCurrent()
+
+ assertTrue(view.text.isNullOrEmpty())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
index 82093adcb75c..67b540cd762e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
@@ -19,10 +19,15 @@ package com.android.systemui.statusbar.notification
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.AnimatorTestRule
+import com.android.systemui.communal.data.repository.communalRepository
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dump.DumpManager
-import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeViewController.Companion.WAKEUP_ANIMATION_DELAY_MS
@@ -34,11 +39,16 @@ import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -49,6 +59,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidTestingRunner::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -56,7 +67,8 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
@get:Rule val animatorTestRule = AnimatorTestRule(this)
- private val kosmos = Kosmos()
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
private val dumpManager: DumpManager = mock()
private val headsUpManager: HeadsUpManager = mock()
@@ -97,6 +109,7 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
whenever(statusBarStateController.state).then { statusBarState }
notificationWakeUpCoordinator =
NotificationWakeUpCoordinator(
+ kosmos.applicationCoroutineScope,
dumpManager,
headsUpManager,
statusBarStateController,
@@ -105,6 +118,7 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
screenOffAnimationController,
logger,
kosmos.notificationsKeyguardInteractor,
+ kosmos.communalInteractor,
)
statusBarStateCallback = withArgCaptor {
verify(statusBarStateController).addCallback(capture())
@@ -161,6 +175,39 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
}
@Test
+ fun setDozeToZeroWhenCommunalShowingWillFullyHideNotifications() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(CommunalScenes.Communal)
+ )
+ kosmos.communalRepository.setTransitionState(transitionState)
+ runCurrent()
+ setDozeAmount(0f)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
+ }
+
+ @Test
+ fun closingCommunalWillShowNotifications() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(CommunalScenes.Communal)
+ )
+ kosmos.communalRepository.setTransitionState(transitionState)
+ runCurrent()
+ setDozeAmount(0f)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
+
+ transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Blank)
+ runCurrent()
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
+ }
+
+ @Test
fun switchingToShadeWithBypassEnabledWillShowNotifications() {
setDozeToZeroWithBypassWillFullyHideNotifications()
clearInvocations(stackScrollerController)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 0e89d8072a2e..06a4d0820386 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -59,7 +59,8 @@ import com.android.internal.R;
import com.android.internal.widget.CachingIconView;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestableContext;
-import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
+import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
@@ -90,13 +91,14 @@ import java.util.function.Consumer;
@RunWithLooper
public class ExpandableNotificationRowTest extends SysuiTestCase {
- private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
+ private final FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic();
private NotificationTestHelper mNotificationTestHelper;
@Rule public MockitoRule mockito = MockitoJUnit.rule();
@Before
public void setUp() throws Exception {
allowTestableLooperAsMainThread();
+ mFeatureFlags.set(Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE, false);
mNotificationTestHelper = new NotificationTestHelper(
mContext,
mDependency,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 054680df1582..34605fed7d28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -597,8 +597,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
private static ShadeExpansionChangeEvent expansionEvent(
float fraction, boolean expanded, boolean tracking) {
- return new ShadeExpansionChangeEvent(
- fraction, expanded, tracking, /* dragDownPxAmount= */ 0f);
+ return new ShadeExpansionChangeEvent(fraction, expanded, tracking);
}
@Test
@@ -607,7 +606,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
/* verify that a predictive back callback is registered when the bouncer becomes visible */
mBouncerExpansionCallback.onVisibilityChanged(true);
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mBackCallbackCaptor.capture());
/* verify that the same callback is unregistered when the bouncer becomes invisible */
@@ -622,7 +621,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mBouncerExpansionCallback.onVisibilityChanged(true);
/* capture the predictive back callback during registration */
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mBackCallbackCaptor.capture());
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
@@ -642,7 +641,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mBouncerExpansionCallback.onVisibilityChanged(true);
/* capture the predictive back callback during registration */
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mBackCallbackCaptor.capture());
assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
@@ -660,7 +659,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mBouncerExpansionCallback.onVisibilityChanged(true);
/* capture the predictive back callback during registration */
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mBackCallbackCaptor.capture());
assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 3da5ab9f9d3d..9c3d9c669adc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -52,7 +52,7 @@ import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
@@ -115,7 +115,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
@Mock
private HeadsUpAppearanceController mHeadsUpAppearanceController;
@Mock
- private ShadeViewController mShadeViewController;
+ private PanelExpansionInteractor mPanelExpansionInteractor;
@Mock
private StatusBarIconController.DarkIconManager.Factory mIconManagerFactory;
@Mock
@@ -304,7 +304,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// WHEN the shade is open and configured to hide the status bar icons
mShadeExpansionStateManager.updateState(STATE_OPEN);
- when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
+ when(mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -320,7 +320,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// WHEN the shade is open but *not* configured to hide the status bar icons
mShadeExpansionStateManager.updateState(STATE_OPEN);
- when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(false);
+ when(mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()).thenReturn(false);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -337,7 +337,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// WHEN the shade is open and configured to hide the status bar icons
mShadeExpansionStateManager.updateState(STATE_OPEN);
- when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
+ when(mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -696,7 +696,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
mCollapsedStatusBarViewBinder,
mStatusBarHideIconsForBouncerManager,
mKeyguardStateController,
- mShadeViewController,
+ mPanelExpansionInteractor,
mStatusBarStateController,
mock(NotificationIconContainerStatusBarViewBinder.class),
mCommandQueue,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
index 867476f9023c..581ca3b14822 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
@@ -28,6 +28,7 @@ import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE
import android.content.pm.PackageManager
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
+import android.os.UserHandle
import android.permission.flags.Flags.FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION
import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.RequiresFlagsDisabled
@@ -85,7 +86,6 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
@Mock private lateinit var activityManager: IActivityManager
@Mock private lateinit var mediaProjectionManager: MediaProjectionManager
@Mock private lateinit var packageManager: PackageManager
- @Mock private lateinit var mediaProjectionInfo: MediaProjectionInfo
@Mock private lateinit var listener1: Runnable
@Mock private lateinit var listener2: Runnable
@Mock private lateinit var listener3: Runnable
@@ -95,6 +95,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
private lateinit var globalSettings: FakeGlobalSettings
private lateinit var mediaProjectionCallback: MediaProjectionManager.Callback
private lateinit var controller: SensitiveNotificationProtectionControllerImpl
+ private lateinit var mediaProjectionInfo: MediaProjectionInfo
@Before
fun setUp() {
@@ -109,14 +110,29 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
setShareFullScreen()
whenever(activityManager.bugreportWhitelistedPackages)
.thenReturn(listOf(BUGREPORT_PACKAGE_NAME))
- whenever(packageManager.getPackageUid(TEST_PROJECTION_PACKAGE_NAME, 0))
+ whenever(
+ packageManager.getPackageUidAsUser(
+ TEST_PROJECTION_PACKAGE_NAME,
+ UserHandle.CURRENT.identifier
+ )
+ )
.thenReturn(TEST_PROJECTION_PACKAGE_UID)
- whenever(packageManager.getPackageUid(BUGREPORT_PACKAGE_NAME, 0))
+ whenever(
+ packageManager.getPackageUidAsUser(
+ BUGREPORT_PACKAGE_NAME,
+ UserHandle.CURRENT.identifier
+ )
+ )
.thenReturn(BUGREPORT_PACKAGE_UID)
// SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding. Setup packagemanager to
// return the correct uid in this scenario
- whenever(packageManager.getPackageUid(mContext.packageName, 0))
+ whenever(
+ packageManager.getPackageUidAsUser(
+ mContext.packageName,
+ UserHandle.CURRENT.identifier
+ )
+ )
.thenReturn(mContext.applicationInfo.uid)
whenever(packageManager.checkPermission(anyString(), anyString()))
@@ -271,7 +287,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
fun isSensitiveStateActive_projectionActive_sysuiExempt_false() {
// SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding
- whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
+ setShareFullScreenViaSystemUi()
mediaProjectionCallback.onStart(mediaProjectionInfo)
assertFalse(controller.isSensitiveStateActive)
@@ -309,7 +325,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
@Test
fun isSensitiveStateActive_projectionActive_bugReportHandlerExempt_false() {
- whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
+ setShareFullScreenViaBugReportHandler()
mediaProjectionCallback.onStart(mediaProjectionInfo)
assertFalse(controller.isSensitiveStateActive)
@@ -371,7 +387,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
fun shouldProtectNotification_projectionActive_sysuiExempt_false() {
// SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding
- whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
+ setShareFullScreenViaSystemUi()
mediaProjectionCallback.onStart(mediaProjectionInfo)
val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
@@ -415,7 +431,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
@Test
fun shouldProtectNotification_projectionActive_bugReportHandlerExempt_false() {
- whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
+ setShareFullScreenViaBugReportHandler()
mediaProjectionCallback.onStart(mediaProjectionInfo)
val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
@@ -548,9 +564,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
fun logSensitiveContentProtectionSession_exemptViaSystemUi() {
// SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding
- val testPackageName = mContext.packageName
- val testUid = mContext.applicationInfo.uid
- whenever(mediaProjectionInfo.packageName).thenReturn(testPackageName)
+ setShareFullScreenViaSystemUi()
mediaProjectionCallback.onStart(mediaProjectionInfo)
@@ -558,7 +572,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
FrameworkStatsLog.write(
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
anyLong(),
- eq(testUid),
+ eq(mContext.applicationInfo.uid),
eq(true),
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
@@ -571,7 +585,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
FrameworkStatsLog.write(
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
anyLong(),
- eq(testUid),
+ eq(mContext.applicationInfo.uid),
eq(true),
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
@@ -582,8 +596,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
@Test
fun logSensitiveContentProtectionSession_exemptViaBugReportHandler() {
// Setup exempt via bugreport handler
- whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
-
+ setShareFullScreenViaBugReportHandler()
mediaProjectionCallback.onStart(mediaProjectionInfo)
verify {
@@ -619,13 +632,26 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
}
private fun setShareFullScreen() {
- whenever(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
- whenever(mediaProjectionInfo.launchCookie).thenReturn(null)
+ setShareScreen(TEST_PROJECTION_PACKAGE_NAME, true)
+ }
+
+ private fun setShareFullScreenViaBugReportHandler() {
+ setShareScreen(BUGREPORT_PACKAGE_NAME, true)
+ }
+
+ private fun setShareFullScreenViaSystemUi() {
+ // SystemUi context package name is exempt, but in test scenarios its
+ // com.android.systemui.tests so use that instead of hardcoding
+ setShareScreen(mContext.packageName, true)
}
private fun setShareSingleApp() {
- whenever(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
- whenever(mediaProjectionInfo.launchCookie).thenReturn(ActivityOptions.LaunchCookie())
+ setShareScreen(TEST_PROJECTION_PACKAGE_NAME, false)
+ }
+
+ private fun setShareScreen(packageName: String, fullScreen: Boolean) {
+ val launchCookie = if (fullScreen) null else ActivityOptions.LaunchCookie()
+ mediaProjectionInfo = MediaProjectionInfo(packageName, UserHandle.CURRENT, launchCookie)
}
private fun setupNotificationEntry(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
index 1b4385148f88..3dee093bd594 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
@@ -1014,6 +1014,136 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
verify(spyContext, never()).startServiceAsUser(any(), any())
}
+ @Test
+ fun userIsAdminAndRestricted_addUserActionsNotAdded() {
+ createUserInteractor()
+ testScope.runTest {
+ val id = 0
+ val userInfo =
+ UserInfo(
+ id,
+ "child",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_ADMIN,
+ UserManager.USER_TYPE_FULL_RESTRICTED,
+ )
+ whenever(
+ manager.hasUserRestrictionForUser(
+ UserManager.DISALLOW_ADD_USER,
+ UserHandle.of(id)
+ )
+ )
+ .thenReturn(true)
+
+ userRepository.setUserInfos(listOf(userInfo))
+ userRepository.setSelectedUserInfo(userInfo)
+ userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+
+ val value = collectLastValue(underTest.actions)
+ runCurrent()
+
+ assertThat(value()).isEqualTo(listOf(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT))
+ }
+ }
+
+ @Test
+ fun userIsNotRestrictedAndCannotAddGuests_actionsDoesNotIncludeAddGuest() {
+ createUserInteractor()
+ testScope.runTest {
+ val userInfos = createUserInfos(count = 2, includeGuest = false)
+
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[0])
+ userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+ keyguardRepository.setKeyguardShowing(false)
+
+ whenever(manager.canAddMoreUsers(UserManager.USER_TYPE_FULL_GUEST)).thenReturn(false)
+
+ val value = collectLastValue(underTest.actions)
+ runCurrent()
+
+ assertThat(value())
+ .isEqualTo(
+ listOf(
+ UserActionModel.ADD_USER,
+ UserActionModel.ADD_SUPERVISED_USER,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+ )
+ )
+ }
+ }
+
+ @Test
+ fun userIsNotRestrictedAndCannotAddUsers_actionsDoesNotIncludeAddUsers() {
+ createUserInteractor()
+ testScope.runTest {
+ val userInfos = createUserInfos(count = 2, includeGuest = false)
+
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[0])
+ userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+ keyguardRepository.setKeyguardShowing(false)
+
+ whenever(manager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY))
+ .thenReturn(false)
+
+ val value = collectLastValue(underTest.actions)
+ runCurrent()
+
+ assertThat(value())
+ .isEqualTo(
+ listOf(
+ UserActionModel.ENTER_GUEST_MODE,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+ )
+ )
+ }
+ }
+
+ @Test
+ fun systemUserHasRestrictions_addUserActionsNotAdded() {
+ createUserInteractor()
+ testScope.runTest {
+ val systemId = 0
+ val systemUser =
+ UserInfo(
+ systemId,
+ "system",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_SYSTEM,
+ UserManager.USER_TYPE_SYSTEM_HEADLESS,
+ )
+ val adminId = 10
+ val adminUser =
+ UserInfo(
+ adminId,
+ "admin",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_ADMIN,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ )
+
+ userRepository.setUserInfos(listOf(systemUser, adminUser))
+ userRepository.setSelectedUserInfo(adminUser)
+ userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+ keyguardRepository.setKeyguardShowing(false)
+
+ whenever(headlessSystemUserMode.isHeadlessSystemUserMode()).thenReturn(true)
+ whenever(
+ manager.hasUserRestrictionForUser(
+ UserManager.DISALLOW_ADD_USER,
+ UserHandle.of(0)
+ )
+ )
+ .thenReturn(true)
+
+ val value = collectLastValue(underTest.actions)
+ runCurrent()
+
+ assertThat(value()).isEqualTo(listOf(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT))
+ }
+ }
+
private fun assertUsers(
models: List<UserModel>?,
count: Int,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
index fccb936a3bc8..dc5597a1cce0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.PendingIntent;
+import android.app.role.RoleManager;
import android.content.Intent;
import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.QuickAccessWalletClient;
@@ -54,11 +55,14 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class QuickAccessWalletControllerTest extends SysuiTestCase {
+ private static final String WALLET_ROLE_HOLDER = "wallet.role.holder";
@Mock
private QuickAccessWalletClient mQuickAccessWalletClient;
@Mock
@@ -69,6 +73,8 @@ public class QuickAccessWalletControllerTest extends SysuiTestCase {
private ActivityStarter mActivityStarter;
@Mock
private ActivityTransitionAnimator.Controller mAnimationController;
+ @Mock
+ private RoleManager mRoleManager;
@Captor
private ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
@Captor
@@ -102,7 +108,8 @@ public class QuickAccessWalletControllerTest extends SysuiTestCase {
MoreExecutors.directExecutor(),
mSecureSettings,
mQuickAccessWalletClient,
- mClock);
+ mClock,
+ mRoleManager);
}
@Test
@@ -113,6 +120,24 @@ public class QuickAccessWalletControllerTest extends SysuiTestCase {
}
@Test
+ public void walletRoleAvailable_isAvailable() {
+ when(mRoleManager.isRoleAvailable(eq(RoleManager.ROLE_WALLET))).thenReturn(true);
+ when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_WALLET)))
+ .thenReturn(List.of(WALLET_ROLE_HOLDER));
+
+ assertTrue(mController.isWalletRoleAvailable());
+ }
+
+ @Test
+ public void walletRoleAvailable_isNotAvailable() {
+ when(mRoleManager.isRoleAvailable(eq(RoleManager.ROLE_WALLET))).thenReturn(false);
+ when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_WALLET)))
+ .thenReturn(List.of(WALLET_ROLE_HOLDER));
+
+ assertFalse(mController.isWalletRoleAvailable());
+ }
+
+ @Test
public void walletServiceUnavailable_walletNotEnabled() {
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt
index bc0bf9dd069f..de7b14d1e102 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt
@@ -32,6 +32,7 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInt
import com.android.systemui.deviceentry.domain.interactor.SystemUIDeviceEntryFaceAuthInteractor
import com.android.systemui.scene.SceneContainerFrameworkModule
import com.android.systemui.scene.shared.flag.SceneContainerFlags
+import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneDataSource
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
import com.android.systemui.shade.domain.interactor.BaseShadeInteractor
@@ -45,6 +46,7 @@ import dagger.Provides
import javax.inject.Provider
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -71,7 +73,10 @@ interface SysUITestModule {
@Binds @Main fun bindMainResources(resources: Resources): Resources
@Binds fun bindBroadcastDispatcher(fake: FakeBroadcastDispatcher): BroadcastDispatcher
@Binds @SysUISingleton fun bindsShadeInteractor(sii: ShadeInteractorImpl): ShadeInteractor
- @Binds fun bindSceneDataSource(delegator: SceneDataSourceDelegator): SceneDataSource
+
+ @Binds
+ @SysUISingleton
+ fun bindSceneDataSource(delegator: SceneDataSourceDelegator): SceneDataSource
@Binds
fun provideFaceAuthInteractor(
@@ -109,6 +114,15 @@ interface SysUITestModule {
sceneContainerOff.get()
}
}
+
+ @Provides
+ @SysUISingleton
+ fun providesSceneDataSourceDelegator(
+ @Application applicationScope: CoroutineScope,
+ config: SceneContainerConfig,
+ ): SceneDataSourceDelegator {
+ return SceneDataSourceDelegator(applicationScope, config)
+ }
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
index 5ff588f810bd..9f5c6b8faa38 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
@@ -2,6 +2,7 @@ package com.android.systemui.communal.data.repository
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.communal.shared.model.CommunalScenes
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -17,11 +18,11 @@ import kotlinx.coroutines.flow.stateIn
@OptIn(ExperimentalCoroutinesApi::class)
class FakeCommunalRepository(
applicationScope: CoroutineScope,
- override val desiredScene: MutableStateFlow<SceneKey> =
+ override val currentScene: MutableStateFlow<SceneKey> =
MutableStateFlow(CommunalScenes.Default),
) : CommunalRepository {
- override fun setDesiredScene(desiredScene: SceneKey) {
- this.desiredScene.value = desiredScene
+ override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) {
+ this.currentScene.value = toScene
}
private val defaultTransitionState = ObservableTransitionState.Idle(CommunalScenes.Default)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
index f0fedd2ed479..1e25f7fd470e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
@@ -20,6 +20,7 @@ import com.android.systemui.biometrics.authController
import com.android.systemui.keyguard.domain.interactor.keyguardBlueprintInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.shade.domain.interactor.shadeInteractor
val Kosmos.lockscreenContentViewModel by
@@ -30,5 +31,6 @@ val Kosmos.lockscreenContentViewModel by
authController = authController,
longPress = keyguardLongPressViewModel,
shadeInteractor = shadeInteractor,
+ applicationScope = applicationCoroutineScope,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
index 513c6ab3586d..4a2eaf0f7bf6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
@@ -27,6 +27,7 @@ import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.log.LogBuffer
import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -78,4 +79,11 @@ val Kosmos.shadeControllerImpl by
{ mock<NotificationGutsManager>() },
)
}
-var Kosmos.shadeController: ShadeController by Kosmos.Fixture { shadeControllerImpl }
+var Kosmos.shadeController: ShadeController by
+ Kosmos.Fixture {
+ if (SceneContainerFlag.isEnabled) {
+ shadeControllerSceneImpl
+ } else {
+ shadeControllerImpl
+ }
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
index 7dfa68605ef3..b85858d915b5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
@@ -22,11 +22,17 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.log.LogBuffer
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.domain.interactor.panelExpansionInteractor
import com.android.systemui.shade.transition.ScrimShadeTransitionController
import com.android.systemui.statusbar.policy.splitShadeStateController
import com.android.systemui.util.mockito.mock
+@Deprecated("ShadeExpansionStateManager is deprecated. Remove your dependency on it instead.")
+val Kosmos.shadeExpansionStateManager by Fixture { ShadeExpansionStateManager() }
+
val Kosmos.shadeStartable by Fixture {
ShadeStartable(
applicationScope = applicationCoroutineScope,
@@ -34,7 +40,10 @@ val Kosmos.shadeStartable by Fixture {
touchLog = mock<LogBuffer>(),
configurationRepository = configurationRepository,
shadeRepository = shadeRepository,
- controller = splitShadeStateController,
+ splitShadeStateController = splitShadeStateController,
scrimShadeTransitionController = mock<ScrimShadeTransitionController>(),
+ sceneInteractorProvider = { sceneInteractor },
+ panelExpansionInteractorProvider = { panelExpansionInteractor },
+ shadeExpansionStateManager = shadeExpansionStateManager,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
index a3ad2b87d5f5..4788624bdf02 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
@@ -44,6 +44,8 @@ class FakeAudioRepository : AudioRepository {
private val models: MutableMap<AudioStream, MutableStateFlow<AudioStreamModel>> = mutableMapOf()
private val lastAudibleVolumes: MutableMap<AudioStream, Int> = mutableMapOf()
+ private var isAffectedByMute: MutableMap<AudioStream, Boolean> = mutableMapOf()
+
private fun getAudioStreamModelState(
audioStream: AudioStream
): MutableStateFlow<AudioStreamModel> =
@@ -93,4 +95,15 @@ class FakeAudioRepository : AudioRepository {
fun setLastAudibleVolume(audioStream: AudioStream, volume: Int) {
lastAudibleVolumes[audioStream] = volume
}
+
+ override suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode) {
+ mutableRingerMode.value = mode
+ }
+
+ override suspend fun isAffectedByMute(audioStream: AudioStream): Boolean =
+ isAffectedByMute[audioStream] ?: true
+
+ fun setIsAffectedByMute(audioStream: AudioStream, isAffected: Boolean) {
+ isAffectedByMute[audioStream] = isAffected
+ }
}
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 178102e2876d..8905ad3273d8 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -151,6 +151,18 @@ java_device_for_host {
filegroup {
name: "ravenwood-services-jarjar-rules",
- srcs: ["ravenwood-services-jarjar-rules.txt"],
+ srcs: ["texts/ravenwood-services-jarjar-rules.txt"],
visibility: ["//frameworks/base"],
}
+
+// For collecting the *stats.csv files in a known directory under out/host/linux-x86/testcases/.
+// The "test" just shows the available stats filenames.
+sh_test_host {
+ name: "ravenwood-stats-checker",
+ src: "scripts/ravenwood-stats-checker.sh",
+ test_suites: ["general-tests"],
+ data: [
+ ":framework-minus-apex.ravenwood.stats",
+ ":services.core.ravenwood.stats",
+ ],
+}
diff --git a/ravenwood/bulk_enable.py b/ravenwood/scripts/bulk_enable.py
index aafaaff7561a..aafaaff7561a 100644
--- a/ravenwood/bulk_enable.py
+++ b/ravenwood/scripts/bulk_enable.py
diff --git a/ravenwood/fix_test_runner.py b/ravenwood/scripts/fix_test_runner.py
index 99b7a1ff226b..99b7a1ff226b 100755
--- a/ravenwood/fix_test_runner.py
+++ b/ravenwood/scripts/fix_test_runner.py
diff --git a/ravenwood/list-ravenwood-tests.sh b/ravenwood/scripts/list-ravenwood-tests.sh
index fb9b823ee93b..fb9b823ee93b 100755
--- a/ravenwood/list-ravenwood-tests.sh
+++ b/ravenwood/scripts/list-ravenwood-tests.sh
diff --git a/ravenwood/scripts/ravenwood-stats-checker.sh b/ravenwood/scripts/ravenwood-stats-checker.sh
new file mode 100755
index 000000000000..93f4a3fe4333
--- /dev/null
+++ b/ravenwood/scripts/ravenwood-stats-checker.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Just print the available *.csv filenames.
+echo '#Stats files:'
+ls *.csv \ No newline at end of file
diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh
new file mode 100755
index 000000000000..4dcaa2be5af3
--- /dev/null
+++ b/ravenwood/scripts/ravenwood-stats-collector.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Script to collect the ravenwood "stats" CVS files and create a single file.
+
+set -e
+
+# Output file
+out=/tmp/ravenwood-stats-all.csv
+
+# Where the input files are.
+path=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/ravenwood-stats-checker/x86_64/
+
+m() {
+ ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
+}
+
+# Building this will generate the files we need.
+m ravenwood-stats-checker
+
+# Start...
+
+cd $path
+
+dump() {
+ local jar=$1
+ local file=$2
+
+ sed -e '1d' -e "s/^/$jar,/" $file
+}
+
+collect() {
+ echo 'Jar,PackageName,ClassName,SupportedMethods,TotalMethods'
+ dump "framework-minus-apex" hoststubgen_framework-minus-apex_stats.csv
+ dump "service.core" hoststubgen_services.core_stats.csv
+}
+
+collect >$out
+
+echo "Full dump CVS created at $out"
diff --git a/ravenwood/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh
index a303626bb445..926c08f4e689 100755
--- a/ravenwood/run-ravenwood-tests.sh
+++ b/ravenwood/scripts/run-ravenwood-tests.sh
@@ -15,7 +15,7 @@
# Run all the ravenwood tests + hoststubgen unit tests.
-all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test"
+all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test ravenwood-stats-checker"
# "echo" is to remove the newlines
all_tests="$all_tests $(echo $(${0%/*}/list-ravenwood-tests.sh) )"
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/texts/framework-minus-apex-ravenwood-policies.txt
index 371c3acab144..371c3acab144 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/texts/framework-minus-apex-ravenwood-policies.txt
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
index 9b4d378cc7b7..9b4d378cc7b7 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
diff --git a/ravenwood/ravenwood-services-jarjar-rules.txt b/ravenwood/texts/ravenwood-services-jarjar-rules.txt
index 8fdd3408f74d..8fdd3408f74d 100644
--- a/ravenwood/ravenwood-services-jarjar-rules.txt
+++ b/ravenwood/texts/ravenwood-services-jarjar-rules.txt
diff --git a/ravenwood/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt
index f64f26d7962a..f64f26d7962a 100644
--- a/ravenwood/ravenwood-standard-options.txt
+++ b/ravenwood/texts/ravenwood-standard-options.txt
diff --git a/ravenwood/services.core-ravenwood-policies.txt b/ravenwood/texts/services.core-ravenwood-policies.txt
index d8d563e05435..d8d563e05435 100644
--- a/ravenwood/services.core-ravenwood-policies.txt
+++ b/ravenwood/texts/services.core-ravenwood-policies.txt
diff --git a/services/Android.bp b/services/Android.bp
index 7bbb42e9a88f..29d1acf5f350 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -254,6 +254,7 @@ java_library {
required: [
"libukey2_jni_shared",
"protolog.conf.json.gz",
+ "core.protolog.pb",
],
lint: {
baseline_filename: "lint-baseline.xml",
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 2d593094aef7..8ac1eb9c90b7 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -82,7 +82,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
import android.util.ExceptionUtils;
-import android.util.Log;
import android.util.Slog;
import com.android.internal.app.IAppOpsService;
@@ -121,8 +120,7 @@ import java.util.Set;
@SuppressLint("LongLogTag")
public class CompanionDeviceManagerService extends SystemService {
- static final String TAG = "CDM_CompanionDeviceManagerService";
- static final boolean DEBUG = false;
+ private static final String TAG = "CDM_CompanionDeviceManagerService";
private static final long PAIR_WITHOUT_PROMPT_WINDOW_MS = 10 * 60 * 1000; // 10 min
@@ -135,7 +133,6 @@ public class CompanionDeviceManagerService extends SystemService {
private final IAppOpsService mAppOpsManager;
private final PowerExemptionManager mPowerExemptionManager;
private final PackageManagerInternal mPackageManagerInternal;
- private final PowerManagerInternal mPowerManagerInternal;
private final AssociationStore mAssociationStore;
private final SystemDataTransferRequestStore mSystemDataTransferRequestStore;
@@ -160,7 +157,8 @@ public class CompanionDeviceManagerService extends SystemService {
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
final UserManager userManager = context.getSystemService(UserManager.class);
- mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+ final PowerManagerInternal powerManagerInternal = LocalServices.getService(
+ PowerManagerInternal.class);
final AssociationDiskStore associationDiskStore = new AssociationDiskStore();
mAssociationStore = new AssociationStore(context, userManager, associationDiskStore);
@@ -178,7 +176,7 @@ public class CompanionDeviceManagerService extends SystemService {
mDevicePresenceProcessor = new DevicePresenceProcessor(context,
mCompanionAppBinder, userManager, mAssociationStore, mObservableUuidStore,
- mPowerManagerInternal);
+ powerManagerInternal);
mTransportManager = new CompanionTransportManager(context, mAssociationStore);
@@ -252,11 +250,6 @@ public class CompanionDeviceManagerService extends SystemService {
private void onPackageRemoveOrDataClearedInternal(
@UserIdInt int userId, @NonNull String packageName) {
- if (DEBUG) {
- Log.i(TAG, "onPackageRemove_Or_DataCleared() u" + userId + "/"
- + packageName);
- }
-
// Clear all associations for the package.
final List<AssociationInfo> associationsForPackage =
mAssociationStore.getAssociationsByPackage(userId, packageName);
@@ -279,8 +272,6 @@ public class CompanionDeviceManagerService extends SystemService {
}
private void onPackageModifiedInternal(@UserIdInt int userId, @NonNull String packageName) {
- if (DEBUG) Log.i(TAG, "onPackageModified() u" + userId + "/" + packageName);
-
final List<AssociationInfo> associationsForPackage =
mAssociationStore.getAssociationsByPackage(userId, packageName);
for (AssociationInfo association : associationsForPackage) {
diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
index 253fe35a3e29..ac19d8bc897f 100644
--- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
+++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
@@ -161,20 +161,20 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
}
if (DEBUG) Log.d(TAG, "onBootPhase - PHASE_BOOT_COMPLETED");
-
- mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
init(getContext().getSystemService(MediaProjectionManager.class),
LocalServices.getService(WindowManagerInternal.class),
- getExemptedPackages());
+ LocalServices.getService(PackageManagerInternal.class),
+ getExemptedPackages()
+ );
if (sensitiveContentAppProtection()) {
publishBinderService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE,
- new SensitiveContentProtectionManagerServiceBinder(mPackageManagerInternal));
+ new SensitiveContentProtectionManagerServiceBinder());
}
}
@VisibleForTesting
void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager,
- ArraySet<String> exemptedPackages) {
+ PackageManagerInternal packageManagerInternal, ArraySet<String> exemptedPackages) {
if (DEBUG) Log.d(TAG, "init");
Objects.requireNonNull(projectionManager);
@@ -182,6 +182,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
mProjectionManager = projectionManager;
mWindowManager = windowManager;
+ mPackageManagerInternal = packageManagerInternal;
mExemptedPackages = exemptedPackages;
// TODO(b/317250444): use MediaProjectionManagerService directly, reduces unnecessary
@@ -231,14 +232,16 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
}
private void onProjectionStart(MediaProjectionInfo projectionInfo) {
- int uid = mPackageManagerInternal.getPackageUid(projectionInfo.getPackageName(), 0,
- projectionInfo.getUserHandle().getIdentifier());
boolean isPackageExempted = (mExemptedPackages != null && mExemptedPackages.contains(
projectionInfo.getPackageName()))
- || canRecordSensitiveContent(projectionInfo.getPackageName());
+ || canRecordSensitiveContent(projectionInfo.getPackageName())
+ || isAutofillServiceRecorderPackage(projectionInfo.getUserHandle().getIdentifier(),
+ projectionInfo.getPackageName());
// TODO(b/324447419): move GlobalSettings lookup to background thread
boolean isFeatureDisabled = Settings.Global.getInt(getContext().getContentResolver(),
DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0;
+ int uid = mPackageManagerInternal.getPackageUid(projectionInfo.getPackageName(), 0,
+ projectionInfo.getUserHandle().getIdentifier());
mMediaProjectionSession = new MediaProjectionSession(
uid, isPackageExempted || isFeatureDisabled, new Random().nextLong());
@@ -295,8 +298,9 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
// notify windowmanager of any currently posted sensitive content notifications
ArraySet<PackageInfo> packageInfos =
getSensitivePackagesFromNotifications(notifications, rankingMap);
-
- mWindowManager.addBlockScreenCaptureForApps(packageInfos);
+ if (packageInfos.size() > 0) {
+ mWindowManager.addBlockScreenCaptureForApps(packageInfos);
+ }
}
private ArraySet<PackageInfo> getSensitivePackagesFromNotifications(
@@ -422,6 +426,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
if (!mProjectionActive) {
return;
}
+
if (DEBUG) {
Log.d(TAG, "setSensitiveContentProtection - current package=" + packageInfo
+ ", isShowingSensitiveContent=" + isShowingSensitiveContent
@@ -452,15 +457,29 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
}
}
- private final class SensitiveContentProtectionManagerServiceBinder
- extends ISensitiveContentProtectionManager.Stub {
- private final PackageManagerInternal mPackageManagerInternal;
+ // TODO: b/328251279 - Autofill service exemption is temporary and will be removed in future.
+ private boolean isAutofillServiceRecorderPackage(int userId, String projectionPackage) {
+ String autofillServiceName = Settings.Secure.getStringForUser(
+ getContext().getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, userId);
+ if (DEBUG) {
+ Log.d(TAG, "autofill service for user " + userId + " is " + autofillServiceName);
+ }
- SensitiveContentProtectionManagerServiceBinder(
- PackageManagerInternal packageManagerInternal) {
- mPackageManagerInternal = packageManagerInternal;
+ if (autofillServiceName == null) {
+ return false;
+ }
+ ComponentName serviceComponent = ComponentName.unflattenFromString(autofillServiceName);
+ if (serviceComponent == null) {
+ return false;
}
+ String autofillServicePackage = serviceComponent.getPackageName();
+ return autofillServicePackage != null
+ && autofillServicePackage.equals(projectionPackage);
+ }
+
+ private final class SensitiveContentProtectionManagerServiceBinder
+ extends ISensitiveContentProtectionManager.Stub {
public void setSensitiveContentProtection(IBinder windowToken, String packageName,
boolean isShowingSensitiveContent) {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b00676a15c0d..47f03f3f16fa 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -414,6 +414,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BinderCallHeavyHitterWatcher.BinderCallHeavyHitterListener;
import com.android.internal.os.BinderCallHeavyHitterWatcher.HeavyHitterContainer;
import com.android.internal.os.BinderInternal;
+import com.android.internal.os.BinderInternal.BinderProxyCountEventListener;
import com.android.internal.os.BinderTransactionNameResolver;
import com.android.internal.os.ByteTransferPipe;
import com.android.internal.os.IResultReceiver;
@@ -614,8 +615,8 @@ public class ActivityManagerService extends IActivityManager.Stub
private static final int MINIMUM_MEMORY_GROWTH_THRESHOLD = 10 * 1000; // 10 MB
/**
- * The number of binder proxies we need to have before we start warning and
- * dumping debug info.
+ * The number of binder proxies we need to have before we start dumping debug info
+ * and kill the offenders.
*/
private static final int BINDER_PROXY_HIGH_WATERMARK = 6000;
@@ -625,6 +626,11 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
private static final int BINDER_PROXY_LOW_WATERMARK = 5500;
+ /**
+ * The number of binder proxies we need to have before we start warning.
+ */
+ private static final int BINDER_PROXY_WARNING_WATERMARK = 5750;
+
// Max character limit for a notification title. If the notification title is larger than this
// the notification will not be legible to the user.
private static final int MAX_BUGREPORT_TITLE_SIZE = 100;
@@ -8015,6 +8021,18 @@ public class ActivityManagerService extends IActivityManager.Stub
return uidRecord != null && !uidRecord.isSetIdle();
}
+ @Override
+ public long getUidLastIdleElapsedTime(int uid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "getUidLastIdleElapsedTime");
+ }
+ synchronized (mProcLock) {
+ final UidRecord uidRecord = mProcessList.getUidRecordLOSP(uid);
+ return uidRecord != null ? uidRecord.getRealLastIdleTime() : 0;
+ }
+ }
+
@GuardedBy("mUidFrozenStateChangedCallbackList")
private final RemoteCallbackList<IUidFrozenStateChangedCallback>
mUidFrozenStateChangedCallbackList = new RemoteCallbackList<>();
@@ -9051,34 +9069,10 @@ public class ActivityManagerService extends IActivityManager.Stub
t.traceBegin("setBinderProxies");
BinderInternal.nSetBinderProxyCountWatermarks(BINDER_PROXY_HIGH_WATERMARK,
- BINDER_PROXY_LOW_WATERMARK);
+ BINDER_PROXY_LOW_WATERMARK, BINDER_PROXY_WARNING_WATERMARK);
BinderInternal.nSetBinderProxyCountEnabled(true);
- BinderInternal.setBinderProxyCountCallback(
- (uid) -> {
- Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
- + Process.myUid());
- BinderProxy.dumpProxyDebugInfo();
- CriticalEventLog.getInstance().logExcessiveBinderCalls(uid);
- if (uid == Process.SYSTEM_UID) {
- Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
- } else {
- killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
- ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
- ApplicationExitInfo.SUBREASON_EXCESSIVE_BINDER_OBJECTS,
- "Too many Binders sent to SYSTEM");
- // We need to run a GC here, because killing the processes involved
- // actually isn't guaranteed to free up the proxies; in fact, if the
- // GC doesn't run for a long time, we may even exceed the global
- // proxy limit for a process (20000), resulting in system_server itself
- // being killed.
- // Note that the GC here might not actually clean up all the proxies,
- // because the binder reference decrements will come in asynchronously;
- // but if new processes belonging to the UID keep adding proxies, we
- // will get another callback here, and run the GC again - this time
- // cleaning up the old proxies.
- VMRuntime.getRuntime().requestConcurrentGC();
- }
- }, mHandler);
+ BinderInternal.setBinderProxyCountCallback(new MyBinderProxyCountEventListener(),
+ mHandler);
t.traceEnd(); // setBinderProxies
t.traceEnd(); // ActivityManagerStartApps
@@ -9093,6 +9087,46 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ private class MyBinderProxyCountEventListener implements BinderProxyCountEventListener {
+ @Override
+ public void onLimitReached(int uid) {
+ Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
+ + Process.myUid());
+ BinderProxy.dumpProxyDebugInfo();
+ CriticalEventLog.getInstance().logExcessiveBinderCalls(uid);
+ if (uid == Process.SYSTEM_UID) {
+ Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
+ } else {
+ killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
+ ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
+ ApplicationExitInfo.SUBREASON_EXCESSIVE_BINDER_OBJECTS,
+ "Too many Binders sent to SYSTEM");
+ // We need to run a GC here, because killing the processes involved
+ // actually isn't guaranteed to free up the proxies; in fact, if the
+ // GC doesn't run for a long time, we may even exceed the global
+ // proxy limit for a process (20000), resulting in system_server itself
+ // being killed.
+ // Note that the GC here might not actually clean up all the proxies,
+ // because the binder reference decrements will come in asynchronously;
+ // but if new processes belonging to the UID keep adding proxies, we
+ // will get another callback here, and run the GC again - this time
+ // cleaning up the old proxies.
+ VMRuntime.getRuntime().requestConcurrentGC();
+ }
+ }
+
+ @Override
+ public void onWarningThresholdReached(int uid) {
+ if (Flags.logExcessiveBinderProxies()) {
+ Slog.w(TAG, "Uid " + uid + " sent too many ("
+ + BINDER_PROXY_WARNING_WATERMARK + ") Binders to uid " + Process.myUid());
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.EXCESSIVE_BINDER_PROXY_COUNT_REPORTED,
+ uid);
+ }
+ }
+ }
+
private void watchDeviceProvisioning(Context context) {
// setting system property based on whether device is provisioned
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index df6481dc2c74..9c1ce666eddf 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -3681,7 +3681,7 @@ public class OomAdjuster {
for (int i = N - 1; i >= 0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
final long bgTime = uidRec.getLastBackgroundTime();
- final long idleTime = uidRec.getLastIdleTime();
+ final long idleTime = uidRec.getLastIdleTimeIfStillIdle();
if (bgTime > 0 && (!uidRec.isIdle() || idleTime == 0)) {
if (bgTime <= maxBgTime) {
EventLogTags.writeAmUidIdle(uidRec.getUid());
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 45fd470401e2..86fa0fccf774 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.Manifest;
+import android.annotation.ElapsedRealtimeLong;
import android.app.ActivityManager;
import android.content.pm.PackageManager;
import android.os.SystemClock;
@@ -65,8 +66,19 @@ public final class UidRecord {
@CompositeRWLock({"mService", "mProcLock"})
private long mLastBackgroundTime;
+ /**
+ * Last time the UID became idle. This is set to 0, once the UID becomes active.
+ */
+ @ElapsedRealtimeLong
@CompositeRWLock({"mService", "mProcLock"})
- private long mLastIdleTime;
+ private long mLastIdleTimeIfStillIdle;
+
+ /**
+ * Last time the UID became idle. Unlike {@link #mLastIdleTimeIfStillIdle}, we never clear it.
+ */
+ @ElapsedRealtimeLong
+ @CompositeRWLock({"mService", "mProcLock"})
+ private long mRealLastIdleTime;
@CompositeRWLock({"mService", "mProcLock"})
private boolean mEphemeral;
@@ -257,14 +269,28 @@ public final class UidRecord {
mLastBackgroundTime = lastBackgroundTime;
}
+ /**
+ * Last time the UID became idle. This is set to 0, once the UID becomes active.
+ */
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
+ long getLastIdleTimeIfStillIdle() {
+ return mLastIdleTimeIfStillIdle;
+ }
+
+ /**
+ * Last time the UID became idle. Unlike {@link #getLastIdleTimeIfStillIdle}, we never clear it.
+ */
@GuardedBy(anyOf = {"mService", "mProcLock"})
- long getLastIdleTime() {
- return mLastIdleTime;
+ long getRealLastIdleTime() {
+ return mRealLastIdleTime;
}
@GuardedBy({"mService", "mProcLock"})
- void setLastIdleTime(long lastActiveTime) {
- mLastIdleTime = lastActiveTime;
+ void setLastIdleTime(@ElapsedRealtimeLong long lastIdleTime) {
+ mLastIdleTimeIfStillIdle = lastIdleTime;
+ if (lastIdleTime > 0) {
+ mRealLastIdleTime = lastIdleTime;
+ }
}
@GuardedBy(anyOf = {"mService", "mProcLock"})
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 14f3120b60b6..7df63b1dab66 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -869,9 +869,7 @@ public class AuthService extends SystemService {
}
if (faceAidlInstances != null && faceAidlInstances.length > 0) {
- mFaceSensorConfigurations.addAidlConfigs(faceAidlInstances,
- name -> IFace.Stub.asInterface(Binder.allowBlocking(
- ServiceManager.waitForDeclaredService(name))));
+ mFaceSensorConfigurations.addAidlConfigs(faceAidlInstances);
}
if (faceService != null) {
@@ -909,9 +907,7 @@ public class AuthService extends SystemService {
}
if (fingerprintAidlInstances != null && fingerprintAidlInstances.length > 0) {
- mFingerprintSensorConfigurations.addAidlSensors(fingerprintAidlInstances,
- name -> IFingerprint.Stub.asInterface(Binder.allowBlocking(
- ServiceManager.waitForDeclaredService(name))));
+ mFingerprintSensorConfigurations.addAidlSensors(fingerprintAidlInstances);
}
if (fingerprintService != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 7ee2a7ababb3..1037124d7048 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -729,8 +729,8 @@ public class FaceService extends SystemService {
private List<ServiceProvider> getProviders(
FaceSensorConfigurations faceSensorConfigurations) {
final List<ServiceProvider> providers = new ArrayList<>();
- final Pair<String, SensorProps[]> filteredSensorProps =
- filterAvailableHalInstances(faceSensorConfigurations);
+ final Pair<String, SensorProps[]> filteredSensorProps = filterAvailableHalInstances(
+ faceSensorConfigurations);
providers.add(mFaceProviderFunction.getFaceProvider(filteredSensorProps,
faceSensorConfigurations.getResetLockoutRequiresChallenge()));
return providers;
@@ -739,28 +739,36 @@ public class FaceService extends SystemService {
@NonNull
private Pair<String, SensorProps[]> filterAvailableHalInstances(
FaceSensorConfigurations faceSensorConfigurations) {
- Pair<String, SensorProps[]> finalSensorPair = faceSensorConfigurations.getSensorPair();
+ String finalSensorInstance = faceSensorConfigurations.getSensorInstance();
if (faceSensorConfigurations.isSingleSensorConfigurationPresent()) {
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance,
+ faceSensorConfigurations.getSensorPropForInstance(finalSensorInstance));
}
-
- final Pair<String, SensorProps[]> virtualSensorProps = faceSensorConfigurations
- .getSensorPairForInstance("virtual");
-
- if (Utils.isVirtualEnabled(getContext())) {
- if (virtualSensorProps != null) {
- return virtualSensorProps;
+ final String virtualInstance = "virtual";
+ final boolean isVirtualHalPresent =
+ faceSensorConfigurations.doesInstanceExist(virtualInstance);
+ if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
+ if (isVirtualHalPresent) {
+ return new Pair<>(virtualInstance,
+ faceSensorConfigurations.getSensorPropForInstance(virtualInstance));
} else {
Slog.e(TAG, "Could not find virtual interface while it is enabled");
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance,
+ faceSensorConfigurations.getSensorPropForInstance(finalSensorInstance));
}
} else {
- if (virtualSensorProps != null) {
- return faceSensorConfigurations.getSensorPairNotForInstance("virtual");
+ if (isVirtualHalPresent) {
+ final String notAVirtualInstance =
+ faceSensorConfigurations.getSensorNameNotForInstance(virtualInstance);
+ if (notAVirtualInstance != null) {
+ return new Pair<>(notAVirtualInstance, faceSensorConfigurations
+ .getSensorPropForInstance(notAVirtualInstance));
+ }
}
}
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance, faceSensorConfigurations
+ .getSensorPropForInstance(finalSensorInstance));
}
private Pair<List<FaceSensorPropertiesInternal>, List<String>>
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 1ba12134ab29..2dc03ed94b6c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -1128,27 +1128,36 @@ public class FingerprintService extends SystemService {
@NonNull
private Pair<String, SensorProps[]> filterAvailableHalInstances(
FingerprintSensorConfigurations fingerprintSensorConfigurations) {
- Pair<String, SensorProps[]> finalSensorPair =
- fingerprintSensorConfigurations.getSensorPair();
+ final String finalSensorInstance = fingerprintSensorConfigurations.getSensorInstance();
if (fingerprintSensorConfigurations.isSingleSensorConfigurationPresent()) {
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance,
+ fingerprintSensorConfigurations.getSensorPropForInstance(finalSensorInstance));
}
-
- final Pair<String, SensorProps[]> virtualSensorPropsPair = fingerprintSensorConfigurations
- .getSensorPairForInstance("virtual");
+ final String virtualInstance = "virtual";
+ final boolean isVirtualHalPresent =
+ fingerprintSensorConfigurations.doesInstanceExist(virtualInstance);
if (Utils.isVirtualEnabled(getContext())) {
- if (virtualSensorPropsPair != null) {
- return virtualSensorPropsPair;
+ if (isVirtualHalPresent) {
+ return new Pair<>(virtualInstance,
+ fingerprintSensorConfigurations.getSensorPropForInstance(virtualInstance));
} else {
Slog.e(TAG, "Could not find virtual interface while it is enabled");
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance,
+ fingerprintSensorConfigurations.getSensorPropForInstance(
+ finalSensorInstance));
}
} else {
- if (virtualSensorPropsPair != null) {
- return fingerprintSensorConfigurations.getSensorPairNotForInstance("virtual");
+ if (isVirtualHalPresent) {
+ final String notAVirtualInstance = fingerprintSensorConfigurations
+ .getSensorNameNotForInstance(virtualInstance);
+ if (notAVirtualInstance != null) {
+ return new Pair<>(notAVirtualInstance, fingerprintSensorConfigurations
+ .getSensorPropForInstance(notAVirtualInstance));
+ }
}
}
- return finalSensorPair;
+ return new Pair<>(finalSensorInstance, fingerprintSensorConfigurations
+ .getSensorPropForInstance(finalSensorInstance));
}
private Pair<List<FingerprintSensorPropertiesInternal>, List<String>>
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ba21a327d837..434985e96d3e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -464,10 +464,11 @@ public final class DisplayManagerService extends SystemService {
// May be used outside of the lock but only on the handler thread.
private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
- // Pending callback records indexed by calling process uid.
+ // Pending callback records indexed by calling process uid and pid.
// Must be used outside of the lock mSyncRoot and should be selflocked.
@GuardedBy("mPendingCallbackSelfLocked")
- public final SparseArray<PendingCallback> mPendingCallbackSelfLocked = new SparseArray<>();
+ public final SparseArray<SparseArray<PendingCallback>> mPendingCallbackSelfLocked =
+ new SparseArray<>();
// Temporary viewports, used when sending new viewport information to the
// input system. May be used outside of the lock but only on the handler thread.
@@ -1011,8 +1012,8 @@ public final class DisplayManagerService extends SystemService {
}
// Do we care about this uid?
- PendingCallback pendingCallback = mPendingCallbackSelfLocked.get(uid);
- if (pendingCallback == null) {
+ SparseArray<PendingCallback> pendingCallbacks = mPendingCallbackSelfLocked.get(uid);
+ if (pendingCallbacks == null) {
return;
}
@@ -1020,7 +1021,12 @@ public final class DisplayManagerService extends SystemService {
if (DEBUG) {
Slog.d(TAG, "Uid " + uid + " becomes " + importance);
}
- pendingCallback.sendPendingDisplayEvent();
+ for (int i = 0; i < pendingCallbacks.size(); i++) {
+ PendingCallback pendingCallback = pendingCallbacks.valueAt(i);
+ if (pendingCallback != null) {
+ pendingCallback.sendPendingDisplayEvent();
+ }
+ }
mPendingCallbackSelfLocked.delete(uid);
}
}
@@ -3193,16 +3199,23 @@ public final class DisplayManagerService extends SystemService {
for (int i = 0; i < mTempCallbacks.size(); i++) {
CallbackRecord callbackRecord = mTempCallbacks.get(i);
final int uid = callbackRecord.mUid;
+ final int pid = callbackRecord.mPid;
if (isUidCached(uid)) {
// For cached apps, save the pending event until it becomes non-cached
synchronized (mPendingCallbackSelfLocked) {
- PendingCallback pendingCallback = mPendingCallbackSelfLocked.get(uid);
+ SparseArray<PendingCallback> pendingCallbacks = mPendingCallbackSelfLocked.get(
+ uid);
if (extraLogging(callbackRecord.mPackageName)) {
- Slog.i(TAG,
- "Uid is cached: " + uid + ", pendingCallback: " + pendingCallback);
+ Slog.i(TAG, "Uid is cached: " + uid
+ + ", pendingCallbacks: " + pendingCallbacks);
+ }
+ if (pendingCallbacks == null) {
+ pendingCallbacks = new SparseArray<>();
+ mPendingCallbackSelfLocked.put(uid, pendingCallbacks);
}
+ PendingCallback pendingCallback = pendingCallbacks.get(pid);
if (pendingCallback == null) {
- mPendingCallbackSelfLocked.put(uid,
+ pendingCallbacks.put(pid,
new PendingCallback(callbackRecord, displayId, event));
} else {
pendingCallback.addDisplayEvent(displayId, event);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fd3da85e4437..4da280bf5c7b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2446,7 +2446,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
ComponentName intentFilterVerifierComponent =
getIntentFilterVerifierComponentNameLPr(computer);
ComponentName domainVerificationAgent =
- getDomainVerificationAgentComponentNameLPr(computer);
+ getDomainVerificationAgentComponentNameLPr(computer, UserHandle.USER_SYSTEM);
DomainVerificationProxy domainVerificationProxy = DomainVerificationProxy.makeProxy(
intentFilterVerifierComponent, domainVerificationAgent, mContext,
@@ -2754,12 +2754,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
@Nullable
- private ComponentName getDomainVerificationAgentComponentNameLPr(@NonNull Computer computer) {
+ private ComponentName getDomainVerificationAgentComponentNameLPr(@NonNull Computer computer,
+ int userId) {
Intent intent = new Intent(Intent.ACTION_DOMAINS_NEED_VERIFICATION);
List<ResolveInfo> matches =
mResolveIntentHelper.queryIntentReceiversInternal(computer, intent, null,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
- UserHandle.USER_SYSTEM, Binder.getCallingUid());
+ userId, Binder.getCallingUid());
ResolveInfo best = null;
final int N = matches.size();
for (int i = 0; i < N; i++) {
@@ -2767,7 +2768,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final String packageName = cur.getComponentInfo().packageName;
if (checkPermission(
android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, packageName,
- UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
+ userId) != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Domain verification agent found but does not hold permission: "
+ packageName);
continue;
@@ -2775,7 +2776,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
if (best == null || cur.priority > best.priority) {
if (computer.isComponentEffectivelyEnabled(cur.getComponentInfo(),
- UserHandle.SYSTEM)) {
+ UserHandle.of(userId))) {
best = cur;
} else {
Slog.w(TAG, "Domain verification agent found but not enabled");
@@ -6512,13 +6513,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
@Nullable
- public ComponentName getDomainVerificationAgent() {
+ public ComponentName getDomainVerificationAgent(int userId) {
final int callerUid = Binder.getCallingUid();
if (!PackageManagerServiceUtils.isRootOrShell(callerUid)) {
throw new SecurityException("Not allowed to query domain verification agent");
}
final Computer snapshot = snapshotComputer();
- return getDomainVerificationAgentComponentNameLPr(snapshot);
+ return getDomainVerificationAgentComponentNameLPr(snapshot, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a9e1725ea9a0..59faf24aa77a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -4412,8 +4412,31 @@ class PackageManagerShellCommand extends ShellCommand {
private int runGetDomainVerificationAgent() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
+ int userId = UserHandle.USER_ALL;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) {
+ UserManagerInternal umi =
+ LocalServices.getService(UserManagerInternal.class);
+ UserInfo userInfo = umi.getUserInfo(userId);
+ if (userInfo == null) {
+ pw.println("Failure [user " + userId + " doesn't exist]");
+ return 1;
+ }
+ }
+ } else {
+ pw.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_SYSTEM, "runGetDomainVerificationAgent");
try {
- final ComponentName domainVerificationAgent = mInterface.getDomainVerificationAgent();
+ final ComponentName domainVerificationAgent =
+ mInterface.getDomainVerificationAgent(translatedUserId);
pw.println(domainVerificationAgent == null
? "No Domain Verifier available!" : domainVerificationAgent.flattenToString());
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f5ed8d4af45b..9f2c36a1c34a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -93,6 +93,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
@@ -911,8 +912,10 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
sharedUserSetting.mDisabledPackages.remove(p);
}
p.getPkgState().setUpdatedSystemApp(false);
+ final AndroidPackageInternal pkg = p.getPkg();
PackageSetting ret = addPackageLPw(name, p.getRealName(), p.getPath(), p.getAppId(),
- p.getFlags(), p.getPrivateFlags(), mDomainVerificationManager.generateNewId());
+ p.getFlags(), p.getPrivateFlags(), mDomainVerificationManager.generateNewId(),
+ pkg == null ? false : pkg.isSdkLibrary());
if (ret != null) {
ret.setLegacyNativeLibraryPath(p.getLegacyNativeLibraryPath());
ret.setPrimaryCpuAbi(p.getPrimaryCpuAbiLegacy());
@@ -951,8 +954,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
}
}
- PackageSetting addPackageLPw(String name, String realName, File codePath, int uid, int pkgFlags,
- int pkgPrivateFlags, @NonNull UUID domainSetId) {
+ PackageSetting addPackageLPw(String name, String realName, File codePath, int uid,
+ int pkgFlags, int pkgPrivateFlags, @NonNull UUID domainSetId, boolean isSdkLibrary) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.getAppId() == uid) {
@@ -964,7 +967,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
}
p = new PackageSetting(name, realName, codePath, pkgFlags, pkgPrivateFlags, domainSetId)
.setAppId(uid);
- if (mAppIds.registerExistingAppId(uid, p, name)) {
+ if ((uid == Process.INVALID_UID && isSdkLibrary && Flags.disallowSdkLibsToBeApps())
+ || mAppIds.registerExistingAppId(uid, p, name)) {
mPackages.put(name, p);
return p;
}
@@ -4176,7 +4180,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
} else if (appId > 0 || (appId == Process.INVALID_UID && isSdkLibrary
&& Flags.disallowSdkLibsToBeApps())) {
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
- appId, pkgFlags, pkgPrivateFlags, domainSetId);
+ appId, pkgFlags, pkgPrivateFlags, domainSetId, isSdkLibrary);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": appId="
+ appId + " pkg=" + packageSetting);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f5ac8306cfa9..63386a999d40 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -567,7 +567,7 @@ public class UserManagerService extends IUserManager.Stub {
int autoLockPreference =
Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER,
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
getMainUserIdUnchecked());
Slog.i(LOG_TAG, "Auto-lock settings changed to " + autoLockPreference);
setOrUpdateAutoLockPreferenceForPrivateProfile(autoLockPreference);
@@ -615,7 +615,7 @@ public class UserManagerService extends IUserManager.Stub {
int privateSpaceAutoLockPreference =
Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER,
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
getMainUserIdUnchecked());
if (privateSpaceAutoLockPreference
!= Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY) {
@@ -714,7 +714,7 @@ public class UserManagerService extends IUserManager.Stub {
if (isAutoLockForPrivateSpaceEnabled()) {
int autoLockPreference = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER,
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
getMainUserIdUnchecked());
boolean isAutoLockOnDeviceLockSelected =
autoLockPreference == Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK;
@@ -1052,7 +1052,8 @@ public class UserManagerService extends IUserManager.Stub {
setOrUpdateAutoLockPreferenceForPrivateProfile(
Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER, mainUserId));
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
+ mainUserId));
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c3175d64e2d3..318042e87387 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9030,7 +9030,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
void sendDeviceOwnerOrProfileOwnerCommand(String action, Bundle extras, int userId) {
if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
+ if (Flags.headlessDeviceOwnerDelegateSecurityLoggingBugFix()
+ && getHeadlessDeviceOwnerModeForDeviceOwner()
+ == HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER) {
+ userId = mOwners.getDeviceOwnerUserId();
+ } else {
+ userId = UserHandle.USER_SYSTEM;
+ }
}
boolean inForeground = false;
ComponentName receiverComponent = null;
diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java
index 2366f56707fa..7aafa8e92690 100644
--- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java
@@ -24,9 +24,11 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import android.content.pm.PackageManagerInternal;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Binder;
@@ -72,6 +74,7 @@ public class SensitiveContentProtectionManagerServiceContentTest {
@Mock private WindowManagerInternal mWindowManager;
@Mock private MediaProjectionManager mProjectionManager;
+ @Mock private PackageManagerInternal mPackageManagerInternal;
private MediaProjectionInfo mMediaProjectionInfo;
@Captor
@@ -91,7 +94,7 @@ public class SensitiveContentProtectionManagerServiceContentTest {
mSensitiveContentProtectionManagerService =
new SensitiveContentProtectionManagerService(mContext);
mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager,
- new ArraySet<>(Set.of(mExemptedScreenRecorderPackage)));
+ mPackageManagerInternal, new ArraySet<>(Set.of(mExemptedScreenRecorderPackage)));
verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any());
mMediaPorjectionCallback = mMediaProjectionCallbackCaptor.getValue();
mMediaProjectionInfo =
@@ -146,6 +149,20 @@ public class SensitiveContentProtectionManagerServiceContentTest {
}
@Test
+ public void testAutofillServicePackageExemption() {
+ String testAutofillService = mScreenRecorderPackage + "/com.example.SampleAutofillService";
+ int userId = Process.myUserHandle().getIdentifier();
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.AUTOFILL_SERVICE, testAutofillService , userId);
+
+ mMediaPorjectionCallback.onStart(mMediaProjectionInfo);
+ mSensitiveContentProtectionManagerService.setSensitiveContentProtection(
+ mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true);
+ verify(mWindowManager, never())
+ .addBlockScreenCaptureForApps(mPackageInfoCaptor.capture());
+ }
+
+ @Test
public void testDeveloperOptionDisableFeature() {
mockDisabledViaDeveloperOption();
mMediaProjectionCallbackCaptor.getValue().onStart(mMediaProjectionInfo);
diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
index e74fe296d0a5..506514469338 100644
--- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.content.pm.PackageManagerInternal;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -104,6 +105,9 @@ public class SensitiveContentProtectionManagerServiceNotificationTest {
private WindowManagerInternal mWindowManager;
@Mock
+ private PackageManagerInternal mPackageManagerInternal;
+
+ @Mock
private StatusBarNotification mNotification1;
@Mock
@@ -141,7 +145,7 @@ public class SensitiveContentProtectionManagerServiceNotificationTest {
setupSensitiveNotification();
mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager,
- new ArraySet<>(Set.of(EXEMPTED_SCREEN_RECORDER_PACKAGE)));
+ mPackageManagerInternal, new ArraySet<>(Set.of(EXEMPTED_SCREEN_RECORDER_PACKAGE)));
// Obtain useful mMediaProjectionCallback
verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any());
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 538c0ee52424..c9aab5318840 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -166,7 +166,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
null
}
whenever(mocks.settings.addPackageLPw(nullable(), nullable(), nullable(), nullable(),
- nullable(), nullable(), nullable())) {
+ nullable(), nullable(), nullable(), nullable())) {
val name: String = getArgument(0)
val pendingAdd = mPendingPackageAdds.firstOrNull { it.first == name }
?: return@whenever null
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 6aa1825ba6b7..759a974bd41f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -736,9 +736,10 @@ public final class UserManagerServiceTest {
Mockito.clearInvocations(mKeyguardManager);
Mockito.clearInvocations(mSpiedContext);
- // Finally, set the preference to don't auto-lock
+ // Finally, set the preference to auto-lock only after device restart, which is the default
+ // behaviour
mUms.setOrUpdateAutoLockPreferenceForPrivateProfile(
- Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER);
+ Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART);
// Verify that inactivity broadcasts are unregistered and keyguard listener was removed
Mockito.verify(mSpiedContext).unregisterReceiver(any());
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index f0dc5f0606f3..7e04277fddc0 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -269,7 +269,7 @@ public class AuthServiceTest {
mFingerprintSensorConfigurationsCaptor.capture());
final SensorProps[] fingerprintProp = mFingerprintSensorConfigurationsCaptor.getValue()
- .getSensorPairForInstance("defaultHIDL").second;
+ .getSensorPropForInstance("defaultHIDL");
assertEquals(fingerprintProp[0].commonProps.sensorId, fingerprintId);
assertEquals(fingerprintProp[0].commonProps.sensorStrength,
@@ -280,7 +280,7 @@ public class AuthServiceTest {
final android.hardware.biometrics.face.SensorProps[] faceProp =
mFaceSensorConfigurationsCaptor.getValue()
- .getSensorPairForInstance("defaultHIDL").second;
+ .getSensorPropForInstance("defaultHIDL");
assertEquals(faceProp[0].commonProps.sensorId, faceId);
assertEquals(faceProp[0].commonProps.sensorStrength,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
index 3aaac2e9cf1b..e015e97debb0 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
@@ -32,8 +32,6 @@ import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.IBiometricService;
-import android.hardware.biometrics.face.IFace;
-import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceSensorConfigurations;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -93,18 +91,12 @@ public class FaceServiceTest {
@Mock
private FaceProvider mFaceProviderVirtual;
@Mock
- private IFace mDefaultFaceDaemon;
- @Mock
- private IFace mVirtualFaceDaemon;
- @Mock
private IBiometricService mIBiometricService;
@Mock
private IBinder mToken;
@Mock
private IFaceServiceReceiver mFaceServiceReceiver;
- private final SensorProps mDefaultSensorProps = new SensorProps();
- private final SensorProps mVirtualSensorProps = new SensorProps();
private FaceService mFaceService;
private final FaceSensorPropertiesInternal mSensorPropsDefault =
new FaceSensorPropertiesInternal(ID_DEFAULT, STRENGTH_STRONG,
@@ -126,10 +118,6 @@ public class FaceServiceTest {
@Before
public void setUp() throws RemoteException {
- when(mDefaultFaceDaemon.getSensorProps()).thenReturn(
- new SensorProps[]{mDefaultSensorProps});
- when(mVirtualFaceDaemon.getSensorProps()).thenReturn(
- new SensorProps[]{mVirtualSensorProps});
when(mFaceProviderDefault.getSensorProperties()).thenReturn(List.of(mSensorPropsDefault));
when(mFaceProviderVirtual.getSensorProperties()).thenReturn(List.of(mSensorPropsVirtual));
when(mFaceProviderDefault.containsSensor(anyInt()))
@@ -140,15 +128,7 @@ public class FaceServiceTest {
mContext.getTestablePermissions().setPermission(
USE_BIOMETRIC_INTERNAL, PackageManager.PERMISSION_GRANTED);
mFaceSensorConfigurations = new FaceSensorConfigurations(false);
- mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_DEFAULT, NAME_VIRTUAL},
- (name) -> {
- if (name.equals(IFace.DESCRIPTOR + "/" + NAME_DEFAULT)) {
- return mDefaultFaceDaemon;
- } else if (name.equals(IFace.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
- return mVirtualFaceDaemon;
- }
- return null;
- });
+ mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_DEFAULT, NAME_VIRTUAL});
}
private void initService() {
@@ -199,15 +179,7 @@ public class FaceServiceTest {
@RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
public void registerAuthenticatorsLegacy_virtualAlwaysWhenNoOther() throws Exception {
mFaceSensorConfigurations = new FaceSensorConfigurations(false);
- mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_VIRTUAL},
- (name) -> {
- if (name.equals(IFace.DESCRIPTOR + "/" + NAME_DEFAULT)) {
- return mDefaultFaceDaemon;
- } else if (name.equals(IFace.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
- return mVirtualFaceDaemon;
- }
- return null;
- });
+ mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_VIRTUAL});
initService();
mFaceService.mServiceWrapper.registerAuthenticatorsLegacy(mFaceSensorConfigurations);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
index 88956b614eae..20961a9ddddd 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
@@ -43,8 +43,6 @@ import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.hardware.biometrics.IBiometricService;
-import android.hardware.biometrics.fingerprint.IFingerprint;
-import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.FingerprintSensorConfigurations;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -123,10 +121,6 @@ public class FingerprintServiceTest {
private IBinder mToken;
@Mock
private VirtualDeviceManagerInternal mVdmInternal;
- @Mock
- private IFingerprint mDefaultFingerprintDaemon;
- @Mock
- private IFingerprint mVirtualFingerprintDaemon;
@Captor
private ArgumentCaptor<FingerprintAuthenticateOptions> mAuthenticateOptionsCaptor;
@@ -145,8 +139,6 @@ public class FingerprintServiceTest {
false /* resetLockoutRequiresHardwareAuthToken */);
private FingerprintSensorConfigurations mFingerprintSensorConfigurations;
private FingerprintService mService;
- private final SensorProps mDefaultSensorProps = new SensorProps();
- private final SensorProps mVirtualSensorProps = new SensorProps();
@Before
public void setup() throws Exception {
@@ -159,10 +151,6 @@ public class FingerprintServiceTest {
.thenAnswer(i -> i.getArguments()[0].equals(ID_DEFAULT));
when(mFingerprintVirtual.containsSensor(anyInt()))
.thenAnswer(i -> i.getArguments()[0].equals(ID_VIRTUAL));
- when(mDefaultFingerprintDaemon.getSensorProps()).thenReturn(
- new SensorProps[]{mDefaultSensorProps});
- when(mVirtualFingerprintDaemon.getSensorProps()).thenReturn(
- new SensorProps[]{mVirtualSensorProps});
mContext.addMockSystemService(AppOpsManager.class, mAppOpsManager);
for (int permission : List.of(OP_USE_BIOMETRIC, OP_USE_FINGERPRINT)) {
@@ -177,15 +165,7 @@ public class FingerprintServiceTest {
mFingerprintSensorConfigurations = new FingerprintSensorConfigurations(
true /* resetLockoutRequiresHardwareAuthToken */);
- mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_DEFAULT, NAME_VIRTUAL},
- (name) -> {
- if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_DEFAULT)) {
- return mDefaultFingerprintDaemon;
- } else if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
- return mVirtualFingerprintDaemon;
- }
- return null;
- });
+ mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_DEFAULT, NAME_VIRTUAL});
}
private void initServiceWith(String... aidlInstances) {
@@ -270,15 +250,7 @@ public class FingerprintServiceTest {
public void registerAuthenticatorsLegacy_virtualAlwaysWhenNoOther() throws Exception {
mFingerprintSensorConfigurations =
new FingerprintSensorConfigurations(true);
- mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_VIRTUAL},
- (name) -> {
- if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_DEFAULT)) {
- return mDefaultFingerprintDaemon;
- } else if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
- return mVirtualFingerprintDaemon;
- }
- return null;
- });
+ mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_VIRTUAL});
initServiceWith(NAME_VIRTUAL);
mService.mServiceWrapper.registerAuthenticatorsLegacy(mFingerprintSensorConfigurations);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ed3d5d546f72..ebdd556428b5 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -8013,6 +8013,27 @@ public class CarrierConfigManager {
KEY_SCAN_LIMITED_SERVICE_AFTER_VOLTE_FAILURE_BOOL =
KEY_PREFIX + "scan_limited_service_after_volte_failure_bool";
+ /**
+ * This config defines {@link ImsReasonInfo} code with which the emergency call
+ * shall be retried.
+ *
+ * <p>
+ * If the reason code is one of the following, the emergency call shall be retried
+ * regardless of this configuration.
+ * <ul>
+ * <li>{@link ImsReasonInfo#CODE_LOCAL_CALL_CS_RETRY_REQUIRED}</li>
+ * <li>{@link ImsReasonInfo#CODE_LOCAL_NOT_REGISTERED}</li>
+ * <li>{@link ImsReasonInfo#CODE_SIP_ALTERNATE_EMERGENCY_CALL}</li>
+ * </ul>
+ * <p>
+ *
+ * This config is empty by default.
+ *
+ * @hide
+ */
+ public static final String KEY_IMS_REASONINFO_CODE_TO_RETRY_EMERGENCY_INT_ARRAY =
+ KEY_PREFIX + "ims_reasoninfo_code_to_retry_emergency_int_array";
+
private static PersistableBundle getDefaults() {
PersistableBundle defaults = new PersistableBundle();
defaults.putBoolean(KEY_RETRY_EMERGENCY_ON_IMS_PDN_BOOL, false);
@@ -8085,6 +8106,8 @@ public class CarrierConfigManager {
defaults.putBoolean(KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL,
true);
defaults.putBoolean(KEY_SCAN_LIMITED_SERVICE_AFTER_VOLTE_FAILURE_BOOL, false);
+ defaults.putIntArray(KEY_IMS_REASONINFO_CODE_TO_RETRY_EMERGENCY_INT_ARRAY,
+ new int[0]);
return defaults;
}
@@ -9836,7 +9859,7 @@ public class CarrierConfigManager {
* An integer key holds the time interval for refreshing or re-querying the satellite
* entitlement status from the entitlement server to ensure it is the latest.
*
- * The default value is 30 days (1 month).
+ * The default value is 7 days.
*/
@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
public static final String KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT =
@@ -11008,7 +11031,7 @@ public class CarrierConfigManager {
CellSignalStrengthLte.USE_RSRP);
sDefaults.putBoolean(KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
sDefaults.putBoolean(KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL, true);
- sDefaults.putInt(KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT, 30);
+ sDefaults.putInt(KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT, 7);
sDefaults.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false);
sDefaults.putString(KEY_SATELLITE_ENTITLEMENT_APP_NAME_STRING, "androidSatmode");
sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index 5a0f742372d7..1d3e4bd531b4 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/Android.bp
@@ -39,7 +39,7 @@ android_test {
"androidx.test.core",
"frameworks-base-testutils",
"guava",
- "mockito-target-minus-junit4",
+ "mockito-target-extended-minus-junit4",
"truth",
],
@@ -48,6 +48,12 @@ android_test {
"android.test.base",
],
+ // Required by Extended Mockito
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+
test_suites: [
"general-tests",
],
diff --git a/wifi/tests/AndroidManifest.xml b/wifi/tests/AndroidManifest.xml
index 18986fc5c603..66056e5cab38 100644
--- a/wifi/tests/AndroidManifest.xml
+++ b/wifi/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.net.wifi.nonupdatable.test">
- <application>
+ <application android:debuggable="true">
<uses-library android:name="android.test.runner"/>
<activity android:label="WifiTestDummyLabel"
android:name="WifiTestDummyName"