summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/Android.bp75
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl5
-rw-r--r--core/java/android/companion/virtual/sensor/VirtualSensor.java2
-rw-r--r--core/java/android/companion/virtual/sensor/VirtualSensorAdditionalInfo.java35
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java28
-rw-r--r--core/java/android/hardware/display/DisplayTopology.java55
-rw-r--r--core/java/android/os/BatteryStats.java17
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/view/SurfaceControl.java13
-rw-r--r--core/java/android/window/DesktopExperienceFlags.java1
-rw-r--r--core/java/android/window/DesktopModeFlags.java12
-rw-r--r--core/java/android/window/TaskSnapshot.java20
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig29
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistory.java92
-rw-r--r--core/res/res/xml/sms_short_codes.xml2
-rw-r--r--data/etc/Android.bp8
-rw-r--r--data/etc/com.android.statementservice.xml23
-rw-r--r--data/etc/privapp-permissions-platform.xml6
-rw-r--r--libs/WindowManager/Shell/Android.bp8
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/IHomeTransitionListener.aidl6
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/ContextUtils.kt (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ContextUtils.kt)2
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java49
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java46
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java81
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java24
-rw-r--r--libs/androidfw/LocaleDataLookup.cpp2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp9
-rw-r--r--media/java/android/media/flags/media_better_together.aconfig7
-rw-r--r--packages/InputDevices/res/raw/keyboard_layout_hungarian.kcm8
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java32
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt20
-rw-r--r--packages/SettingsLib/ValuePreference/Android.bp31
-rw-r--r--packages/SettingsLib/ValuePreference/AndroidManifest.xml23
-rw-r--r--packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference.xml45
-rw-r--r--packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference_text_frame.xml49
-rw-r--r--packages/SettingsLib/ValuePreference/res/values/styles.xml23
-rw-r--r--packages/SettingsLib/ValuePreference/src/com/android/settingslib/widget/ValuePreference.kt44
-rw-r--r--packages/SettingsLib/res/values/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java33
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/StatementService/Android.bp4
-rw-r--r--packages/SystemUI/aconfig/accessibility.aconfig10
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt16
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt11
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt4
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt9
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt20
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt11
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt4
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt15
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java54
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt110
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt64
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java35
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt78
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt41
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java45
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java29
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt3
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt3
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt119
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java103
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java90
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java64
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt89
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCaseExt.kt34
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProviderKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt3
-rw-r--r--ravenwood/tools/hoststubgen/README.md59
-rw-r--r--ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt2
-rw-r--r--ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt4
-rw-r--r--ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt12
-rw-r--r--ravenwood/tools/hoststubgen/test-tiny-framework/README.md21
-rw-r--r--services/Android.bp13
-rw-r--r--services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java26
-rw-r--r--services/art-profile-extra1
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java7
-rw-r--r--services/core/java/com/android/server/am/AppProfiler.java2
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java50
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java119
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java70
-rw-r--r--services/core/java/com/android/server/appop/AppOpsUidStateTracker.java13
-rw-r--r--services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java37
-rw-r--r--services/core/java/com/android/server/display/DisplayTopologyCoordinator.java26
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java26
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayWindow.java11
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerInternal.java7
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java12
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java35
-rw-r--r--services/core/java/com/android/server/pm/UserManagerInternal.java15
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java8
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java3
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java4
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java4
-rw-r--r--services/core/java/com/android/server/power/ThermalManagerService.java47
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java9
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryHistoryStepDetailsProvider.java276
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryStatsImpl.java217
-rw-r--r--services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java62
-rw-r--r--services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionShellCommand.java26
-rw-r--r--services/core/java/com/android/server/wm/AbsAppSnapshotController.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivitySnapshotCache.java1
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java17
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java30
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java6
-rw-r--r--services/core/java/com/android/server/wm/SnapshotCache.java8
-rw-r--r--services/core/java/com/android/server/wm/SnapshotController.java36
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotCache.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java247
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTransitionCallbackTest.java260
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java109
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryHistoryStepDetailsProviderTest.java163
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java63
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java19
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java2
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java4
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MockPowerStatsInternal.java198
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java5
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java3
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/processor/WakelockPowerStatsProcessorTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java62
-rw-r--r--services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java29
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java33
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java29
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java27
-rw-r--r--tools/protologtool/Android.bp6
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt2
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt71
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt25
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt6
-rw-r--r--tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt43
-rw-r--r--tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt43
-rw-r--r--tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt24
182 files changed, 3741 insertions, 1732 deletions
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 980d9737aba7..7123ee7b5777 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -17,19 +17,19 @@ aidl_library {
filegroup {
name: "framework-core-sources",
srcs: [
- "**/*.java",
"**/*.aidl",
- ":systemfeatures-gen-srcs",
+ "**/*.java",
":framework-nfc-non-updatable-sources",
":messagequeue-gen",
":ranging_stack_mock_initializer",
+ ":systemfeatures-gen-srcs",
],
// Exactly one MessageQueue.java will be added to srcs by messagequeue-gen
exclude_srcs: [
+ "**/*_ravenwood.java",
+ ":dynamic_instrumentation_manager_aidl_sources",
"android/os/*MessageQueue/**/*.java",
"android/ranging/**/*.java",
- ":dynamic_instrumentation_manager_aidl_sources",
- "**/*_ravenwood.java",
],
visibility: ["//frameworks/base"],
}
@@ -52,9 +52,9 @@ soong_config_module_type {
"release_ranging_stack",
],
properties: [
- "srcs",
"cmd",
"out",
+ "srcs",
],
}
@@ -153,9 +153,9 @@ filegroup {
filegroup {
name: "framework-core-sources-for-test-mock",
srcs: [
+ "android/accounts/AccountManager.java",
"android/accounts/AccountManagerCallback.java",
"android/accounts/AccountManagerFuture.java",
- "android/accounts/AccountManager.java",
"android/accounts/AccountsException.java",
"android/accounts/AuthenticatorException.java",
"android/accounts/OperationCanceledException.java",
@@ -163,8 +163,8 @@ filegroup {
"android/app/IApplicationThread.aidl",
"android/app/IServiceConnection.aidl",
"android/app/PackageDeleteObserver.java",
- "android/content/ComponentCallbacks2.java",
"android/content/ComponentCallbacks.java",
+ "android/content/ComponentCallbacks2.java",
"android/content/ContentInterface.java",
"android/content/ContentProvider.java",
"android/content/ContentProviderNative.java",
@@ -178,8 +178,8 @@ filegroup {
"android/content/OperationApplicationException.java",
"android/content/pm/ActivityInfo.java",
"android/content/pm/ApplicationInfo.java",
- "android/content/pm/InstantAppInfo.java",
"android/content/pm/IPackageDataObserver.aidl",
+ "android/content/pm/InstantAppInfo.java",
"android/content/pm/KeySet.java",
"android/content/pm/PackageManager.java",
"android/content/pm/VerifierDeviceIdentity.java",
@@ -192,8 +192,8 @@ filegroup {
"android/os/Bundle.java",
"android/os/IBinder.java",
"android/os/IInterface.java",
- "android/os/Parcelable.java",
"android/os/ParcelFileDescriptor.java",
+ "android/os/Parcelable.java",
"android/os/RemoteException.java",
"android/os/storage/VolumeInfo.java",
"android/util/AndroidException.java",
@@ -215,24 +215,24 @@ filegroup {
filegroup {
name: "libvibrator_aidl",
srcs: [
+ "android/os/ExternalVibrationScale.aidl",
"android/os/IExternalVibrationController.aidl",
"android/os/IExternalVibratorService.aidl",
- "android/os/ExternalVibrationScale.aidl",
],
}
filegroup {
name: "libpowermanager_aidl",
srcs: [
- "android/os/Temperature.aidl",
"android/os/CoolingDevice.aidl",
+ "android/os/IPowerManager.aidl",
+ "android/os/IScreenTimeoutPolicyListener.aidl",
"android/os/IThermalEventListener.aidl",
"android/os/IThermalHeadroomListener.aidl",
- "android/os/IThermalStatusListener.aidl",
"android/os/IThermalService.aidl",
- "android/os/IPowerManager.aidl",
+ "android/os/IThermalStatusListener.aidl",
"android/os/IWakeLockCallback.aidl",
- "android/os/IScreenTimeoutPolicyListener.aidl",
+ "android/os/Temperature.aidl",
],
}
@@ -282,8 +282,8 @@ genrule {
java_library {
name: "uieventloggerlib",
srcs: [
- "com/android/internal/logging/UiEventLoggerImpl.java",
":statslog-framework-java-gen",
+ "com/android/internal/logging/UiEventLoggerImpl.java",
],
libs: [
"androidx.annotation_annotation",
@@ -353,11 +353,11 @@ filegroup {
name: "framework-permission-s-shared-srcs",
srcs: [
":modules-utils-preconditions-srcs",
- "com/android/internal/infra/AndroidFuture.java",
- "com/android/internal/infra/ServiceConnector.java",
+ "android/os/HandlerExecutor.java",
"com/android/internal/infra/AndroidFuture.aidl",
+ "com/android/internal/infra/AndroidFuture.java",
"com/android/internal/infra/IAndroidFuture.aidl",
- "android/os/HandlerExecutor.java",
+ "com/android/internal/infra/ServiceConnector.java",
],
}
@@ -393,10 +393,10 @@ filegroup {
"android/content/pm/FileSystemControlParcel.aidl",
"android/content/pm/IDataLoader.aidl",
"android/content/pm/IDataLoaderManager.aidl",
- "android/content/pm/InstallationFileParcel.aidl",
- "android/content/pm/InstallationFileLocation.aidl",
"android/content/pm/IDataLoaderStatusListener.aidl",
"android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl",
+ "android/content/pm/InstallationFileLocation.aidl",
+ "android/content/pm/InstallationFileParcel.aidl",
],
}
@@ -404,9 +404,9 @@ filegroup {
name: "incremental_manager_aidl",
srcs: [
"android/os/incremental/IIncrementalService.aidl",
+ "android/os/incremental/IStorageHealthListener.aidl",
"android/os/incremental/IStorageLoadingProgressListener.aidl",
"android/os/incremental/IncrementalNewFileParams.aidl",
- "android/os/incremental/IStorageHealthListener.aidl",
"android/os/incremental/PerUidReadTimeouts.aidl",
"android/os/incremental/StorageHealthCheckParams.aidl",
],
@@ -422,15 +422,15 @@ filegroup {
filegroup {
name: "hwbinder-stubs-srcs",
srcs: [
- "android/os/HidlSupport.java",
+ "android/os/DeadObjectException.java",
+ "android/os/DeadSystemException.java",
"android/os/HidlMemory.java",
+ "android/os/HidlSupport.java",
"android/os/HwBinder.java",
"android/os/HwBlob.java",
"android/os/HwParcel.java",
"android/os/IHwBinder.java",
"android/os/IHwInterface.java",
- "android/os/DeadObjectException.java",
- "android/os/DeadSystemException.java",
"android/os/NativeHandle.java",
"android/os/RemoteException.java",
"android/util/AndroidException.java",
@@ -444,12 +444,12 @@ filegroup {
cc_defaults {
name: "incremental_default",
cflags: [
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
"-Wall",
+ "-Werror",
"-Wextra",
"-Wextra-semi",
- "-Werror",
"-Wzero-as-null-pointer-constant",
- "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
],
shared_libs: [
"libbinder",
@@ -489,8 +489,8 @@ cc_library {
],
defaults: ["incremental_default"],
shared_libs: [
- "libincremental_aidl-cpp",
"libdataloader_aidl-cpp",
+ "libincremental_aidl-cpp",
],
}
@@ -580,8 +580,8 @@ filegroup {
filegroup {
name: "framework-telephony-common-shared-srcs",
srcs: [
- "android/os/RegistrantList.java",
"android/os/Registrant.java",
+ "android/os/RegistrantList.java",
"android/util/IndentingPrintWriter.java",
"android/util/LocalLog.java",
"android/util/TimeUtils.java",
@@ -599,8 +599,8 @@ filegroup {
name: "framework-ims-common-shared-srcs",
srcs: [
":modules-utils-preconditions-srcs",
- "android/os/RegistrantList.java",
"android/os/Registrant.java",
+ "android/os/RegistrantList.java",
"com/android/internal/os/SomeArgs.java",
],
}
@@ -609,9 +609,9 @@ filegroup {
filegroup {
name: "framework-core-sources-for-fuzzers",
srcs: [
- "android/os/IInterface.java",
"android/os/Binder.java",
"android/os/IBinder.java",
+ "android/os/IInterface.java",
"android/os/Parcelable.java",
],
}
@@ -657,6 +657,17 @@ filegroup {
}
java_library {
+ name: "protolog-common-lib",
+ srcs: [
+ ":protolog-common-src",
+ ],
+ host_supported: true,
+ static_libs: [
+ "framework-annotations-lib",
+ ],
+}
+
+java_library {
name: "protolog-group",
srcs: [
"com/android/internal/protolog/common/IProtoLogGroup.java",
@@ -694,7 +705,9 @@ java_library {
name: "protolog-groups",
srcs: [
"com/android/internal/protolog/WmProtoLogGroups.java",
- ":protolog-common-src",
+ ],
+ static_libs: [
+ "protolog-common-lib",
],
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 01b2953362b5..6c6709bb2b47 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -369,6 +369,11 @@ interface IActivityTaskManager {
in RemoteCallback navigationObserver, in BackAnimationAdapter adaptor);
/**
+ * Registers a callback to be invoked when the system server requests a back gesture.
+ */
+ void registerBackGestureDelegate(in RemoteCallback monitor);
+
+ /**
* registers a callback to be invoked when a background activity launch is aborted.
*
* @param observer callback to be registered.
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensor.java b/core/java/android/companion/virtual/sensor/VirtualSensor.java
index 8d4acfcb30d7..7f228ab37f21 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensor.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensor.java
@@ -174,7 +174,7 @@ public final class VirtualSensor implements Parcelable {
@FlaggedApi(Flags.FLAG_VIRTUAL_SENSOR_ADDITIONAL_INFO)
public void sendAdditionalInfo(@NonNull VirtualSensorAdditionalInfo info) {
if (!Flags.virtualSensorAdditionalInfo()) {
- return;
+ throw new UnsupportedOperationException("Sensor additional info not supported.");
}
if ((mFlags & VirtualSensorConfig.ADDITIONAL_INFO_MASK) == 0) {
throw new UnsupportedOperationException("Sensor additional info not supported.");
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorAdditionalInfo.java b/core/java/android/companion/virtual/sensor/VirtualSensorAdditionalInfo.java
index a4fca507b1d5..0f1a2989b808 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensorAdditionalInfo.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorAdditionalInfo.java
@@ -90,6 +90,7 @@ public final class VirtualSensorAdditionalInfo implements Parcelable {
*
* @see SensorAdditionalInfo#type
*/
+ @VirtualSensorAdditionalInfo.Type
public int getType() {
return mType;
}
@@ -114,6 +115,21 @@ public final class VirtualSensorAdditionalInfo implements Parcelable {
@NonNull
private final ArrayList<float[]> mValues = new ArrayList<>();
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_SAMPLING} */
+ private static final int TYPE_SAMPLING_PLAYLOAD_SIZE = 2;
+
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_UNTRACKED_DELAY} */
+ private static final int TYPE_UNTRACKED_DELAY_PAYLOAD_SIZE = 2;
+
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_INTERNAL_TEMPERATURE} */
+ private static final int TYPE_INTERNAL_TEMPERATURE_PLAYLOAD_SIZE = 1;
+
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_VEC3_CALIBRATION} */
+ private static final int TYPE_VEC3_CALIBRATION_PAYLOAD_SIZE = 12;
+
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_SENSOR_PLACEMENT} */
+ private static final int TYPE_SENSOR_PLACEMENT_PAYLOAD_SIZE = 12;
+
/**
* Creates a new builder.
*
@@ -135,28 +151,31 @@ public final class VirtualSensorAdditionalInfo implements Parcelable {
}
/**
- * Additional info payload data represented in float values. Depending on the type of
- * information, this may be null.
+ * Additional info payload data represented in float values.
*
+ * @param values the float values of this additional info frame.
+ * @throws IllegalArgumentException if the payload size doesn't match the expectation
+ * for the given type, as documented in {@link SensorAdditionalInfo}.
* @see SensorAdditionalInfo#floatValues
*/
@NonNull
public Builder addValues(@NonNull float[] values) {
- if (values.length > 14) {
- throw new IllegalArgumentException("Maximum payload value size is 14.");
- }
if (mValues.isEmpty()) {
switch (mType) {
case SensorAdditionalInfo.TYPE_UNTRACKED_DELAY:
+ assertValuesLength(values, TYPE_UNTRACKED_DELAY_PAYLOAD_SIZE);
+ break;
case SensorAdditionalInfo.TYPE_SAMPLING:
- assertValuesLength(values, 2);
+ assertValuesLength(values, TYPE_SAMPLING_PLAYLOAD_SIZE);
break;
case SensorAdditionalInfo.TYPE_INTERNAL_TEMPERATURE:
- assertValuesLength(values, 1);
+ assertValuesLength(values, TYPE_INTERNAL_TEMPERATURE_PLAYLOAD_SIZE);
break;
case SensorAdditionalInfo.TYPE_VEC3_CALIBRATION:
+ assertValuesLength(values, TYPE_VEC3_CALIBRATION_PAYLOAD_SIZE);
+ break;
case SensorAdditionalInfo.TYPE_SENSOR_PLACEMENT:
- assertValuesLength(values, 11);
+ assertValuesLength(values, TYPE_SENSOR_PLACEMENT_PAYLOAD_SIZE);
break;
}
} else if (values.length != mValues.getFirst().length) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 210653bb41e5..63c819eb8233 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -5198,12 +5198,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* </tr>
* <tr>
* <td style="text-align: center;">PRIV</td>
- * <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">PRIV</td>
- * <td style="text-align: center;">UHD</td>
- * </tr>
- * <tr>
- * <td style="text-align: center;">PRIV</td>
* <td style="text-align: center;">S720P</td>
* <td style="text-align: center;">JPEG/JPEG_R</td>
* <td style="text-align: center;">MAXIMUM_16_9</td>
@@ -5271,28 +5265,36 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* </thead>
* <tbody>
* <tr>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Preview</td>
* <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Video</td>
* <td style="text-align: center;">S1080P</td>
* <td style="text-align: center;"></td>
* <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Preview</td>
* <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Video</td>
* <td style="text-align: center;">S1440P</td>
* <td style="text-align: center;"></td>
* <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Preview</td>
* <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">PRIV Video</td>
+ * <td style="text-align: center;">UHD</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV Preview</td>
* <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;">YUV Analysis</td>
* <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Video</td>
+ * <td style="text-align: center;">1080P</td>
* </tr>
* </tbody>
* </table>
diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java
index c3c8c3d63bec..aae09e6f4c01 100644
--- a/core/java/android/hardware/display/DisplayTopology.java
+++ b/core/java/android/hardware/display/DisplayTopology.java
@@ -169,7 +169,23 @@ public final class DisplayTopology implements Parcelable {
* @hide
*/
public void addDisplay(int displayId, float width, float height) {
- addDisplay(displayId, width, height, /* shouldLog= */ true);
+ if (findDisplay(displayId, mRoot) != null) {
+ return;
+ }
+ if (mRoot == null) {
+ mRoot = new TreeNode(displayId, width, height, POSITION_LEFT, /* offset= */ 0);
+ mPrimaryDisplayId = displayId;
+ } else if (mRoot.mChildren.isEmpty()) {
+ // This is the 2nd display. Align the middles of the top and bottom edges.
+ float offset = mRoot.mWidth / 2 - width / 2;
+ TreeNode display = new TreeNode(displayId, width, height, POSITION_TOP, offset);
+ mRoot.mChildren.add(display);
+ } else {
+ TreeNode rightMostDisplay = findRightMostDisplay(mRoot, mRoot.mWidth).first;
+ TreeNode newDisplay = new TreeNode(displayId, width, height, POSITION_RIGHT,
+ /* offset= */ 0);
+ rightMostDisplay.mChildren.add(newDisplay);
+ }
}
/**
@@ -216,7 +232,7 @@ public final class DisplayTopology implements Parcelable {
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
if (node.mDisplayId != displayId) {
- addDisplay(node.mDisplayId, node.mWidth, node.mHeight, /* shouldLog= */ false);
+ addDisplay(node.mDisplayId, node.mWidth, node.mHeight);
}
queue.addAll(node.mChildren);
}
@@ -227,10 +243,6 @@ public final class DisplayTopology implements Parcelable {
} else {
mPrimaryDisplayId = Display.INVALID_DISPLAY;
}
- Slog.i(TAG, "Primary display with ID " + displayId
- + " removed, new primary display: " + mPrimaryDisplayId);
- } else {
- Slog.i(TAG, "Display with ID " + displayId + " removed");
}
return true;
}
@@ -598,37 +610,6 @@ public final class DisplayTopology implements Parcelable {
return out.toString();
}
- private void addDisplay(int displayId, float width, float height, boolean shouldLog) {
- if (findDisplay(displayId, mRoot) != null) {
- return;
- }
- if (mRoot == null) {
- mRoot = new TreeNode(displayId, width, height, POSITION_LEFT, /* offset= */ 0);
- mPrimaryDisplayId = displayId;
- if (shouldLog) {
- Slog.i(TAG, "First display added: " + mRoot);
- }
- } else if (mRoot.mChildren.isEmpty()) {
- // This is the 2nd display. Align the middles of the top and bottom edges.
- float offset = mRoot.mWidth / 2 - width / 2;
- TreeNode display = new TreeNode(displayId, width, height, POSITION_TOP, offset);
- mRoot.mChildren.add(display);
- if (shouldLog) {
- Slog.i(TAG, "Second display added: " + display + ", parent ID: "
- + mRoot.mDisplayId);
- }
- } else {
- TreeNode rightMostDisplay = findRightMostDisplay(mRoot, mRoot.mWidth).first;
- TreeNode newDisplay = new TreeNode(displayId, width, height, POSITION_RIGHT,
- /* offset= */ 0);
- rightMostDisplay.mChildren.add(newDisplay);
- if (shouldLog) {
- Slog.i(TAG, "Display added: " + newDisplay + ", parent ID: "
- + rightMostDisplay.mDisplayId);
- }
- }
- }
-
/**
* @param display The display from which the search should start.
* @param xPos The x position of the right edge of that display.
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 71d79bb32807..cc1dee7a5747 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1780,7 +1780,7 @@ public abstract class BatteryStats {
out.writeInt(statIrqTime);
out.writeInt(statSoftIrqTime);
out.writeInt(statIdlTime);
- out.writeString(statSubsystemPowerState);
+ out.writeString8(statSubsystemPowerState);
}
public void readFromParcel(Parcel in) {
@@ -1801,7 +1801,15 @@ public abstract class BatteryStats {
statIrqTime = in.readInt();
statSoftIrqTime = in.readInt();
statIdlTime = in.readInt();
- statSubsystemPowerState = in.readString();
+ statSubsystemPowerState = in.readString8();
+ }
+
+
+ public boolean isEmpty() {
+ return userTime == 0 && systemTime == 0 && appCpuUid1 == Process.INVALID_UID
+ && appCpuUid2 == Process.INVALID_UID && appCpuUid3 == Process.INVALID_UID
+ && statSystemTime == 0 && statIOWaitTime == 0 && statIrqTime == 0
+ && statSoftIrqTime == 0 && statIdlTime == 0 && statSubsystemPowerState == null;
}
}
@@ -2238,6 +2246,7 @@ public abstract class BatteryStats {
tagsFirstOccurrence = false;
powerStats = null;
processStateChange = null;
+ stepDetails = null;
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -2289,6 +2298,7 @@ public abstract class BatteryStats {
currentTime = o.currentTime;
powerStats = o.powerStats;
processStateChange = o.processStateChange;
+ stepDetails = o.stepDetails;
}
public boolean sameNonEvent(HistoryItem o) {
@@ -7318,7 +7328,8 @@ public abstract class BatteryStats {
}
item.append(", SubsystemPowerState ");
- item.append(rec.stepDetails.statSubsystemPowerState);
+ item.append(rec.stepDetails.statSubsystemPowerState != null
+ ? rec.stepDetails.statSubsystemPowerState : "Empty");
item.append("\n");
} else {
item.append(BATTERY_STATS_CHECKIN_VERSION); item.append(',');
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b7e296228e45..e7bca1419418 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13317,10 +13317,18 @@ public final class Settings {
public static final String CONTEXTUAL_SEARCH_PACKAGE = "contextual_search_package";
/**
- * Inetger property which determines whether advanced protection is on or not.
+ * Integer property which determines whether advanced protection is on or not.
* @hide
*/
public static final String ADVANCED_PROTECTION_MODE = "advanced_protection_mode";
+
+ /**
+ * Integer property which determines whether advanced protection USB data protection
+ * feature is on or not.
+ *
+ * @hide
+ */
+ public static final String AAPM_USB_DATA_PROTECTION = "aapm_usb_data_protection";
}
/**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index c4347f05f4a3..c7ae3283c46c 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -28,6 +28,7 @@ import static android.view.SurfaceControlProto.NAME;
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.DurationNanosLong;
import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
@@ -469,9 +470,9 @@ public final class SurfaceControl implements Parcelable {
private final long mFrameVsyncId;
private final @JankType int mJankType;
- private final long mFrameIntervalNs;
- private final long mScheduledAppFrameTimeNs;
- private final long mActualAppFrameTimeNs;
+ private final @DurationNanosLong long mFrameIntervalNs;
+ private final @DurationNanosLong long mScheduledAppFrameTimeNs;
+ private final @DurationNanosLong long mActualAppFrameTimeNs;
/**
* @hide
@@ -512,7 +513,7 @@ public final class SurfaceControl implements Parcelable {
* @return the frame interval in ns
* @hide
*/
- public long getFrameIntervalNanos() {
+ public @DurationNanosLong long getFrameIntervalNanos() {
return mFrameIntervalNs;
}
@@ -525,7 +526,7 @@ public final class SurfaceControl implements Parcelable {
*
* @return scheduled app time in ns
*/
- public long getScheduledAppFrameTimeNanos() {
+ public @DurationNanosLong long getScheduledAppFrameTimeNanos() {
return mScheduledAppFrameTimeNs;
}
@@ -534,7 +535,7 @@ public final class SurfaceControl implements Parcelable {
*
* @return the actual app time in ns
*/
- public long getActualAppFrameTimeNanos() {
+ public @DurationNanosLong long getActualAppFrameTimeNanos() {
return mActualAppFrameTimeNs;
}
diff --git a/core/java/android/window/DesktopExperienceFlags.java b/core/java/android/window/DesktopExperienceFlags.java
index 5e8ce5ee557f..04e6c68859c9 100644
--- a/core/java/android/window/DesktopExperienceFlags.java
+++ b/core/java/android/window/DesktopExperienceFlags.java
@@ -64,6 +64,7 @@ public enum DesktopExperienceFlags {
ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX(Flags::enableDynamicRadiusComputationBugfix, false),
ENABLE_KEYBOARD_SHORTCUTS_TO_SWITCH_DESKS(Flags::keyboardShortcutsToSwitchDesks, false),
ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT(Flags::enableMoveToNextDisplayShortcut, true),
+ ENABLE_MULTIDISPLAY_TRACKPAD_BACK_GESTURE(Flags::enableMultidisplayTrackpadBackGesture, false),
ENABLE_MULTIPLE_DESKTOPS_BACKEND(Flags::enableMultipleDesktopsBackend, false),
ENABLE_MULTIPLE_DESKTOPS_FRONTEND(Flags::enableMultipleDesktopsFrontend, false),
ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS(
diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java
index d5120ffb4de6..9b3d6242b213 100644
--- a/core/java/android/window/DesktopModeFlags.java
+++ b/core/java/android/window/DesktopModeFlags.java
@@ -66,16 +66,16 @@ public enum DesktopModeFlags {
ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX(
Flags::enableDesktopIndicatorInSeparateThreadBugfix, false),
ENABLE_DESKTOP_OPENING_DEEPLINK_MINIMIZE_ANIMATION_BUGFIX(
- Flags::enableDesktopOpeningDeeplinkMinimizeAnimationBugfix, false),
+ Flags::enableDesktopOpeningDeeplinkMinimizeAnimationBugfix, true),
ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX(
- Flags::enableDesktopRecentsTransitionsCornersBugfix, false),
+ Flags::enableDesktopRecentsTransitionsCornersBugfix, true),
ENABLE_DESKTOP_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE_BUGFIX(
Flags::skipCompatUiEducationInDesktopMode, true),
ENABLE_DESKTOP_SYSTEM_DIALOGS_TRANSITIONS(Flags::enableDesktopSystemDialogsTransitions, true),
ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX(
- Flags::enableDesktopTabTearingMinimizeAnimationBugfix, false),
+ Flags::enableDesktopTabTearingMinimizeAnimationBugfix, true),
ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX(
- Flags::enableDesktopTrampolineCloseAnimationBugfix, false),
+ Flags::enableDesktopTrampolineCloseAnimationBugfix, true),
ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER(
Flags::enableDesktopWallpaperActivityForSystemUser, true),
ENABLE_DESKTOP_WINDOWING_APP_TO_WEB(Flags::enableDesktopWindowingAppToWeb, true),
@@ -107,7 +107,7 @@ public enum DesktopModeFlags {
true),
ENABLE_DRAG_RESIZE_SET_UP_IN_BG_THREAD(Flags::enableDragResizeSetUpInBgThread, true),
ENABLE_DRAG_TO_DESKTOP_INCOMING_TRANSITIONS_BUGFIX(
- Flags::enableDragToDesktopIncomingTransitionsBugfix, false),
+ Flags::enableDragToDesktopIncomingTransitionsBugfix, true),
ENABLE_FULLY_IMMERSIVE_IN_DESKTOP(Flags::enableFullyImmersiveInDesktop, true),
ENABLE_HANDLE_INPUT_FIX(Flags::enableHandleInputFix, true),
ENABLE_HOLD_TO_DRAG_APP_HANDLE(Flags::enableHoldToDragAppHandle, true),
@@ -134,7 +134,7 @@ public enum DesktopModeFlags {
ENABLE_TOP_VISIBLE_ROOT_TASK_PER_USER_TRACKING(Flags::enableTopVisibleRootTaskPerUserTracking,
true),
ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX(
- Flags::enableVisualIndicatorInTransitionBugfix, false),
+ Flags::enableVisualIndicatorInTransitionBugfix, true),
ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, true),
ENABLE_WINDOWING_EDGE_DRAG_RESIZE(Flags::enableWindowingEdgeDragResize, true),
ENABLE_WINDOWING_SCALED_RESIZING(Flags::enableWindowingScaledResizing, true),
diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java
index 53c64bd6e664..4ddd73319840 100644
--- a/core/java/android/window/TaskSnapshot.java
+++ b/core/java/android/window/TaskSnapshot.java
@@ -37,6 +37,7 @@ import com.android.window.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.function.Consumer;
/**
* Represents a task snapshot.
@@ -76,6 +77,7 @@ public class TaskSnapshot implements Parcelable {
// Must be one of the named color spaces, otherwise, always use SRGB color space.
private final ColorSpace mColorSpace;
private int mInternalReferences;
+ private Consumer<HardwareBuffer> mSafeSnapshotReleaser;
/** Keep in cache, doesn't need reference. */
public static final int REFERENCE_NONE = 0;
@@ -365,8 +367,24 @@ public class TaskSnapshot implements Parcelable {
mInternalReferences &= ~usage;
if (Flags.releaseSnapshotAggressively() && mInternalReferences == 0 && mSnapshot != null
&& !mSnapshot.isClosed()) {
- mSnapshot.close();
+ if (mSafeSnapshotReleaser != null) {
+ mSafeSnapshotReleaser.accept(mSnapshot);
+ } else {
+ mSnapshot.close();
+ }
+ }
+ }
+
+ /**
+ * Register a safe release callback, instead of immediately closing the hardware buffer when
+ * no more reference, to let the system server decide when to close it.
+ * Only used in core.
+ */
+ public synchronized void setSafeRelease(Consumer<HardwareBuffer> releaser) {
+ if (!Flags.safeReleaseSnapshotAggressively()) {
+ return;
}
+ mSafeSnapshotReleaser = releaser;
}
public static final @NonNull Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 8dd0457248a4..59dd32258d8c 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -516,6 +516,17 @@ flag {
}
flag {
+ name: "safe_release_snapshot_aggressively"
+ namespace: "windowing_frontend"
+ description: "Protect task snapshot memory from premature release, which can occur when a local variable holds a reference while the snapshot is removed from the cache."
+ bug: "238206323"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "scramble_snapshot_file_name"
namespace: "windowing_frontend"
description: "Scramble the file name of task snapshot."
@@ -524,4 +535,22 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "delegate_back_gesture_to_shell"
+ namespace: "windowing_frontend"
+ description: "Delegate back gesture event to back animation controller."
+ bug: "394599430"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "enable_multidisplay_trackpad_back_gesture"
+ namespace: "lse_desktop_experience"
+ description: "Adds support for trackpad back gestures on connected displays"
+ bug: "382774299"
} \ No newline at end of file
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index f1c47a7a023b..3fc74c9f1f54 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -79,7 +79,7 @@ public class BatteryStatsHistory {
private static final String TAG = "BatteryStatsHistory";
// Current on-disk Parcel version. Must be updated when the format of the parcelable changes
- private static final int VERSION = 213;
+ private static final int VERSION = 214;
// Part of initial delta int that specifies the time delta.
static final int DELTA_TIME_MASK = 0x7ffff;
@@ -316,7 +316,6 @@ public class BatteryStatsHistory {
}
private final Parcel mHistoryBuffer;
- private final HistoryStepDetailsCalculator mStepDetailsCalculator;
private final Clock mClock;
private int mMaxHistoryBufferSize;
@@ -337,25 +336,6 @@ public class BatteryStatsHistory {
*/
private List<Parcel> mHistoryParcels = null;
- /**
- * When iterating history files, the current file index.
- */
- private BatteryHistoryFragment mCurrentFragment;
-
- /**
- * When iterating history files, the current file parcel.
- */
- private Parcel mCurrentParcel;
- /**
- * When iterating history file, the current parcel's Parcel.dataSize().
- */
- private int mCurrentParcelEnd;
- /**
- * Used when BatteryStatsImpl object is created from deserialization of a parcel,
- * such as Settings app or checkin file, to iterate over history parcels.
- */
- private int mParcelIndex = 0;
-
private final ReentrantLock mWriteLock = new ReentrantLock();
private final HistoryItem mHistoryCur = new HistoryItem();
@@ -384,28 +364,11 @@ public class BatteryStatsHistory {
// Monotonically increasing size of written history
private long mMonotonicHistorySize;
private final ArraySet<PowerStats.Descriptor> mWrittenPowerStatsDescriptors = new ArraySet<>();
- private byte mLastHistoryStepLevel = 0;
private boolean mMutable = true;
private int mIteratorCookie;
private final BatteryStatsHistory mWritableHistory;
/**
- * A delegate responsible for computing additional details for a step in battery history.
- */
- public interface HistoryStepDetailsCalculator {
- /**
- * Returns additional details for the current history step or null.
- */
- @Nullable
- HistoryStepDetails getHistoryStepDetails();
-
- /**
- * Resets the calculator to get ready for a new battery session
- */
- void clear();
- }
-
- /**
* A delegate for android.os.Trace to allow testing static calls. Due to
* limitations in Android Tracing (b/153319140), the delegate also records
* counter values in system properties which allows reading the value at the
@@ -472,21 +435,17 @@ public class BatteryStatsHistory {
* @param maxHistoryBufferSize the most amount of RAM to used for buffering of history steps
*/
public BatteryStatsHistory(Parcel historyBuffer, int maxHistoryBufferSize,
- @Nullable BatteryHistoryStore store, HistoryStepDetailsCalculator stepDetailsCalculator,
- Clock clock, MonotonicClock monotonicClock, TraceDelegate tracer,
- EventLogger eventLogger) {
- this(historyBuffer, maxHistoryBufferSize, store,
- stepDetailsCalculator,
- clock, monotonicClock, tracer, eventLogger, null);
+ @Nullable BatteryHistoryStore store, Clock clock, MonotonicClock monotonicClock,
+ TraceDelegate tracer, EventLogger eventLogger) {
+ this(historyBuffer, maxHistoryBufferSize, store, clock, monotonicClock, tracer, eventLogger,
+ null);
}
private BatteryStatsHistory(@Nullable Parcel historyBuffer, int maxHistoryBufferSize,
- @Nullable BatteryHistoryStore store,
- @NonNull HistoryStepDetailsCalculator stepDetailsCalculator, @NonNull Clock clock,
+ @Nullable BatteryHistoryStore store, @NonNull Clock clock,
@NonNull MonotonicClock monotonicClock, @NonNull TraceDelegate tracer,
@NonNull EventLogger eventLogger, @Nullable BatteryStatsHistory writableHistory) {
mMaxHistoryBufferSize = maxHistoryBufferSize;
- mStepDetailsCalculator = stepDetailsCalculator;
mTracer = tracer;
mClock = clock;
mMonotonicClock = monotonicClock;
@@ -527,7 +486,6 @@ public class BatteryStatsHistory {
mClock = Clock.SYSTEM_CLOCK;
mTracer = null;
mStore = null;
- mStepDetailsCalculator = null;
mEventLogger = new EventLogger();
mWritableHistory = null;
mMutable = false;
@@ -556,9 +514,6 @@ public class BatteryStatsHistory {
mNextHistoryTagIdx = 0;
mNumHistoryTagChars = 0;
mHistoryBufferLastPos = -1;
- if (mStepDetailsCalculator != null) {
- mStepDetailsCalculator.clear();
- }
}
/**
@@ -596,7 +551,7 @@ public class BatteryStatsHistory {
Parcel historyBufferCopy = Parcel.obtain();
historyBufferCopy.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
- return new BatteryStatsHistory(historyBufferCopy, 0, mStore, null,
+ return new BatteryStatsHistory(historyBufferCopy, 0, mStore,
null, null, null, mEventLogger, this);
}
} finally {
@@ -712,10 +667,6 @@ public class BatteryStatsHistory {
if (mStore != null) {
mStore.lock();
}
- mCurrentFragment = null;
- mCurrentParcel = null;
- mCurrentParcelEnd = 0;
- mParcelIndex = 0;
BatteryStatsHistoryIterator iterator = new BatteryStatsHistoryIterator(
this, startTimeMs, endTimeMs);
mIteratorCookie = System.identityHashCode(iterator);
@@ -1614,6 +1565,21 @@ public class BatteryStatsHistory {
}
/**
+ * Records an update containing HistoryStepDetails, except if the details are empty.
+ */
+ public void recordHistoryStepDetails(HistoryStepDetails details, long elapsedRealtimeMs,
+ long uptimeMs) {
+ if (details.isEmpty()) {
+ return;
+ }
+ synchronized (this) {
+ mHistoryCur.stepDetails = details;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ mHistoryCur.stepDetails = null;
+ }
+ }
+
+ /**
* Writes the current history item to history.
*/
public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) {
@@ -1632,8 +1598,8 @@ public class BatteryStatsHistory {
mHistoryAddTmp.processStateChange = null;
mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
+ mHistoryAddTmp.stepDetails = null;
writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
-
}
}
mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
@@ -1952,15 +1918,8 @@ public class BatteryStatsHistory {
}
int firstToken = deltaTimeToken | (cur.states & BatteryStatsHistory.DELTA_STATE_MASK);
- if (cur.batteryLevel < mLastHistoryStepLevel || mLastHistoryStepLevel == 0) {
- cur.stepDetails = mStepDetailsCalculator.getHistoryStepDetails();
- if (cur.stepDetails != null) {
- batteryLevelInt |= BatteryStatsHistory.BATTERY_LEVEL_DETAILS_FLAG;
- mLastHistoryStepLevel = cur.batteryLevel;
- }
- } else {
- cur.stepDetails = null;
- mLastHistoryStepLevel = cur.batteryLevel;
+ if (cur.stepDetails != null) {
+ batteryLevelInt |= BatteryStatsHistory.BATTERY_LEVEL_DETAILS_FLAG;
}
final boolean batteryLevelIntChanged = batteryLevelInt != 0;
@@ -2055,6 +2014,7 @@ public class BatteryStatsHistory {
+ Integer.toHexString(cur.states2));
}
}
+ cur.tagsFirstOccurrence = false;
if (cur.wakelockTag != null || cur.wakeReasonTag != null) {
int wakeLockIndex;
int wakeReasonIndex;
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 9b3a6cba5f23..36564cd90d05 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -358,7 +358,7 @@
<!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm),
visual voicemail code for T-Mobile: 122 -->
- <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245|611611|96831|10907" />
+ <shortcode country="us" pattern="\\d{5,6}" free="122|\\d{5,6}" />
<!--Uruguay : 1-6 digits (standard system default, not country specific) -->
<shortcode country="uy" pattern="\\d{1,6}" free="55002|191289" />
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 8f85617acae3..98278f4529ff 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -184,6 +184,14 @@ prebuilt_etc {
}
prebuilt_etc {
+ name: "privapp_whitelist_com.android.statementservice",
+ system_ext_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.statementservice.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "privapp_whitelist_com.android.settings.intelligence",
product_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.statementservice.xml b/data/etc/com.android.statementservice.xml
new file mode 100644
index 000000000000..e102af206395
--- /dev/null
+++ b/data/etc/com.android.statementservice.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.statementservice">
+ <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
+ <permission name="android.permission.DOMAIN_VERIFICATION_AGENT"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 9234902335c1..1dd0465f691e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -623,12 +623,6 @@ applications that come with the platform
<permission name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE"/>
</privapp-permissions>
- <privapp-permissions package="com.android.statementservice">
- <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
- <permission name="android.permission.DOMAIN_VERIFICATION_AGENT"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.soundpicker">
<permission name="android.permission.INTERACT_ACROSS_USERS" />
</privapp-permissions>
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index bcb6c4f555f7..033c934056d6 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -26,9 +26,11 @@ package {
java_library {
name: "wm_shell_protolog-groups",
srcs: [
- ":protolog-common-src",
"src/com/android/wm/shell/protolog/ShellProtoLogGroup.java",
],
+ static_libs: [
+ "protolog-common-lib",
+ ],
}
filegroup {
@@ -159,12 +161,12 @@ java_library {
android_library {
name: "WindowManager-Shell",
srcs: [
- ":wm_shell_protolog_src",
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
- "src/com/android/wm/shell/EventLogTags.logtags",
":wm_shell-aidls",
":wm_shell-shared-aidls",
":wm_shell-sources-kt",
+ ":wm_shell_protolog_src",
+ "src/com/android/wm/shell/EventLogTags.logtags",
],
resource_dirs: [
"res",
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/IHomeTransitionListener.aidl b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/IHomeTransitionListener.aidl
index 8481c446c6aa..8dcda53b602b 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/IHomeTransitionListener.aidl
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/IHomeTransitionListener.aidl
@@ -18,6 +18,7 @@ package com.android.wm.shell.shared;
import android.window.RemoteTransition;
import android.window.TransitionFilter;
+import android.view.InsetsState;
/**
* Listener interface that Launcher attaches to SystemUI to get home activity transition callbacks
@@ -29,5 +30,10 @@ oneway interface IHomeTransitionListener {
* Called when a transition changes the visibility of the home activity on the default display.
*/
void onHomeVisibilityChanged(in boolean isVisible);
+
+ /**
+ * Called when the insets at display-level change.
+ */
+ void onDisplayInsetsChanged(in InsetsState insets);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ContextUtils.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/ContextUtils.kt
index 0b36f452348a..27db5297b758 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ContextUtils.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/ContextUtils.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.bubbles
+package com.android.wm.shell.shared.bubbles
import android.content.Context
import android.view.View
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index e5a4cd034e72..a9224b02ad31 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -451,6 +451,6 @@ public class DesktopModeStatus {
pw.println(maxTaskLimitHandle == null ? "null" : maxTaskLimitHandle.getInt(/* def= */ -1));
pw.print(innerPrefix); pw.print("showAppHandle config override=");
- pw.print(overridesShowAppHandle(context));
+ pw.println(overridesShowAppHandle(context));
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
index 8e78686ac13d..8e3dc4c36c1d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
@@ -66,7 +66,7 @@ public class SizeChangeAnimation {
* The maximum of stretching applied to any surface during interpolation (since the animation
* is a combination of stretching/cropping/fading).
*/
- private static final float SCALE_FACTOR = 0.7f;
+ private static final float DEFAULT_SCALE_FACTOR = 0.7f;
/**
* Since this animation is made of several sub-animations, we want to pre-arrange the
@@ -82,13 +82,27 @@ public class SizeChangeAnimation {
*/
private static final int ANIMATION_RESOLUTION = 1000;
+ /**
+ * Initialize a size-change animation from start to end bounds
+ */
public SizeChangeAnimation(Rect startBounds, Rect endBounds) {
- this(startBounds, endBounds, 1f);
+ this(startBounds, endBounds, 1f, DEFAULT_SCALE_FACTOR);
}
- public SizeChangeAnimation(Rect startBounds, Rect endBounds, float initialScale) {
- mAnimation = buildContainerAnimation(startBounds, endBounds, initialScale);
- mSnapshotAnim = buildSnapshotAnimation(startBounds, endBounds);
+ /**
+ * Initialize a size-change animation from start to end bounds.
+ * <p>
+ * Allows specifying the initial scale factor, {@code initialScale}, that is applied to the
+ * start bounds. This can be useful for example when a task is scaled down when the size change
+ * animation starts.
+ * <p>
+ * By default the max scale applied to any surface is {@link #DEFAULT_SCALE_FACTOR}. Use
+ * {@code scaleFactor} to override it.
+ */
+ public SizeChangeAnimation(Rect startBounds, Rect endBounds, float initialScale,
+ float scaleFactor) {
+ mAnimation = buildContainerAnimation(startBounds, endBounds, initialScale, scaleFactor);
+ mSnapshotAnim = buildSnapshotAnimation(startBounds, endBounds, scaleFactor);
}
/**
@@ -172,15 +186,15 @@ public class SizeChangeAnimation {
/** Animation for the whole container (snapshot is inside this container). */
private static AnimationSet buildContainerAnimation(Rect startBounds, Rect endBounds,
- float initialScale) {
+ float initialScale, float scaleFactor) {
final long duration = ANIMATION_RESOLUTION;
boolean growing = endBounds.width() - startBounds.width()
+ endBounds.height() - startBounds.height() >= 0;
- long scalePeriod = (long) (duration * SCALE_FACTOR);
- float startScaleX = SCALE_FACTOR * ((float) startBounds.width()) / endBounds.width()
- + (1.f - SCALE_FACTOR);
- float startScaleY = SCALE_FACTOR * ((float) startBounds.height()) / endBounds.height()
- + (1.f - SCALE_FACTOR);
+ long scalePeriod = (long) (duration * scaleFactor);
+ float startScaleX = scaleFactor * ((float) startBounds.width()) / endBounds.width()
+ + (1.f - scaleFactor);
+ float startScaleY = scaleFactor * ((float) startBounds.height()) / endBounds.height()
+ + (1.f - scaleFactor);
final AnimationSet animSet = new AnimationSet(true);
final Animation scaleAnim = new ScaleAnimation(startScaleX, 1, startScaleY, 1);
@@ -218,15 +232,16 @@ public class SizeChangeAnimation {
}
/** The snapshot surface is assumed to be a child of the container surface. */
- private static AnimationSet buildSnapshotAnimation(Rect startBounds, Rect endBounds) {
+ private static AnimationSet buildSnapshotAnimation(Rect startBounds, Rect endBounds,
+ float scaleFactor) {
final long duration = ANIMATION_RESOLUTION;
boolean growing = endBounds.width() - startBounds.width()
+ endBounds.height() - startBounds.height() >= 0;
- long scalePeriod = (long) (duration * SCALE_FACTOR);
- float endScaleX = 1.f / (SCALE_FACTOR * ((float) startBounds.width()) / endBounds.width()
- + (1.f - SCALE_FACTOR));
- float endScaleY = 1.f / (SCALE_FACTOR * ((float) startBounds.height()) / endBounds.height()
- + (1.f - SCALE_FACTOR));
+ long scalePeriod = (long) (duration * scaleFactor);
+ float endScaleX = 1.f / (scaleFactor * ((float) startBounds.width()) / endBounds.width()
+ + (1.f - scaleFactor));
+ float endScaleY = 1.f / (scaleFactor * ((float) startBounds.height()) / endBounds.height()
+ + (1.f - scaleFactor));
AnimationSet snapAnimSet = new AnimationSet(true);
// Animation for the "old-state" snapshot that is atop the task.
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 81cf031994a2..746632f67725 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
@@ -286,6 +286,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
this::createExternalInterface, this);
mShellCommandHandler.addDumpCallback(this::dump, this);
mShellController.addConfigurationChangeListener(this);
+ registerBackGestureDelegate();
}
public BackAnimation getBackAnimationImpl() {
@@ -1144,6 +1145,32 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mBackAnimationAdapter = new BackAnimationAdapter(runner);
}
+ private void registerBackGestureDelegate() {
+ if (!Flags.delegateBackGestureToShell()) {
+ return;
+ }
+ final RemoteCallback requestBackMonitor = new RemoteCallback(
+ new RemoteCallback.OnResultListener() {
+ @Override
+ public void onResult(@Nullable Bundle result) {
+ mShellExecutor.execute(() -> {
+ if (mBackGestureStarted) {
+ Log.w(TAG, "Back gesture is running, ignore request");
+ return;
+ }
+ onMotionEvent(0, 0, KeyEvent.ACTION_DOWN, EDGE_NONE);
+ setTriggerBack(true);
+ onMotionEvent(0, 0, KeyEvent.ACTION_UP, EDGE_NONE);
+ });
+ }
+ });
+ try {
+ mActivityTaskManager.registerBackGestureDelegate(requestBackMonitor);
+ } catch (RemoteException remoteException) {
+ Log.w(TAG, "Failed register back gesture request ", remoteException);
+ }
+ }
+
/**
* Description of current BackAnimationController state.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 81eff6f7399a..70fa48cca0b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -120,6 +120,7 @@ import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation.UpdateSource;
import com.android.wm.shell.shared.bubbles.BubbleBarUpdate;
import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider;
+import com.android.wm.shell.shared.bubbles.ContextUtils;
import com.android.wm.shell.shared.bubbles.DeviceConfig;
import com.android.wm.shell.shared.draganddrop.DragAndDropConstants;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 3dce45690cf2..4900b6fc77ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -94,6 +94,7 @@ import com.android.wm.shell.shared.TypefaceUtils.FontFamily;
import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
+import com.android.wm.shell.shared.bubbles.ContextUtils;
import com.android.wm.shell.shared.bubbles.DeviceConfig;
import com.android.wm.shell.shared.bubbles.DismissView;
import com.android.wm.shell.shared.bubbles.RelativeTouchListener;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index fa22a3961002..b89bfd5c969e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -596,11 +596,11 @@ public class BubbleBarAnimationHelper {
final Size size = getExpandedViewSize();
Point position = getExpandedViewRestPosition(size);
- final SizeChangeAnimation sca =
- new SizeChangeAnimation(
- new Rect(origBounds.left - position.x, origBounds.top - position.y,
- origBounds.right - position.x, origBounds.bottom - position.y),
- new Rect(0, 0, size.getWidth(), size.getHeight()), origScale);
+ Rect startBounds = new Rect(origBounds.left - position.x, origBounds.top - position.y,
+ origBounds.right - position.x, origBounds.bottom - position.y);
+ Rect endBounds = new Rect(0, 0, size.getWidth(), size.getHeight());
+ final SizeChangeAnimation sca = new SizeChangeAnimation(startBounds, endBounds,
+ origScale, /* scaleFactor= */ 1f);
sca.initialize(bbev, taskLeash, snapshot, startT);
Animator a = sca.buildViewAnimator(bbev, tvSf, snapshot, /* onFinish */ (va) -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index f62fd819319e..b3c25d495002 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -762,6 +762,7 @@ public abstract class WMShellBaseModule {
ShellTaskOrganizer organizer,
TransactionPool pool,
DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
@ShellAnimationThread ShellExecutor animExecutor,
@@ -773,15 +774,19 @@ public abstract class WMShellBaseModule {
shellInit = new ShellInit(mainExecutor);
}
return new Transitions(context, shellInit, shellCommandHandler, shellController, organizer,
- pool, displayController, mainExecutor, mainHandler, animExecutor,
- rootTaskDisplayAreaOrganizer, homeTransitionObserver, focusTransitionObserver);
+ pool, displayController, displayInsetsController, mainExecutor, mainHandler,
+ animExecutor, rootTaskDisplayAreaOrganizer, homeTransitionObserver,
+ focusTransitionObserver);
}
@WMSingleton
@Provides
static HomeTransitionObserver provideHomeTransitionObserver(Context context,
- @ShellMainThread ShellExecutor mainExecutor) {
- return new HomeTransitionObserver(context, mainExecutor);
+ @ShellMainThread ShellExecutor mainExecutor,
+ DisplayInsetsController displayInsetsController,
+ ShellInit shellInit) {
+ return new HomeTransitionObserver(context, mainExecutor, displayInsetsController,
+ shellInit);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java
index ce98b03b77a6..bff08ba6d88f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java
@@ -42,9 +42,10 @@ public class DefaultSurfaceAnimator {
@NonNull Animation anim, @NonNull SurfaceControl leash,
@NonNull Runnable finishCallback, @NonNull TransactionPool pool,
@NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
- @Nullable Rect clipRect) {
+ @Nullable Rect clipRect,
+ @Nullable TransitionAnimationHelper.RoundedContentPerDisplay roundedBounds) {
final DefaultAnimationAdapter adapter = new DefaultAnimationAdapter(anim, leash,
- position, clipRect, cornerRadius);
+ position, clipRect, cornerRadius, roundedBounds);
buildSurfaceAnimation(animations, anim, finishCallback, pool, mainExecutor, adapter);
}
@@ -109,9 +110,17 @@ public class DefaultSurfaceAnimator {
@Nullable final Rect mClipRect;
@Nullable private final Rect mAnimClipRect;
final float mCornerRadius;
+ final int mWindowBottom;
+
+ /**
+ * Inset changes aren't synchronized with transitions, so use a "provider" to track the
+ * bottom of the display content during the animation.
+ */
+ @Nullable final TransitionAnimationHelper.RoundedContentPerDisplay mRoundedContentBounds;
DefaultAnimationAdapter(@NonNull Animation anim, @NonNull SurfaceControl leash,
- @Nullable Point position, @Nullable Rect clipRect, float cornerRadius) {
+ @Nullable Point position, @Nullable Rect clipRect, float cornerRadius,
+ TransitionAnimationHelper.RoundedContentPerDisplay roundedBounds) {
super(leash);
mAnim = anim;
mPosition = (position != null && (position.x != 0 || position.y != 0))
@@ -119,6 +128,8 @@ public class DefaultSurfaceAnimator {
mClipRect = (clipRect != null && !clipRect.isEmpty()) ? clipRect : null;
mAnimClipRect = mClipRect != null ? new Rect() : null;
mCornerRadius = cornerRadius;
+ mWindowBottom = clipRect != null ? clipRect.bottom : 0;
+ mRoundedContentBounds = roundedBounds;
}
@Override
@@ -136,6 +147,11 @@ public class DefaultSurfaceAnimator {
if (mClipRect != null) {
boolean needCrop = false;
+ if (mRoundedContentBounds != null) {
+ mClipRect.bottom = Math.min(mRoundedContentBounds.mBounds.bottom,
+ mWindowBottom);
+ }
+
mAnimClipRect.set(mClipRect);
if (transformation.hasClipRect()) {
mAnimClipRect.intersectUnchecked(transformation.getClipRect());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index bf5800330979..e9200834c5dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -59,13 +59,13 @@ import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPI
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static com.android.internal.jank.Cuj.CUJ_DEFAULT_TASK_TO_TASK_ANIMATION;
-import static com.android.internal.policy.TransitionAnimation.DEFAULT_APP_TRANSITION_DURATION;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CHANGE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_CLOSE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
+import static com.android.wm.shell.Flags.enableDynamicInsetsForAppLaunch;
import static com.android.wm.shell.transition.DefaultSurfaceAnimator.buildSurfaceAnimation;
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionTypeFromInfo;
@@ -111,11 +111,13 @@ import com.android.window.flags.Flags;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.animation.SizeChangeAnimation;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
+import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.sysui.ShellInit;
import java.util.ArrayList;
@@ -125,6 +127,7 @@ import java.util.function.Consumer;
/** The default handler that handles anything not already handled. */
public class DefaultTransitionHandler implements Transitions.TransitionHandler {
private static final int MAX_ANIMATION_DURATION = 3000;
+ private static final int SIZE_CHANGE_ANIMATION_DURATION = 400;
private final TransactionPool mTransactionPool;
private final DisplayController mDisplayController;
@@ -134,6 +137,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
private final ShellExecutor mAnimExecutor;
private final TransitionAnimation mTransitionAnimation;
private final DevicePolicyManager mDevicePolicyManager;
+ private final TransitionAnimationHelper.RoundedContentTracker mRoundedContentBounds;
/** Keeps track of the currently-running animations associated with each transition. */
private final ArrayMap<IBinder, ArrayList<Animator>> mAnimations = new ArrayMap<>();
@@ -163,6 +167,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
DefaultTransitionHandler(@NonNull Context context,
@NonNull ShellInit shellInit,
@NonNull DisplayController displayController,
+ @NonNull DisplayInsetsController displayInsetsController,
@NonNull TransactionPool transactionPool,
@NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler,
@NonNull ShellExecutor animExecutor,
@@ -179,6 +184,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
shellInit.addInitCallback(this::onInit, this);
mRootTDAOrganizer = rootTDAOrganizer;
+ mRoundedContentBounds = new TransitionAnimationHelper.RoundedContentTracker(
+ displayController, displayInsetsController);
mInteractionJankMonitor = interactionJankMonitor;
}
@@ -191,6 +198,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
mMainHandler);
TransitionAnimation.initAttributeCache(mContext, mMainHandler);
+ mRoundedContentBounds.init();
}
private void updateEnterpriseThumbnailDrawable() {
@@ -297,6 +305,18 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
return ROTATION_ANIMATION_SEAMLESS;
}
+ @Nullable
+ final TransitionAnimationHelper.RoundedContentPerDisplay getRoundedContentBounds(
+ TransitionInfo.Change change) {
+ if (!enableDynamicInsetsForAppLaunch()) {
+ return null;
+ }
+ if (change.getTaskInfo() == null && change.getActivityComponent() == null) {
+ return null;
+ }
+ return mRoundedContentBounds.forDisplay(change.getEndDisplayId());
+ }
+
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -556,7 +576,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
change.getEndAbsBounds().left - animRoot.getOffset().x,
change.getEndAbsBounds().top - animRoot.getOffset().y);
- if (change.getActivityComponent() != null) {
+ final boolean isActivity = change.getActivityComponent() != null;
+ if (isActivity) {
// For appcompat letterbox: we intentionally report the task-bounds so that we
// can animate as-if letterboxes are "part of" the activity. This means we can't
// always rely solely on endAbsBounds and need to also max with endRelOffset.
@@ -564,7 +585,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
animRelOffset.y = Math.max(animRelOffset.y, change.getEndRelOffset().y);
}
- if (change.getActivityComponent() != null && !isActivityLevel
+ if (isActivity && !isActivityLevel
&& !mRotator.isRotated(change)) {
// At this point, this is an independent activity change in a non-activity
// transition. This means that an activity transition got erroneously combined
@@ -589,8 +610,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
}
buildSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
- mTransactionPool, mMainExecutor, animRelOffset, cornerRadius,
- clipRect);
+ mTransactionPool, mMainExecutor, animRelOffset, cornerRadius, clipRect,
+ isTask || isActivity
+ ? mRoundedContentBounds.forDisplay(change.getEndDisplayId())
+ : null);
final TransitionInfo.AnimationOptions options = change.getAnimationOptions();
if (options != null) {
@@ -779,15 +802,16 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
private void startBoundsChangeAnimation(@NonNull SurfaceControl.Transaction startT,
@NonNull ArrayList<Animator> animations, @NonNull TransitionInfo.Change change,
@NonNull Runnable finishCb, @NonNull ShellExecutor mainExecutor) {
- final SizeChangeAnimation sca =
- new SizeChangeAnimation(change.getStartAbsBounds(), change.getEndAbsBounds());
+ final SizeChangeAnimation sca = new SizeChangeAnimation(change.getStartAbsBounds(),
+ change.getEndAbsBounds(), /* initialScale= */ 1f, /* scaleFactor= */ 1f);
sca.initialize(change.getLeash(), change.getSnapshot(), startT);
final ValueAnimator va = sca.buildAnimator(change.getLeash(), change.getSnapshot(),
(animator) -> mainExecutor.execute(() -> {
animations.remove(animator);
finishCb.run();
}));
- va.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ va.setDuration(SIZE_CHANGE_ANIMATION_DURATION);
+ va.setInterpolator(Interpolators.EMPHASIZED);
animations.add(va);
}
@@ -932,7 +956,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
a.restrictDuration(MAX_ANIMATION_DURATION);
a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
- mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
+ mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds(),
+ getRoundedContentBounds(change));
}
private void attachThumbnailAnimation(@NonNull ArrayList<Animator> animations,
@@ -956,7 +981,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
a.restrictDuration(MAX_ANIMATION_DURATION);
a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
- mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
+ mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds(),
+ getRoundedContentBounds(change));
}
private static int getWallpaperTransitType(TransitionInfo info) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
index cca982142a3a..c71458dec5ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
@@ -29,15 +29,18 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.Context;
import android.os.IBinder;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.shared.IHomeTransitionListener;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
+import com.android.wm.shell.sysui.ShellInit;
/**
* The {@link TransitionObserver} that observes for transitions involving the home
@@ -51,13 +54,30 @@ public class HomeTransitionObserver implements TransitionObserver,
private @NonNull final Context mContext;
private @NonNull final ShellExecutor mMainExecutor;
+ private @NonNull final DisplayInsetsController mDisplayInsetsController;
private IBinder mPendingStartDragTransition;
private Boolean mPendingHomeVisibilityUpdate;
public HomeTransitionObserver(@NonNull Context context,
- @NonNull ShellExecutor mainExecutor) {
+ @NonNull ShellExecutor mainExecutor,
+ @NonNull DisplayInsetsController displayInsetsController,
+ @NonNull ShellInit shellInit) {
mContext = context;
mMainExecutor = mainExecutor;
+ mDisplayInsetsController = displayInsetsController;
+
+ shellInit.addInitCallback(this::onInit, this);
+ }
+
+ private void onInit() {
+ mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY,
+ new DisplayInsetsController.OnInsetsChangedListener() {
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ if (mListener == null) return;
+ mListener.call(l -> l.onDisplayInsetsChanged(insetsState));
+ }
+ });
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index aa42b7f0ca76..8100f1d1a9a9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -347,21 +347,21 @@ class ScreenRotationAnimation {
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
buildSurfaceAnimation(animations, mRotateEnterAnimation, getEnterSurface(), finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
- null /* clipRect */);
+ null /* clipRect */, null);
}
private void startScreenshotRotationAnimation(@NonNull ArrayList<Animator> animations,
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
buildSurfaceAnimation(animations, mRotateExitAnimation, mAnimLeash, finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
- null /* clipRect */);
+ null /* clipRect */, null);
}
private void buildScreenshotAlphaAnimation(@NonNull ArrayList<Animator> animations,
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
buildSurfaceAnimation(animations, mRotateAlphaAnimation, mAnimLeash, finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
- null /* clipRect */);
+ null /* clipRect */, null);
}
private void buildLumaAnimation(@NonNull ArrayList<Animator> animations,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index edfb56019a60..48b48640a37f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -39,6 +39,11 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.graphics.Color;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.util.SparseArray;
+import android.view.InsetsSource;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.animation.Animation;
@@ -47,6 +52,9 @@ import android.window.TransitionInfo;
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.ProtoLog;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.TransitionUtil;
@@ -325,4 +333,77 @@ public class TransitionAnimationHelper {
}
return false;
}
+
+ /**
+ * In some situations (eg. TaskBar) the content area of a display appears to be rounded. For
+ * these situations, we may want the animation to also express the same rounded corners (even
+ * though in steady-state, the app internally manages the insets). This class Keeps track of,
+ * and provides, the bounds of rounded-corner display content.
+ *
+ * This is used to enable already-running animations to adapt to changes in taskbar/navbar
+ * position live.
+ */
+ public static class RoundedContentPerDisplay implements
+ DisplayInsetsController.OnInsetsChangedListener {
+
+ /** The current bounds of the display content (post-inset). */
+ final Rect mBounds = new Rect();
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ Insets insets = Insets.NONE;
+ for (int i = insetsState.sourceSize() - 1; i >= 0; i--) {
+ final InsetsSource source = insetsState.sourceAt(i);
+ if (!source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
+ continue;
+ }
+ insets = Insets.max(source.calculateInsets(insetsState.getDisplayFrame(), false),
+ insets);
+ }
+ mBounds.set(insetsState.getDisplayFrame());
+ mBounds.inset(insets);
+ }
+ }
+
+ /**
+ * Keeps track of the bounds of rounded-corner display content (post-inset).
+ *
+ * @see RoundedContentPerDisplay
+ */
+ public static class RoundedContentTracker implements
+ DisplayController.OnDisplaysChangedListener {
+ final DisplayController mDisplayController;
+ final DisplayInsetsController mDisplayInsetsController;
+ final SparseArray<RoundedContentPerDisplay> mPerDisplay = new SparseArray<>();
+
+ RoundedContentTracker(DisplayController dc, DisplayInsetsController dic) {
+ mDisplayController = dc;
+ mDisplayInsetsController = dic;
+ }
+
+ void init() {
+ mDisplayController.addDisplayWindowListener(this);
+ }
+
+ RoundedContentPerDisplay forDisplay(int displayId) {
+ return mPerDisplay.get(displayId);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ final RoundedContentPerDisplay perDisplay = new RoundedContentPerDisplay();
+ mDisplayInsetsController.addInsetsChangedListener(displayId, perDisplay);
+ mPerDisplay.put(displayId, perDisplay);
+ final DisplayLayout dl = mDisplayController.getDisplayLayout(displayId);
+ perDisplay.mBounds.set(0, 0, dl.width(), dl.height());
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ final RoundedContentPerDisplay listener = mPerDisplay.removeReturnOld(displayId);
+ if (listener != null) {
+ mDisplayInsetsController.removeInsetsChangedListener(displayId, listener);
+ }
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 4f49ebcd2e83..3dc8733c879d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -84,6 +84,7 @@ import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
@@ -314,13 +315,14 @@ public class Transitions implements RemoteCallable<Transitions>,
@NonNull ShellTaskOrganizer organizer,
@NonNull TransactionPool pool,
@NonNull DisplayController displayController,
+ @NonNull DisplayInsetsController displayInsetsController,
@NonNull ShellExecutor mainExecutor,
@NonNull Handler mainHandler,
@NonNull ShellExecutor animExecutor,
@NonNull HomeTransitionObserver homeTransitionObserver,
@NonNull FocusTransitionObserver focusTransitionObserver) {
this(context, shellInit, new ShellCommandHandler(), shellController, organizer, pool,
- displayController, mainExecutor, mainHandler, animExecutor,
+ displayController, displayInsetsController, mainExecutor, mainHandler, animExecutor,
new RootTaskDisplayAreaOrganizer(mainExecutor, context, shellInit),
homeTransitionObserver, focusTransitionObserver);
}
@@ -332,6 +334,7 @@ public class Transitions implements RemoteCallable<Transitions>,
@NonNull ShellTaskOrganizer organizer,
@NonNull TransactionPool pool,
@NonNull DisplayController displayController,
+ @NonNull DisplayInsetsController displayInsetsController,
@NonNull ShellExecutor mainExecutor,
@NonNull Handler mainHandler,
@NonNull ShellExecutor animExecutor,
@@ -345,8 +348,8 @@ public class Transitions implements RemoteCallable<Transitions>,
mDisplayController = displayController;
mPlayerImpl = new TransitionPlayerImpl();
mDefaultTransitionHandler = new DefaultTransitionHandler(context, shellInit,
- displayController, pool, mainExecutor, mainHandler, animExecutor, rootTDAOrganizer,
- InteractionJankMonitor.getInstance());
+ displayController, displayInsetsController, pool, mainExecutor, mainHandler,
+ animExecutor, rootTDAOrganizer, InteractionJankMonitor.getInstance());
mRemoteTransitionHandler = new RemoteTransitionHandler(mMainExecutor);
mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index 25cf06b4247c..cdadce57d610 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -50,7 +50,6 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.Accessibilit
import androidx.core.view.isGone
import com.android.window.flags.Flags
import com.android.wm.shell.R
-import com.android.wm.shell.bubbles.ContextUtils.isRtl
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum.A11Y_APP_HANDLE_MENU_DESKTOP_VIEW
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum.A11Y_APP_HANDLE_MENU_FULLSCREEN
@@ -58,6 +57,7 @@ import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventE
import com.android.wm.shell.shared.annotations.ShellBackgroundThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper
+import com.android.wm.shell.shared.bubbles.ContextUtils.isRtl
import com.android.wm.shell.shared.split.SplitScreenConstants
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 077b35583e04..f6e49853eddf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -629,9 +629,9 @@ public class StageCoordinatorTests extends ShellTestCase {
private Transitions createTestTransitions() {
ShellInit shellInit = new ShellInit(mMainExecutor);
final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
- mTaskOrganizer, mTransactionPool, mock(DisplayController.class), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
- mock(FocusTransitionObserver.class));
+ mTaskOrganizer, mTransactionPool, mock(DisplayController.class),
+ mDisplayInsetsController, mMainExecutor, mMainHandler, mAnimExecutor,
+ mock(HomeTransitionObserver.class), mock(FocusTransitionObserver.class));
shellInit.init();
return t;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
index 18fdbeff40f4..6996d44af034 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
@@ -53,6 +53,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
@@ -78,6 +79,8 @@ public class DefaultTransitionHandlerTest extends ShellTestCase {
InstrumentationRegistry.getInstrumentation().getTargetContext();
private final DisplayController mDisplayController = mock(DisplayController.class);
+ private final DisplayInsetsController mDisplayInsetsController =
+ mock(DisplayInsetsController.class);
private final TransactionPool mTransactionPool = new MockTransactionPool();
private final TestShellExecutor mMainExecutor = new TestShellExecutor();
private final TestShellExecutor mAnimExecutor = new TestShellExecutor();
@@ -95,7 +98,7 @@ public class DefaultTransitionHandlerTest extends ShellTestCase {
mContext,
mShellInit);
mTransitionHandler = new DefaultTransitionHandler(
- mContext, mShellInit, mDisplayController,
+ mContext, mShellInit, mDisplayController, mDisplayInsetsController,
mTransactionPool, mMainExecutor, mMainHandler, mAnimExecutor,
mRootTaskDisplayAreaOrganizer, mock(InteractionJankMonitor.class));
mShellInit.init();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
index 55bff09e0ae2..52634c08dafd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
@@ -61,6 +61,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.shared.IHomeTransitionListener;
import com.android.wm.shell.shared.TransactionPool;
@@ -88,6 +89,8 @@ public class HomeTransitionObserverTest extends ShellTestCase {
private final TestShellExecutor mMainExecutor = new TestShellExecutor();
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private final DisplayController mDisplayController = mock(DisplayController.class);
+ private final DisplayInsetsController mDisplayInsetsController =
+ mock(DisplayInsetsController.class);
private IHomeTransitionListener mListener;
private Transitions mTransition;
@@ -98,10 +101,11 @@ public class HomeTransitionObserverTest extends ShellTestCase {
mListener = mock(IHomeTransitionListener.class);
when(mListener.asBinder()).thenReturn(mock(IBinder.class));
- mHomeTransitionObserver = new HomeTransitionObserver(mContext, mMainExecutor);
+ mHomeTransitionObserver = new HomeTransitionObserver(mContext, mMainExecutor,
+ mDisplayInsetsController, mock(ShellInit.class));
mTransition = new Transitions(mContext, mock(ShellInit.class), mock(ShellController.class),
- mOrganizer, mTransactionPool, mDisplayController, mMainExecutor,
- mMainHandler, mAnimExecutor, mHomeTransitionObserver,
+ mOrganizer, mTransactionPool, mDisplayController, mDisplayInsetsController,
+ mMainExecutor, mMainHandler, mAnimExecutor, mHomeTransitionObserver,
mock(FocusTransitionObserver.class));
mHomeTransitionObserver.setHomeTransitionListener(mTransition, mListener);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 9849b1174d8e..44bb2154f170 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -107,6 +107,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.recents.IRecentsAnimationRunner;
@@ -145,6 +146,8 @@ public class ShellTransitionTests extends ShellTestCase {
private final ShellExecutor mAnimExecutor = new TestShellExecutor();
private final TestTransitionHandler mDefaultHandler = new TestTransitionHandler();
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+ private final DisplayInsetsController mDisplayInsets =
+ mock(DisplayInsetsController.class);
@Before
public void setUp() {
@@ -156,9 +159,9 @@ public class ShellTransitionTests extends ShellTestCase {
public void instantiate_addInitCallback() {
ShellInit shellInit = mock(ShellInit.class);
final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
- mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
- mock(FocusTransitionObserver.class));
+ mOrganizer, mTransactionPool, createTestDisplayController(), mDisplayInsets,
+ mMainExecutor, mMainHandler, mAnimExecutor,
+ mock(HomeTransitionObserver.class), mock(FocusTransitionObserver.class));
// One from Transitions, one from RootTaskDisplayAreaOrganizer
verify(shellInit).addInitCallback(any(), eq(t));
verify(shellInit).addInitCallback(any(), isA(RootTaskDisplayAreaOrganizer.class));
@@ -169,9 +172,9 @@ public class ShellTransitionTests extends ShellTestCase {
ShellInit shellInit = new ShellInit(mMainExecutor);
ShellController shellController = mock(ShellController.class);
final Transitions t = new Transitions(mContext, shellInit, shellController,
- mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
- mock(FocusTransitionObserver.class));
+ mOrganizer, mTransactionPool, createTestDisplayController(), mDisplayInsets,
+ mMainExecutor, mMainHandler, mAnimExecutor,
+ mock(HomeTransitionObserver.class), mock(FocusTransitionObserver.class));
shellInit.init();
verify(shellController, times(1)).addExternalInterface(
eq(IShellTransitions.DESCRIPTOR), any(), any());
@@ -1314,8 +1317,9 @@ public class ShellTransitionTests extends ShellTestCase {
ShellInit shellInit = new ShellInit(mMainExecutor);
final Transitions transitions =
new Transitions(mContext, shellInit, mock(ShellController.class), mOrganizer,
- mTransactionPool, createTestDisplayController(), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
+ mTransactionPool, createTestDisplayController(), mDisplayInsets,
+ mMainExecutor, mMainHandler, mAnimExecutor,
+ mock(HomeTransitionObserver.class),
mock(FocusTransitionObserver.class));
final RecentTasksController mockRecentsTaskController = mock(RecentTasksController.class);
doReturn(mContext).when(mockRecentsTaskController).getContext();
@@ -1909,8 +1913,8 @@ public class ShellTransitionTests extends ShellTestCase {
private Transitions createTestTransitions() {
ShellInit shellInit = new ShellInit(mMainExecutor);
final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
- mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
+ mOrganizer, mTransactionPool, createTestDisplayController(), mDisplayInsets,
+ mMainExecutor, mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
mock(FocusTransitionObserver.class));
shellInit.init();
return t;
diff --git a/libs/androidfw/LocaleDataLookup.cpp b/libs/androidfw/LocaleDataLookup.cpp
index 9aacdcb9ca92..ed645826234d 100644
--- a/libs/androidfw/LocaleDataLookup.cpp
+++ b/libs/androidfw/LocaleDataLookup.cpp
@@ -5774,7 +5774,6 @@ const char* lookupLikelyScript(uint32_t packed_lang_region) {
case 0xD2120000u: // squ -> Latn
case 0x73724D45u: // sr-ME -> Latn
case 0x7372524Fu: // sr-RO -> Latn
- case 0x73725255u: // sr-RU -> Latn
case 0x73725452u: // sr-TR -> Latn
case 0x82320000u: // sra -> Latn
case 0x92320000u: // sre -> Latn
@@ -7265,7 +7264,6 @@ const char* lookupLikelyScript(uint32_t packed_lang_region) {
return SCRIPT_CODES[73u];
case 0x8ACD0000u: // nwc -> Newa
return SCRIPT_CODES[74u];
- case 0xB40C474Eu: // man-GN -> Nkoo
case 0xBA0D0000u: // nqo -> Nkoo
return SCRIPT_CODES[75u];
case 0xDCF90000u: // zhx -> Nshu
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 3ef970830dc4..46dcc1f4c50b 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -164,8 +164,13 @@ std::string Bitmap::getAshmemId(const char* tag, uint64_t bitmapId,
android::base::ReadFileToString("/proc/self/cmdline", &temp);
return temp;
}();
- return std::format("bitmap/{}-id_{}-{}x{}-size_{}-{}",
- tag, bitmapId, width, height, size, sCmdline);
+ /* counter is to ensure the uniqueness of the ashmem filename,
+ * e.g. a bitmap with same mId could be sent multiple times, an
+ * ashmem region is created each time
+ */
+ static std::atomic<uint32_t> counter{0};
+ return std::format("bitmap/{}_{}_{}x{}_size-{}_id-{}_{}",
+ tag, counter.fetch_add(1), width, height, size, bitmapId, sCmdline);
}
sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index c9ec31bab048..7221f1ddeb7f 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -259,3 +259,10 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_output_switcher_personal_audio_sharing"
+ namespace: "cross_device_experiences"
+ description: "Enables personal audio sharing in the output switcher."
+ bug: "385672684"
+} \ No newline at end of file
diff --git a/packages/InputDevices/res/raw/keyboard_layout_hungarian.kcm b/packages/InputDevices/res/raw/keyboard_layout_hungarian.kcm
index 6c947c77ad3d..455fb83474b6 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_hungarian.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_hungarian.kcm
@@ -37,8 +37,8 @@ key 0 {
key 1 {
label: '1'
base: '1'
- shift: '!'
- ralt: '\u0303'
+ shift: '\''
+ ralt: '\u007e'
}
key 2 {
@@ -80,7 +80,7 @@ key 7 {
label: '7'
base: '7'
shift: '='
- ralt: '\u0300'
+ ralt: '`'
}
key 8 {
@@ -374,6 +374,7 @@ key M {
base: 'm'
shift, capslock: 'M'
shift+capslock: 'm'
+ ralt: '<'
}
key COMMA {
@@ -387,6 +388,7 @@ key PERIOD {
label: '.'
base: '.'
shift: ':'
+ ralt: '>'
}
key MINUS {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index bcc737a351a9..d05aaaa6e389 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -52,8 +52,11 @@ import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Objects;
+import java.util.stream.Stream;
/**
* This is a utility class for defining some utility methods and constants
@@ -69,7 +72,8 @@ public class PackageUtil {
//intent attribute strings related to uninstall
public static final String INTENT_ATTR_PACKAGE_NAME=PREFIX+"PackageName";
private static final String DOWNLOADS_AUTHORITY = "downloads";
- private static final String SPLIT_BASE_APK_END_WITH = "base.apk";
+ private static final String SPLIT_BASE_APK_SUFFIX = "base.apk";
+ private static final String SPLIT_APK_SUFFIX = ".apk";
/**
* Utility method to get package information for a given {@link File}
@@ -77,11 +81,20 @@ public class PackageUtil {
@Nullable
public static PackageInfo getPackageInfo(Context context, File sourceFile, int flags) {
String filePath = sourceFile.getAbsolutePath();
- if (filePath.endsWith(SPLIT_BASE_APK_END_WITH)) {
+ if (filePath.endsWith(SPLIT_BASE_APK_SUFFIX)) {
File dir = sourceFile.getParentFile();
- if (dir.listFiles().length > 1) {
- // split apks, use file directory to get archive info
- filePath = dir.getPath();
+ try (Stream<Path> list = Files.list(dir.toPath())) {
+ long count = list
+ .filter((name) -> name.endsWith(SPLIT_APK_SUFFIX))
+ .limit(2)
+ .count();
+ if (count > 1) {
+ // split apks, use file directory to get archive info
+ filePath = dir.getPath();
+ }
+ } catch (Exception ignored) {
+ // No access to the parent directory, proceed to read app snippet
+ // from the base apk only
}
}
try {
@@ -240,9 +253,10 @@ public class PackageUtil {
appInfo.publicSourceDir = archiveFilePath;
if (appInfo.splitNames != null && appInfo.splitSourceDirs == null) {
- final File[] files = sourceFile.getParentFile().listFiles();
+ final File[] files = sourceFile.getParentFile().listFiles(
+ (dir, name) -> name.endsWith(SPLIT_APK_SUFFIX));
final String[] splits = Arrays.stream(appInfo.splitNames)
- .map(i -> findFilePath(files, i + ".apk"))
+ .map(i -> findFilePath(files, i + SPLIT_APK_SUFFIX))
.filter(Objects::nonNull)
.toArray(String[]::new);
@@ -283,7 +297,9 @@ public class PackageUtil {
}
private static String findFilePath(File[] files, String postfix) {
- for (File file : files) {
+ final int length = files != null ? files.length : 0;
+ for (int i = 0; i < length; i++) {
+ File file = files[i];
final String path = file.getAbsolutePath();
if (path.endsWith(postfix)) {
return path;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
index e8477ef261a8..b84b903ac1cb 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
@@ -41,6 +41,8 @@ import android.util.Log
import com.android.packageinstaller.v2.model.PackageUtil.getAppSnippet
import java.io.ByteArrayOutputStream
import java.io.File
+import java.nio.file.Files
+import java.nio.file.Path
import kotlinx.parcelize.Parceler
import kotlinx.parcelize.Parcelize
@@ -48,6 +50,7 @@ object PackageUtil {
private val LOG_TAG = InstallRepository::class.java.simpleName
private const val DOWNLOADS_AUTHORITY = "downloads"
private const val SPLIT_BASE_APK_SUFFIX = "base.apk"
+ private const val SPLIT_APK_SUFFIX = ".apk"
const val localLogv = false
const val ARGS_ABORT_REASON: String = "abort_reason"
@@ -440,9 +443,20 @@ object PackageUtil {
var filePath = sourceFile.absolutePath
if (filePath.endsWith(SPLIT_BASE_APK_SUFFIX)) {
val dir = sourceFile.parentFile
- if ((dir?.listFiles()?.size ?: 0) > 1) {
- // split apks, use file directory to get archive info
- filePath = dir.path
+ try {
+ Files.list(dir.toPath()).use { list ->
+ val count: Long = list
+ .filter { name: Path -> name.endsWith(SPLIT_APK_SUFFIX) }
+ .limit(2)
+ .count()
+ if (count > 1) {
+ // split apks, use file directory to get archive info
+ filePath = dir.path
+ }
+ }
+ } catch (ignored: Exception) {
+ // No access to the parent directory, proceed to read app snippet
+ // from the base apk only
}
}
return try {
diff --git a/packages/SettingsLib/ValuePreference/Android.bp b/packages/SettingsLib/ValuePreference/Android.bp
new file mode 100644
index 000000000000..1cdcd2247eaf
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/Android.bp
@@ -0,0 +1,31 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+ name: "SettingsLibValuePreference",
+ use_resource_processor: true,
+ defaults: [
+ "SettingsLintDefaults",
+ ],
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ static_libs: [
+ "androidx.annotation_annotation",
+ "androidx.preference_preference",
+ "SettingsLibSettingsTheme",
+ ],
+
+ sdk_version: "system_current",
+ min_sdk_version: "23",
+ apex_available: [
+ "//apex_available:platform",
+ ],
+}
diff --git a/packages/SettingsLib/ValuePreference/AndroidManifest.xml b/packages/SettingsLib/ValuePreference/AndroidManifest.xml
new file mode 100644
index 000000000000..217282be9c80
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.widget.preference.value">
+
+ <uses-sdk android:minSdkVersion="21"/>
+
+</manifest>
diff --git a/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference.xml b/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference.xml
new file mode 100644
index 000000000000..4fd3ab10fb16
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="72dp"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:background="?android:attr/selectableItemBackground"
+ android:clipToPadding="false"
+ android:baselineAligned="false"
+ android:filterTouchesWhenObscured="false">
+
+ <include layout="@layout/settingslib_expressive_preference_icon_frame"/>
+
+ <include layout="@layout/settingslib_expressive_value_preference_text_frame"/>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="end|center_vertical"
+ android:paddingStart="@dimen/settingslib_expressive_space_small1"
+ android:paddingEnd="0dp"
+ android:orientation="vertical"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference_text_frame.xml b/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference_text_frame.xml
new file mode 100644
index 000000000000..a385ee521a74
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference_text_frame.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/settingslib_expressive_space_none"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingVertical="@dimen/settingslib_expressive_space_small1"
+ android:paddingStart="@dimen/settingslib_expressive_space_none"
+ android:paddingEnd="@dimen/settingslib_expressive_space_small1"
+ android:filterTouchesWhenObscured="false">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.SettingsLib.ValuePreferenceTitle"
+ android:ellipsize="marquee"/>
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="10"/>
+</RelativeLayout> \ No newline at end of file
diff --git a/packages/SettingsLib/ValuePreference/res/values/styles.xml b/packages/SettingsLib/ValuePreference/res/values/styles.xml
new file mode 100644
index 000000000000..284819498f64
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <style name="TextAppearance.SettingsLib.ValuePreferenceTitle"
+ parent="@style/TextAppearance.SettingsLib.DisplaySmall">
+ <item name="android:textColor">@color/settingslib_text_color_primary</item>
+ </style>
+</resources>
diff --git a/packages/SettingsLib/ValuePreference/src/com/android/settingslib/widget/ValuePreference.kt b/packages/SettingsLib/ValuePreference/src/com/android/settingslib/widget/ValuePreference.kt
new file mode 100644
index 000000000000..475638c8b406
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/src/com/android/settingslib/widget/ValuePreference.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import com.android.settingslib.widget.preference.value.R
+
+/** The BulletPreference shows a text which describe a feature. */
+class ValuePreference
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : Preference(context, attrs, defStyleAttr, defStyleRes) {
+
+ init {
+ layoutResource = R.layout.settingslib_expressive_value_preference
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ holder.isDividerAllowedAbove = false
+ holder.isDividerAllowedBelow = false
+ }
+}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 1297aa3ff7d5..6a7e048b577a 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -288,7 +288,7 @@
<string name="bluetooth_profile_hid">Input device</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile (accessing Internet through remote device). [CHAR LIMIT=40] -->
<string name="bluetooth_profile_pan">Internet access</string>
- <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PBAP profile. [CHAR LIMIT=40] -->
+ <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PBAP profile. [CHAR LIMIT=80] -->
<string name="bluetooth_profile_pbap">Allow access to contacts and call history</string>
<!-- Bluetooth settings. The user-visible summary string that is used whenever referring to the PBAP profile (sharing contacts). [CHAR LIMIT=60] -->
<string name="bluetooth_profile_pbap_summary">Info will be used for call announcements and more</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index 155c7e6530aa..e46574cef917 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -37,9 +37,11 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.settingslib.R;
+import com.android.settingslib.flags.Flags;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
public class LeAudioProfile implements LocalBluetoothProfile {
@@ -59,6 +61,10 @@ public class LeAudioProfile implements LocalBluetoothProfile {
// Order of this profile in device profiles list
private static final int ORDINAL = 1;
+ // Cached callbacks being registered before service is connected.
+ private ConcurrentHashMap<BluetoothLeAudio.Callback, Executor>
+ mCachedCallbackExecutorMap = new ConcurrentHashMap<>();
+
// These callbacks run on the main thread.
private final class LeAudioServiceListener implements BluetoothProfile.ServiceListener {
@@ -88,7 +94,19 @@ public class LeAudioProfile implements LocalBluetoothProfile {
// Check current list of CachedDevices to see if any are hearing aid devices.
mDeviceManager.updateHearingAidsDevices();
mProfileManager.callServiceConnectedListeners();
- mIsProfileReady = true;
+ if (!mIsProfileReady) {
+ mIsProfileReady = true;
+ if (Flags.adoptPrimaryGroupManagementApiV2()) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onServiceConnected, register mCachedCallbackExecutorMap = "
+ + mCachedCallbackExecutorMap);
+ }
+ mCachedCallbackExecutorMap.forEach(
+ (callback, executor) -> registerCallback(executor, callback));
+ }
+ }
}
public void onServiceDisconnected(int profile) {
@@ -96,7 +114,12 @@ public class LeAudioProfile implements LocalBluetoothProfile {
Log.d(TAG, "Bluetooth service disconnected");
}
mProfileManager.callServiceDisconnectedListeners();
- mIsProfileReady = false;
+ if (mIsProfileReady) {
+ mIsProfileReady = false;
+ if (Flags.adoptPrimaryGroupManagementApiV2()) {
+ mCachedCallbackExecutorMap.clear();
+ }
+ }
}
}
@@ -367,6 +390,9 @@ public class LeAudioProfile implements LocalBluetoothProfile {
@NonNull BluetoothLeAudio.Callback callback) {
if (mService == null) {
Log.w(TAG, "Proxy not attached to service. Cannot register callback.");
+ if (Flags.adoptPrimaryGroupManagementApiV2()) {
+ mCachedCallbackExecutorMap.putIfAbsent(callback, executor);
+ }
return;
}
mService.registerCallback(executor, callback);
@@ -384,6 +410,9 @@ public class LeAudioProfile implements LocalBluetoothProfile {
* callback is registered
*/
public void unregisterCallback(@NonNull BluetoothLeAudio.Callback callback) {
+ if (Flags.adoptPrimaryGroupManagementApiV2()) {
+ mCachedCallbackExecutorMap.remove(callback);
+ }
if (mService == null) {
Log.w(TAG, "Proxy not attached to service. Cannot unregister callback.");
return;
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index d0f84627f8d8..463e94bfa0d6 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -464,6 +464,7 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED,
new InclusiveIntegerRangeValidator(0, 1));
VALIDATORS.put(Secure.ADVANCED_PROTECTION_MODE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.AAPM_USB_DATA_PROTECTION, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DISABLE_ADAPTIVE_AUTH_LIMIT_LOCK, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_APP_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_KEYGUARD_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 7179cbdf93fb..e9b6c73cb800 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -642,6 +642,7 @@ public class SettingsBackupTest {
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
newHashSet(
+ Settings.Secure.AAPM_USB_DATA_PROTECTION,
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, // Deprecated since O.
Settings.Secure.ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS,
diff --git a/packages/StatementService/Android.bp b/packages/StatementService/Android.bp
index 39b0302beff8..3fc9aabb7edb 100644
--- a/packages/StatementService/Android.bp
+++ b/packages/StatementService/Android.bp
@@ -32,7 +32,11 @@ android_app {
},
target_sdk_version: "29",
platform_apis: true,
+ system_ext_specific: true,
privileged: true,
+ required: [
+ "privapp_whitelist_com.android.statementservice",
+ ],
certificate: "platform",
static_libs: [
"StatementServiceParser",
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index c6bc1c70ad18..3cb30258fcb1 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -155,13 +155,3 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
-
-flag {
- name: "hearing_devices_input_routing_ui_improvement"
- namespace: "accessibility"
- description: "UI improvement for hearing device input routing feature"
- bug: "397314200"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
index fdb07bdbe7f3..576ff61c4f94 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
@@ -83,7 +83,7 @@ constructor(
ViewTransitionRegistry.instance
} else {
null
- }
+ },
) : ActivityTransitionAnimator.Controller {
override val isLaunching: Boolean = true
@@ -313,9 +313,17 @@ constructor(
// visibility that is saved by `setShouldBlockVisibilityChanges()` for a later restoration.
(ghostedView as? LaunchableView)?.setShouldBlockVisibilityChanges(true)
- // Create a ghost of the view that will be moving and fading out. This allows to fade out
- // the content before fading out the background.
- ghostView = GhostView.addGhost(ghostedView, transitionContainer)
+ try {
+ // Create a ghost of the view that will be moving and fading out. This allows to fade
+ // out the content before fading out the background.
+ ghostView = GhostView.addGhost(ghostedView, transitionContainer)
+ } catch (e: Exception) {
+ // It is not 100% clear what conditions cause this exception to happen in practice, and
+ // we could never reproduce it, but it does show up extremely rarely. We already handle
+ // the scenario where ghostView is null, so we just avoid crashing and log the error.
+ // See b/315858472 for an investigation of the issue.
+ Log.e(TAG, "Failed to create ghostView", e)
+ }
// [GhostView.addGhost], the result of which is our [ghostView], creates a [GhostView], and
// adds it first to a [FrameLayout] container. It then adds _that_ container to an
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
index 5f71b19fbc3f..884666854ab4 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
@@ -111,10 +111,6 @@ class ComposedDigitalLayerController(private val clockCtx: ClockContext) :
override fun onZenDataChanged(data: ZenData) {}
- override fun onFontAxesChanged(axes: ClockAxisStyle) {
- view.updateAxes(axes)
- }
-
override var isReactiveTouchInteractionEnabled
get() = view.isReactiveTouchInteractionEnabled
set(value) {
@@ -152,6 +148,13 @@ class ComposedDigitalLayerController(private val clockCtx: ClockContext) :
override fun onFidgetTap(x: Float, y: Float) {
view.animateFidget(x, y)
}
+
+ private var hasFontAxes = false
+
+ override fun onFontAxesChanged(style: ClockAxisStyle) {
+ view.updateAxes(style, isAnimated = hasFontAxes)
+ hasFontAxes = true
+ }
}
override val faceEvents =
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 3cfa78d17fe7..450cece8709a 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -231,8 +231,6 @@ class DefaultClockController(
override fun onAlarmDataChanged(data: AlarmData) {}
override fun onZenDataChanged(data: ZenData) {}
-
- override fun onFontAxesChanged(axes: ClockAxisStyle) {}
}
open inner class DefaultClockAnimations(
@@ -285,6 +283,8 @@ class DefaultClockController(
override fun onPositionUpdated(distance: Float, fraction: Float) {}
override fun onFidgetTap(x: Float, y: Float) {}
+
+ override fun onFontAxesChanged(style: ClockAxisStyle) {}
}
inner class LargeClockAnimations(
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
index 8744357a74c9..84f45fcc0532 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
@@ -99,12 +99,6 @@ class FlexClockController(private val clockCtx: ClockContext) : ClockController
smallClock.events.onZenDataChanged(data)
largeClock.events.onZenDataChanged(data)
}
-
- override fun onFontAxesChanged(axes: ClockAxisStyle) {
- val fontAxes = ClockAxisStyle(getDefaultAxes(clockCtx.settings).merge(axes))
- smallClock.events.onFontAxesChanged(fontAxes)
- largeClock.events.onFontAxesChanged(fontAxes)
- }
}
override fun initialize(
@@ -113,10 +107,10 @@ class FlexClockController(private val clockCtx: ClockContext) : ClockController
foldFraction: Float,
clockListener: ClockEventListener?,
) {
- events.onFontAxesChanged(clockCtx.settings.axes)
smallClock.run {
layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
+ animations.onFontAxesChanged(clockCtx.settings.axes)
animations.doze(dozeFraction)
animations.fold(foldFraction)
events.onTimeTick()
@@ -125,6 +119,7 @@ class FlexClockController(private val clockCtx: ClockContext) : ClockController
largeClock.run {
layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
+ animations.onFontAxesChanged(clockCtx.settings.axes)
animations.doze(dozeFraction)
animations.fold(foldFraction)
events.onTimeTick()
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
index 171a68f72e20..ec7803d0c6d6 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
@@ -31,10 +31,12 @@ import com.android.systemui.plugins.clocks.ClockFaceConfig
import com.android.systemui.plugins.clocks.ClockFaceController
import com.android.systemui.plugins.clocks.ClockFaceEvents
import com.android.systemui.plugins.clocks.ClockFaceLayout
+import com.android.systemui.plugins.clocks.ClockFontAxis.Companion.merge
import com.android.systemui.plugins.clocks.DefaultClockFaceLayout
import com.android.systemui.plugins.clocks.ThemeConfig
import com.android.systemui.plugins.clocks.WeatherData
import com.android.systemui.plugins.clocks.ZenData
+import com.android.systemui.shared.clocks.FlexClockController.Companion.getDefaultAxes
import com.android.systemui.shared.clocks.FontUtils.get
import com.android.systemui.shared.clocks.FontUtils.set
import com.android.systemui.shared.clocks.ViewUtils.computeLayoutDiff
@@ -131,15 +133,6 @@ class FlexClockFaceController(clockCtx: ClockContext, private val isLargeClock:
layerController.faceEvents.onThemeChanged(theme)
}
- override fun onFontAxesChanged(settings: ClockAxisStyle) {
- var axes = ClockAxisStyle(settings)
- if (!isLargeClock && axes[GSFAxes.WIDTH] > SMALL_CLOCK_MAX_WDTH) {
- axes[GSFAxes.WIDTH] = SMALL_CLOCK_MAX_WDTH
- }
-
- layerController.events.onFontAxesChanged(axes)
- }
-
/**
* targetRegion passed to all customized clock applies counter translationY of Keyguard and
* keyguard_large_clock_top_margin from default clock
@@ -232,6 +225,15 @@ class FlexClockFaceController(clockCtx: ClockContext, private val isLargeClock:
override fun onFidgetTap(x: Float, y: Float) {
layerController.animations.onFidgetTap(x, y)
}
+
+ override fun onFontAxesChanged(style: ClockAxisStyle) {
+ var axes = ClockAxisStyle(getDefaultAxes(clockCtx.settings).merge(style))
+ if (!isLargeClock && axes[GSFAxes.WIDTH] > SMALL_CLOCK_MAX_WDTH) {
+ axes[GSFAxes.WIDTH] = SMALL_CLOCK_MAX_WDTH
+ }
+
+ layerController.animations.onFontAxesChanged(axes)
+ }
}
companion object {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
index 7be9a936cbd3..eef910c3bd27 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
@@ -171,10 +171,6 @@ open class SimpleDigitalHandLayerController(
override fun onAlarmDataChanged(data: AlarmData) {}
override fun onZenDataChanged(data: ZenData) {}
-
- override fun onFontAxesChanged(axes: ClockAxisStyle) {
- view.updateAxes(axes)
- }
}
override val animations =
@@ -195,6 +191,13 @@ open class SimpleDigitalHandLayerController(
view.dozeFraction = fraction
}
+ private var hasFontAxes = false
+
+ override fun onFontAxesChanged(style: ClockAxisStyle) {
+ view.updateAxes(style, isAnimated = hasFontAxes)
+ hasFontAxes = true
+ }
+
override fun fold(fraction: Float) {
applyLayout()
refreshTime()
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
index 4531aed0e83d..4a5532b6e462 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
@@ -272,8 +272,8 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) {
invalidate()
}
- fun updateAxes(axes: ClockAxisStyle) {
- childViews.forEach { view -> view.updateAxes(axes) }
+ fun updateAxes(axes: ClockAxisStyle, isAnimated: Boolean) {
+ childViews.forEach { view -> view.updateAxes(axes, isAnimated) }
requestLayout()
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
index 377a24c2899b..05c9818f0c57 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
@@ -200,11 +200,11 @@ open class SimpleDigitalClockTextView(
invalidate()
}
- fun updateAxes(lsAxes: ClockAxisStyle) {
+ fun updateAxes(lsAxes: ClockAxisStyle, isAnimated: Boolean) {
lsFontVariation = lsAxes.toFVar()
aodFontVariation = lsAxes.copyWith(fixedAodAxes).toFVar()
fidgetFontVariation = buildFidgetVariation(lsAxes).toFVar()
- logger.updateAxes(lsFontVariation, aodFontVariation)
+ logger.updateAxes(lsFontVariation, aodFontVariation, isAnimated)
lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation)
typeface = lockScreenPaint.typeface
@@ -212,7 +212,15 @@ open class SimpleDigitalClockTextView(
textBounds = lockScreenPaint.getTextBounds(text)
targetTextBounds = textBounds
- textAnimator.setTextStyle(TextAnimator.Style(fVar = lsFontVariation))
+ textAnimator.setTextStyle(
+ TextAnimator.Style(fVar = lsFontVariation),
+ TextAnimator.Animation(
+ animate = isAnimated && isAnimationEnabled,
+ duration = AXIS_CHANGE_ANIMATION_DURATION,
+ interpolator = aodDozingInterpolator,
+ ),
+ )
+
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
recomputeMaxSingleDigitSizes()
requestLayout()
@@ -651,6 +659,7 @@ open class SimpleDigitalClockTextView(
.compose()
val CHARGE_ANIMATION_DURATION = 500L
+ val AXIS_CHANGE_ANIMATION_DURATION = 400L
val FIDGET_ANIMATION_DURATION = 250L
val FIDGET_INTERPOLATOR = PathInterpolator(0.26873f, 0f, 0.45042f, 1f)
val FIDGET_DISTS =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
index a58f7f72f08a..ae5cd0196e72 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
@@ -41,6 +41,7 @@ import android.app.NotificationChannel;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.TestableLooper;
@@ -101,52 +102,53 @@ public class AssistantFeedbackControllerTest extends SysuiTestCase {
switchFlag("false");
// test flag disables logic with default values
assertEquals(STATUS_UNCHANGED, mAssistantFeedbackController.getFeedbackStatus(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED).getRanking()));
assertNull(mAssistantFeedbackController.getFeedbackIcon(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED).getRanking()));
// test that the flag disables logic with values that otherwise would return a value
assertEquals(STATUS_UNCHANGED, mAssistantFeedbackController.getFeedbackStatus(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED).getRanking()));
assertNull(mAssistantFeedbackController.getFeedbackIcon(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED).getRanking()));
}
@Test
public void testFeedback_noChange() {
switchFlag("true");
assertEquals(STATUS_UNCHANGED, mAssistantFeedbackController.getFeedbackStatus(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED).getRanking()));
assertNull(mAssistantFeedbackController.getFeedbackIcon(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED).getRanking()));
}
@Test
public void testFeedback_changedImportance() {
switchFlag("true");
- NotificationEntry entry = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_UNCHANGED);
- assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
-
- entry = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_LOW, RANKING_UNCHANGED);
- assertEquals(STATUS_SILENCED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
-
- entry = getEntry(IMPORTANCE_LOW, IMPORTANCE_MIN, RANKING_UNCHANGED);
- assertEquals(STATUS_DEMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
+ NotificationListenerService.Ranking ranking =
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_UNCHANGED).getRanking();
+ assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
+
+ ranking = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_LOW, RANKING_UNCHANGED).getRanking();
+ assertEquals(STATUS_SILENCED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
+
+ ranking = getEntry(IMPORTANCE_LOW, IMPORTANCE_MIN, RANKING_UNCHANGED).getRanking();
+ assertEquals(STATUS_DEMOTED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
}
@Test
public void testFeedback_changedRanking() {
switchFlag("true");
- NotificationEntry entry =
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_PROMOTED);
- assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
-
- entry = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_DEMOTED);
- assertEquals(STATUS_DEMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
+ NotificationListenerService.Ranking ranking =
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_PROMOTED).getRanking();
+ assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
+
+ ranking = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_DEMOTED).getRanking();
+ assertEquals(STATUS_DEMOTED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
}
@Test
@@ -155,7 +157,7 @@ public class AssistantFeedbackControllerTest extends SysuiTestCase {
FeedbackIcon expected = new FeedbackIcon(com.android.internal.R.drawable.ic_feedback_uprank,
com.android.internal.R.string.notification_feedback_indicator_promoted);
assertEquals(expected, mAssistantFeedbackController.getFeedbackIcon(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED).getRanking()));
}
private NotificationEntry getEntry(int oldImportance, int newImportance,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
index 101874807474..52f68bf4d729 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
@@ -25,7 +25,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -36,13 +38,15 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@RunWithLooper
class BundleEntryAdapterTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
private lateinit var underTest: BundleEntryAdapter
@get:Rule val setFlagsRule = SetFlagsRule()
+ private val factory: EntryAdapterFactory = kosmos.entryAdapterFactory
@Before
fun setUp() {
- underTest = BundleEntryAdapter(BundleEntry("key"))
+ underTest = factory.create(BundleEntry("key")) as BundleEntryAdapter
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
index 7449064bc65b..02c6a484bd43 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
@@ -29,6 +29,9 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.res.R
import com.android.systemui.statusbar.RankingBuilder
+import com.android.systemui.statusbar.notification.collection.coordinator.mockVisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.provider.mockHighPriorityProvider
import com.android.systemui.statusbar.notification.mockNotificationActivityStarter
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -41,9 +44,12 @@ import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -257,6 +263,109 @@ class NotificationEntryAdapterTest : SysuiTestCase() {
@Test
@EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun getRanking() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+ underTest = factory.create(entry) as NotificationEntryAdapter
+ assertThat(underTest.ranking).isEqualTo(entry.ranking)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun endLifetimeExtension() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+ val callback =
+ Mockito.mock(NotifLifetimeExtender.OnEndLifetimeExtensionCallback::class.java)
+
+ underTest = factory.create(entry) as NotificationEntryAdapter
+ underTest.endLifetimeExtension(callback, Mockito.mock(NotifLifetimeExtender::class.java))
+ verify(callback).onEndLifetimeExtension(any(), eq(entry))
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun onImportanceChanged() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+ underTest = factory.create(entry) as NotificationEntryAdapter
+
+ underTest.onImportanceChanged()
+ verify(kosmos.mockVisualStabilityCoordinator)
+ .temporarilyAllowSectionChanges(eq(entry), anyLong())
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun markForUserTriggeredMovement() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+ underTest = factory.create(entry) as NotificationEntryAdapter
+
+ assertThat(underTest.isMarkedForUserTriggeredMovement)
+ .isEqualTo(entry.isMarkedForUserTriggeredMovement)
+
+ underTest.markForUserTriggeredMovement()
+ assertThat(underTest.isMarkedForUserTriggeredMovement)
+ .isEqualTo(entry.isMarkedForUserTriggeredMovement)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isHighPriority() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+ underTest = factory.create(entry) as NotificationEntryAdapter
+
+ underTest.isHighPriority
+
+ verify(kosmos.mockHighPriorityProvider).isHighPriority(entry)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isBlockable() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+ underTest = factory.create(entry) as NotificationEntryAdapter
+
+ assertThat(underTest.isBlockable).isEqualTo(entry.isBlockable)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
fun canDragAndDrop() {
val pi = mock(PendingIntent::class.java)
Mockito.`when`(pi.isActivity).thenReturn(true)
@@ -436,7 +545,6 @@ class NotificationEntryAdapterTest : SysuiTestCase() {
underTest = factory.create(entry) as NotificationEntryAdapter
-
underTest.onEntryClicked(row)
verify(kosmos.mockNotificationActivityStarter).onNotificationClicked(entry, row)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
index 7fe97d27f273..928b0014dc52 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
@@ -15,12 +15,15 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -30,6 +33,9 @@ import com.android.systemui.statusbar.notification.collection.render.NotifGutsVi
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
import com.android.systemui.statusbar.notification.row.NotificationGuts
import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -45,12 +51,16 @@ import org.mockito.MockitoAnnotations.initMocks
@RunWith(AndroidJUnit4::class)
@RunWithLooper
class GutsCoordinatorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
private lateinit var coordinator: GutsCoordinator
private lateinit var notifLifetimeExtender: NotifLifetimeExtender
private lateinit var notifGutsViewListener: NotifGutsViewListener
private lateinit var entry1: NotificationEntry
private lateinit var entry2: NotificationEntry
+ private lateinit var entryAdapter1: EntryAdapter
+ private lateinit var entryAdapter2: EntryAdapter
@Mock private lateinit var notifGutsViewManager: NotifGutsViewManager
@Mock private lateinit var pipeline: NotifPipeline
@@ -73,12 +83,60 @@ class GutsCoordinatorTest : SysuiTestCase() {
notifLifetimeExtender.setCallback(lifetimeExtenderCallback)
entry1 = NotificationEntryBuilder().setId(1).build()
entry2 = NotificationEntryBuilder().setId(2).build()
+ entryAdapter1 = kosmos.entryAdapterFactory.create(entry1)
+ entryAdapter2 = kosmos.entryAdapterFactory.create(entry2)
whenever(notificationGuts.gutsContent).thenReturn(mock(GutsContent::class.java))
}
@Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
fun testSimpleLifetimeExtension() {
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entryAdapter1, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entryAdapter1)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun testDoubleOpenLifetimeExtension() {
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entryAdapter1, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ notifGutsViewListener.onGutsOpen(entryAdapter1, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entryAdapter1)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun testTwoEntryLifetimeExtension() {
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entryAdapter1, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entryAdapter2, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entryAdapter1)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entryAdapter2)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry2)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
+ }
+
+ @Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
+ fun testSimpleLifetimeExtension_entry() {
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
notifGutsViewListener.onGutsClose(entry1)
@@ -87,7 +145,8 @@ class GutsCoordinatorTest : SysuiTestCase() {
}
@Test
- fun testDoubleOpenLifetimeExtension() {
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
+ fun testDoubleOpenLifetimeExtension_entry() {
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
@@ -99,7 +158,8 @@ class GutsCoordinatorTest : SysuiTestCase() {
}
@Test
- fun testTwoEntryLifetimeExtension() {
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
+ fun testTwoEntryLifetimeExtension_entry() {
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
index 0947cd5aaabb..e808deb1d5ad 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
@@ -44,6 +44,7 @@ import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.view.LayoutInflater;
import android.view.View;
@@ -132,7 +133,7 @@ public class FeedbackInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_SetsTextApplicationName() {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(),
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
mMockNotificationRow, mAssistantFeedbackController, mStatusBarService,
mNotificationGutsManager);
final TextView textView = mFeedbackInfo.findViewById(R.id.pkg_name);
@@ -144,7 +145,7 @@ public class FeedbackInfoTest extends SysuiTestCase {
final Drawable iconDrawable = mock(Drawable.class);
when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
.thenReturn(iconDrawable);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(),
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
mMockNotificationRow, mAssistantFeedbackController, mStatusBarService,
mNotificationGutsManager);
final ImageView iconView = mFeedbackInfo.findViewById(R.id.pkg_icon);
@@ -153,9 +154,11 @@ public class FeedbackInfoTest extends SysuiTestCase {
@Test
public void testPrompt_silenced() {
- when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
+ when(mAssistantFeedbackController.getFeedbackStatus(
+ any(NotificationListenerService.Ranking.class)))
.thenReturn(STATUS_SILENCED);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
assertEquals("This notification was automatically demoted to Silent by the system. "
@@ -165,9 +168,11 @@ public class FeedbackInfoTest extends SysuiTestCase {
@Test
public void testPrompt_promoted() {
- when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
+ when(mAssistantFeedbackController.getFeedbackStatus(
+ any(NotificationListenerService.Ranking.class)))
.thenReturn(STATUS_PROMOTED);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
assertEquals("This notification was automatically ranked higher in your shade. "
@@ -177,9 +182,11 @@ public class FeedbackInfoTest extends SysuiTestCase {
@Test
public void testPrompt_alerted() {
- when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
+ when(mAssistantFeedbackController.getFeedbackStatus(
+ any(NotificationListenerService.Ranking.class)))
.thenReturn(STATUS_ALERTED);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
assertEquals("This notification was automatically promoted to Default by the system. "
@@ -189,9 +196,11 @@ public class FeedbackInfoTest extends SysuiTestCase {
@Test
public void testPrompt_demoted() {
- when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
+ when(mAssistantFeedbackController.getFeedbackStatus(
+ any(NotificationListenerService.Ranking.class)))
.thenReturn(STATUS_DEMOTED);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
assertEquals("This notification was automatically ranked lower in your shade. "
@@ -201,7 +210,8 @@ public class FeedbackInfoTest extends SysuiTestCase {
@Test
public void testPositiveFeedback() {
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
final View yes = mFeedbackInfo.findViewById(R.id.yes);
@@ -218,7 +228,8 @@ public class FeedbackInfoTest extends SysuiTestCase {
any(NotificationMenuRowPlugin.MenuItem.class)))
.thenReturn(true);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
final View no = mFeedbackInfo.findViewById(R.id.no);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
index 387c62d76083..324487b121bc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
@@ -67,15 +67,19 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.AssistantFeedbackController
import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.notification.collection.provider.mockHighPriorityProvider
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
import com.android.systemui.statusbar.notification.row.icon.appIconProvider
import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.testKosmos
@@ -263,7 +267,11 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
assertEquals(View.INVISIBLE.toLong(), guts.visibility.toLong())
executor.runAllReady()
verify(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>())
- verify(headsUpManager).setGutsShown(realRow.entry, true)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(true))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow.entry, true)
+ }
assertEquals(View.VISIBLE.toLong(), guts.visibility.toLong())
gutsManager.closeAndSaveGuts(false, false, true, 0, 0, false)
@@ -271,7 +279,11 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean())
verify(row, times(1)).setGutsView(any<MenuItem>())
executor.runAllReady()
- verify(headsUpManager).setGutsShown(realRow.entry, false)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(false))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow.entry, false)
+ }
}
@Test
@@ -301,7 +313,11 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
verify(guts).closeControls(anyInt(), anyInt(), eq(false), eq(false))
verify(row, times(1)).setGutsView(any<MenuItem>())
executor.runAllReady()
- verify(headsUpManager).setGutsShown(realRow.entry, false)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(false))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow.entry, false)
+ }
}
@Test
@@ -505,17 +521,22 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
@Throws(Exception::class)
fun testInitializeNotificationInfoView_highPriority() {
val notificationInfoView: NotificationInfo = mock()
- val row = spy(helper.createRow())
+ val row = createTestNotificationRow()
val entry = row.entry
NotificationEntryHelper.modifyRanking(entry)
.setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE)
.setImportance(NotificationManager.IMPORTANCE_HIGH)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
whenever(highPriorityProvider.isHighPriority(entry)).thenReturn(true)
+ whenever(kosmos.mockHighPriorityProvider.isHighPriority(entry)).thenReturn(true)
val statusBarNotification = entry.sbn
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
@@ -527,15 +548,17 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
eq(channelEditorDialogController),
any<PackageDemotionInteractor>(),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
/* isDeviceProvisioned = */ eq(false),
/* isNonblockable = */ eq(false),
- /* isDismissable = */ eq(true),
+ /* isDismissable = */ eq(false),
/* wasShownHighPriority = */ eq(true),
eq(assistantFeedbackController),
eq(metricsLogger),
@@ -547,17 +570,21 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
@Throws(Exception::class)
fun testInitializeNotificationInfoView_PassesAlongProvisionedState() {
val notificationInfoView: NotificationInfo = mock()
- val row = spy(helper.createRow())
+ val row = createTestNotificationRow()
NotificationEntryHelper.modifyRanking(row.entry)
.setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
val statusBarNotification = row.entry.sbn
val entry = row.entry
whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
@@ -569,15 +596,17 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
eq(channelEditorDialogController),
any<PackageDemotionInteractor>(),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
/* isDeviceProvisioned = */ eq(true),
/* isNonblockable = */ eq(false),
- /* isDismissable = */ eq(true),
+ /* isDismissable = */ eq(false),
/* wasShownHighPriority = */ eq(false),
eq(assistantFeedbackController),
eq(metricsLogger),
@@ -589,15 +618,19 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
@Throws(Exception::class)
fun testInitializeNotificationInfoView_withInitialAction() {
val notificationInfoView: NotificationInfo = mock()
- val row = spy(helper.createRow())
+ val row = createTestNotificationRow()
NotificationEntryHelper.modifyRanking(row.entry)
.setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
val statusBarNotification = row.entry.sbn
val entry = row.entry
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
@@ -609,15 +642,17 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
eq(channelEditorDialogController),
any<PackageDemotionInteractor>(),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
/* isDeviceProvisioned = */ eq(false),
/* isNonblockable = */ eq(false),
- /* isDismissable = */ eq(true),
+ /* isDismissable = */ eq(false),
/* wasShownHighPriority = */ eq(false),
eq(assistantFeedbackController),
eq(metricsLogger),
@@ -639,6 +674,7 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
NotificationEntryHelper.modifyRanking(row.entry)
.setChannel(testNotificationChannel)
.build()
+ row.entryAdapter = kosmos.entryAdapterFactory.create(row.entry)
return row
} catch (e: Exception) {
fail()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt
index 16663def16a4..b2521b0ce766 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt
@@ -62,13 +62,16 @@ import com.android.systemui.kosmos.testCase
import com.android.systemui.res.R
import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.notification.AssistantFeedbackController
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.coordinator.mockVisualStabilityCoordinator
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
import com.android.systemui.statusbar.notification.row.icon.mockAppIconProvider
import com.android.systemui.statusbar.notification.row.icon.mockNotificationIconStyleProvider
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.testKosmos
import com.android.telecom.telecomManager
import com.google.common.truth.Truth.assertThat
@@ -100,6 +103,7 @@ class NotificationInfoTest : SysuiTestCase() {
private lateinit var classifiedNotificationChannel: NotificationChannel
private lateinit var sbn: StatusBarNotification
private lateinit var entry: NotificationEntry
+ private lateinit var entryAdapter: EntryAdapter
private val mockPackageManager = kosmos.mockPackageManager
private val mockAppIconProvider = kosmos.mockAppIconProvider
@@ -189,7 +193,12 @@ class NotificationInfoTest : SysuiTestCase() {
null,
0,
)
- entry = NotificationEntryBuilder().setSbn(sbn).build()
+ entry =
+ NotificationEntryBuilder()
+ .setSbn(sbn)
+ .updateRanking { it.setChannel(notificationChannel) }
+ .build()
+ entryAdapter = kosmos.entryAdapterFactory.create(entry)
whenever(assistantFeedbackController.isFeedbackEnabled).thenReturn(false)
whenever(assistantFeedbackController.getInlineDescriptionResource(any()))
.thenReturn(R.string.notification_channel_summary_automatic)
@@ -263,7 +272,7 @@ class NotificationInfoTest : SysuiTestCase() {
.thenReturn(applicationInfo)
whenever(mockPackageManager.getApplicationLabel(any())).thenReturn("Other")
- val entry = NotificationEntryBuilder().setSbn(sbn).build()
+ val entry = NotificationEntryBuilder(entry).setSbn(sbn).build()
bindNotification(entry = entry)
val nameView = underTest.findViewById<TextView>(R.id.delegate_name)
assertThat(nameView.visibility).isEqualTo(VISIBLE)
@@ -304,6 +313,10 @@ class NotificationInfoTest : SysuiTestCase() {
@Test
fun testBindNotification_DefaultChannelDoesNotUseChannelName() {
+ entry =
+ NotificationEntryBuilder(entry)
+ .updateRanking { it.setChannel(defaultNotificationChannel) }
+ .build()
bindNotification(notificationChannel = defaultNotificationChannel)
val textView = underTest.findViewById<TextView>(R.id.channel_name)
assertThat(textView.visibility).isEqualTo(GONE)
@@ -320,6 +333,10 @@ class NotificationInfoTest : SysuiTestCase() {
)
)
.thenReturn(10)
+ entry =
+ NotificationEntryBuilder(entry)
+ .updateRanking { it.setChannel(notificationChannel) }
+ .build()
bindNotification(notificationChannel = defaultNotificationChannel)
val textView = underTest.findViewById<TextView>(R.id.channel_name)
assertThat(textView.visibility).isEqualTo(VISIBLE)
@@ -747,7 +764,13 @@ class NotificationInfoTest : SysuiTestCase() {
underTest.findViewById<View>(R.id.done).performClick()
underTest.handleCloseControls(true, false)
- verify(onUserInteractionCallback).onImportanceChanged(entry)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockVisualStabilityCoordinator)
+ .temporarilyAllowSectionChanges(eq(entry), any())
+ } else {
+ verify(onUserInteractionCallback).onImportanceChanged(entry)
+ }
+
assertThat(underTest.shouldBeSavedOnClose()).isFalse()
}
@@ -866,7 +889,12 @@ class NotificationInfoTest : SysuiTestCase() {
@EnableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
@Throws(RemoteException::class)
fun testBindNotification_SetsFeedbackLink_isReservedChannel() {
- entry.setRanking(RankingBuilder(entry.ranking).setSummarization("something").build())
+ entry.setRanking(
+ RankingBuilder(entry.ranking)
+ .setSummarization("something")
+ .setChannel(classifiedNotificationChannel)
+ .build()
+ )
val latch = CountDownLatch(1)
bindNotification(
notificationChannel = classifiedNotificationChannel,
@@ -927,6 +955,7 @@ class NotificationInfoTest : SysuiTestCase() {
pkg: String = TEST_PACKAGE_NAME,
notificationChannel: NotificationChannel = this.notificationChannel,
entry: NotificationEntry = this.entry,
+ entryAdapter: EntryAdapter = this.entryAdapter,
onSettingsClick: NotificationInfo.OnSettingsClickListener? = null,
onAppSettingsClick: NotificationInfo.OnAppSettingsClickListener? = null,
onFeedbackClickListener: NotificationInfo.OnFeedbackClickListener? = null,
@@ -948,8 +977,10 @@ class NotificationInfoTest : SysuiTestCase() {
channelEditorDialogController,
packageDemotionInteractor,
pkg,
- notificationChannel,
+ entry.ranking,
+ entry.sbn,
entry,
+ entryAdapter,
onSettingsClick,
onAppSettingsClick,
onFeedbackClickListener,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index e6b2c2541447..bda2ba79d6b5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -81,6 +81,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
@@ -746,7 +747,9 @@ public class NotificationTestHelper {
mock(PeopleNotificationIdentifier.class),
mock(NotificationIconStyleProvider.class),
mock(VisualStabilityCoordinator.class),
- mock(NotificationActionClickManager.class)
+ mock(NotificationActionClickManager.class),
+ mock(HighPriorityProvider.class),
+ mock(HeadsUpManager.class)
).create(entry);
row.initialize(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index 57b0f3f8d8c5..0eb60163766c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -40,6 +40,7 @@ import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.TestableLooper;
import android.text.SpannableString;
@@ -81,7 +82,6 @@ public class PartialConversationInfoTest extends SysuiTestCase {
private TestableLooper mTestableLooper;
private PartialConversationInfo mInfo;
private NotificationChannel mNotificationChannel;
- private NotificationChannel mDefaultNotificationChannel;
private StatusBarNotification mSbn;
private NotificationEntry mEntry;
@@ -141,15 +141,14 @@ public class PartialConversationInfoTest extends SysuiTestCase {
// Some test channels.
mNotificationChannel = new NotificationChannel(
TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
- mDefaultNotificationChannel = new NotificationChannel(
- NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME,
- IMPORTANCE_LOW);
Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
.setContentTitle(new SpannableString("title"))
.build();
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
n, UserHandle.CURRENT, null, 0);
- mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+ mEntry = new NotificationEntryBuilder().setSbn(mSbn).updateRanking(rankingBuilder -> {
+ rankingBuilder.setChannel(mNotificationChannel);
+ }).build();
}
@Test
@@ -160,8 +159,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -178,8 +177,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -194,8 +193,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -219,8 +218,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- entry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -237,8 +236,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
@@ -260,8 +259,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
@@ -282,8 +281,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -298,8 +297,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
},
@@ -316,8 +315,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
true);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java
index 209dfb2d2ed6..9b86412fc051 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java
@@ -31,6 +31,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
import android.testing.TestableLooper;
@@ -46,9 +47,16 @@ import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
+import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor;
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
@@ -74,6 +82,8 @@ public class PromotedNotificationInfoTest extends SysuiTestCase {
private NotificationChannel mNotificationChannel;
private StatusBarNotification mSbn;
private NotificationEntry mEntry;
+ private NotificationListenerService.Ranking mRanking;
+ private EntryAdapter mEntryAdapter;
private UiEventLoggerFake mUiEventLogger = new UiEventLoggerFake();
@Rule
@@ -110,7 +120,20 @@ public class PromotedNotificationInfoTest extends SysuiTestCase {
notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, applicationInfo);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
notification, UserHandle.getUserHandleForUid(TEST_UID), null, 0);
- mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+ mEntry = new NotificationEntryBuilder().setSbn(mSbn).updateRanking(rankingBuilder -> {
+ rankingBuilder.setChannel(mNotificationChannel);
+ }).build();
+ mEntryAdapter = new EntryAdapterFactoryImpl(
+ mock(NotificationActivityStarter.class),
+ mock(MetricsLogger.class),
+ mock(PeopleNotificationIdentifier.class),
+ mock(NotificationIconStyleProvider.class),
+ mock(VisualStabilityCoordinator.class),
+ mock(NotificationActionClickManager.class),
+ mock(HighPriorityProvider.class),
+ mock(HeadsUpManager.class)
+ ).create(mEntry);
+ mRanking = mEntry.getRanking();
when(mAssistantFeedbackController.isFeedbackEnabled()).thenReturn(false);
mTestableLooper = TestableLooper.get(this);
@@ -143,8 +166,10 @@ public class PromotedNotificationInfoTest extends SysuiTestCase {
mChannelEditorDialogController,
mPackageDemotionInteractor,
TEST_PACKAGE_NAME,
- mNotificationChannel,
+ mRanking,
+ mSbn,
mEntry,
+ mEntryAdapter,
null,
null,
null,
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt
index 77c18eac289c..894327690b5e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt
@@ -61,4 +61,7 @@ interface ClockAnimations {
/** Runs when an animation when the view is tapped on the lockscreen */
fun onFidgetTap(x: Float, y: Float)
+
+ /** Update reactive axes for this clock */
+ fun onFontAxesChanged(style: ClockAxisStyle)
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt
index 0fc3470716fe..7c0e4866b00d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt
@@ -42,7 +42,4 @@ interface ClockEvents {
/** Call with zen/dnd information */
fun onZenDataChanged(data: ZenData)
-
- /** Update reactive axes for this clock */
- fun onFontAxesChanged(axes: ClockAxisStyle)
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
index 5b67edda73cc..4f04aaa33b24 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
@@ -90,10 +90,11 @@ class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) :
}
}
- fun updateAxes(lsFVar: String, aodFVar: String) {
- i({ "updateAxes(LS = $str1, AOD = $str2)" }) {
+ fun updateAxes(lsFVar: String, aodFVar: String, isAnimated: Boolean) {
+ i({ "updateAxes(LS = $str1, AOD = $str2, isAnimated=$bool1)" }) {
str1 = lsFVar
str2 = aodFVar
+ bool1 = isAnimated
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index 24b955152093..7f46613936ac 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -327,9 +327,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
setupDeviceListView(dialog, hearingDeviceItemList);
setupPairNewDeviceButton(dialog);
setupPresetSpinner(dialog, activeHearingDevice);
- if (com.android.settingslib.flags.Flags.hearingDevicesInputRoutingControl()
- && com.android.systemui.Flags
- .hearingDevicesInputRoutingUiImprovement()) {
+ if (com.android.settingslib.flags.Flags.hearingDevicesInputRoutingControl()) {
setupInputRoutingSpinner(dialog, activeHearingDevice);
}
if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index b16c416fb9df..dbaa90c10313 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -52,6 +52,7 @@ import android.os.PowerManager;
import android.os.Trace;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
+import android.provider.Settings;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
@@ -920,12 +921,21 @@ public class UdfpsController implements DozeReceiver, Dumpable {
true /* isAod */);
};
- if (mScreenOn) {
+ if (isScreenOffUnlockEnabled() || mScreenOn) {
mAodInterruptRunnable.run();
mAodInterruptRunnable = null;
}
}
+ private boolean isScreenOffUnlockEnabled() {
+ return mContext.getResources().getBoolean(R.bool.config_screen_off_udfps_enabled)
+ && Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREEN_OFF_UNLOCK_UDFPS_ENABLED,
+ 0,
+ mContext.getUserId()) != 0;
+ }
+
/**
* Add a callback for fingerUp and fingerDown events
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
index d0c6a3e6a3ef..bf1f971c0f8c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
@@ -580,7 +580,23 @@ public class MediaSwitchingController
synchronized (mMediaDevicesLock) {
if (!mLocalMediaManager.isPreferenceRouteListingExist()) {
attachRangeInfo(devices);
- Collections.sort(devices, Comparator.naturalOrder());
+ if (Flags.enableOutputSwitcherDeviceGrouping()) {
+ List<MediaDevice> selectedDevices = new ArrayList<>();
+ Set<String> selectedDeviceIds =
+ getSelectedMediaDevice().stream()
+ .map(MediaDevice::getId)
+ .collect(Collectors.toSet());
+ for (MediaDevice device : devices) {
+ if (selectedDeviceIds.contains(device.getId())) {
+ selectedDevices.add(device);
+ }
+ }
+ devices.removeAll(selectedDevices);
+ Collections.sort(devices, Comparator.naturalOrder());
+ devices.addAll(0, selectedDevices);
+ } else {
+ Collections.sort(devices, Comparator.naturalOrder());
+ }
}
if (Flags.fixOutputMediaItemListIndexOutOfBoundsException()) {
// For the first time building list, to make sure the top device is the connected
diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
index 917869a66ca4..3e6f234a3663 100644
--- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
@@ -30,8 +30,10 @@ import android.graphics.Rect;
import android.graphics.RenderEffect;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Looper;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -52,6 +54,9 @@ import java.util.concurrent.Executor;
* need to be careful to synchronize when necessary.
*/
public class ScrimView extends View {
+ private static final String TAG = "ScrimView";
+ private static final boolean isDebugLoggable = Build.isDebuggable() || Log.isLoggable(TAG,
+ Log.DEBUG);
private final Object mColorLock = new Object();
@@ -381,12 +386,21 @@ public class ScrimView extends View {
*/
public void setBlurRadius(float blurRadius) {
if (blurRadius > 0) {
+ debugLog("Apply blur RenderEffect to ScrimView " + mScrimName + " for radius "
+ + blurRadius);
setRenderEffect(RenderEffect.createBlurEffect(
blurRadius,
blurRadius,
Shader.TileMode.CLAMP));
} else {
+ debugLog("Resetting blur RenderEffect to ScrimView " + mScrimName);
setRenderEffect(null);
}
}
+
+ private void debugLog(String logMsg) {
+ if (isDebugLoggable) {
+ Log.d(TAG, logMsg);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index b90624245cc5..fcfce1281722 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -989,8 +989,10 @@ public final class NotificationPanelViewController implements
mBlurConfig.getMaxBlurRadiusPx(),
Shader.TileMode.CLAMP);
}
+ debugLog("Applying blur RenderEffect to shade.");
mView.setRenderEffect(mBlurRenderEffect);
} else {
+ debugLog("Resetting blur RenderEffect on shade.");
mView.setRenderEffect(null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
index 11ec2edb36f6..e9a6ad26f5e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
@@ -108,13 +108,12 @@ public class AssistantFeedbackController {
/**
* Get the feedback status according to assistant's adjustments
*
- * @param entry Notification Entry to show feedback for
+ * @param ranking Ranking of the notification show feedback for
*/
- public int getFeedbackStatus(NotificationEntry entry) {
+ public int getFeedbackStatus(Ranking ranking) {
if (!isFeedbackEnabled()) {
return STATUS_UNCHANGED;
}
- Ranking ranking = entry.getRanking();
int oldImportance = ranking.getChannel().getImportance();
int newImportance = ranking.getImportance();
if (oldImportance < NotificationManager.IMPORTANCE_DEFAULT
@@ -138,11 +137,11 @@ public class AssistantFeedbackController {
* Get the feedback indicator image and content description resources according to assistant's
* changes on this notification's rank or importance.
*
- * @param entry Notification Entry to show feedback for
+ * @param ranking Ranking of the notification to show feedback for
*/
@Nullable
- public FeedbackIcon getFeedbackIcon(NotificationEntry entry) {
- int feedbackStatus = getFeedbackStatus(entry);
+ public FeedbackIcon getFeedbackIcon(Ranking ranking) {
+ int feedbackStatus = getFeedbackStatus(ranking);
return mIcons.get(feedbackStatus);
}
@@ -150,10 +149,10 @@ public class AssistantFeedbackController {
* Get the inline settings description resource according to assistant's changes on this
* notification's rank or importance.
*
- * @param entry Notification Entry to show feedback for
+ * @param ranking Ranking of the notification to show feedback for
*/
- public int getInlineDescriptionResource(NotificationEntry entry) {
- int feedbackStatus = getFeedbackStatus(entry);
+ public int getInlineDescriptionResource(Ranking ranking) {
+ int feedbackStatus = getFeedbackStatus(ranking);
switch (feedbackStatus) {
case STATUS_ALERTED:
return com.android.systemui.res.R.string.notification_channel_summary_automatic_alerted;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
index be17ae56c315..6a3f8f166c34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
@@ -19,14 +19,20 @@ package com.android.systemui.statusbar.notification.collection
import android.app.Notification
import android.content.Context
import android.os.Build
+import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.util.Log
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.icon.IconPack
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import kotlinx.coroutines.flow.StateFlow
-class BundleEntryAdapter(val entry: BundleEntry) : EntryAdapter {
+class BundleEntryAdapter(
+ private val highPriorityProvider: HighPriorityProvider,
+ val entry: BundleEntry,
+) : EntryAdapter {
/** TODO (b/394483200): convert to PipelineEntry.ROOT_ENTRY when pipeline is migrated? */
override fun getParent(): GroupEntry {
return GroupEntry.ROOT_ENTRY
@@ -94,6 +100,41 @@ class BundleEntryAdapter(val entry: BundleEntry) : EntryAdapter {
return null
}
+ override fun getRanking(): NotificationListenerService.Ranking? {
+ return null
+ }
+
+ override fun endLifetimeExtension(
+ callback: NotifLifetimeExtender.OnEndLifetimeExtensionCallback?,
+ extender: NotifLifetimeExtender,
+ ) {
+ Log.wtf(TAG, "endLifetimeExtension() called")
+ }
+
+ override fun onImportanceChanged() {
+ Log.wtf(TAG, "onImportanceChanged() called")
+ }
+
+ override fun markForUserTriggeredMovement() {
+ Log.wtf(TAG, "markForUserTriggeredMovement() called")
+ }
+
+ override fun isMarkedForUserTriggeredMovement(): Boolean {
+ return false
+ }
+
+ override fun isHighPriority(): Boolean {
+ return highPriorityProvider.isHighPriority(entry)
+ }
+
+ override fun setInlineControlsShown(currentlyVisible: Boolean) {
+ // nothing to do, yet
+ }
+
+ override fun isBlockable(): Boolean {
+ return false
+ }
+
override fun canDragAndDrop(): Boolean {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
index 3757ebfb9986..16d9c787d435 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
@@ -17,11 +17,13 @@
package com.android.systemui.statusbar.notification.collection;
import android.content.Context;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.icon.IconPack;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -123,6 +125,40 @@ public interface EntryAdapter {
@Nullable
StatusBarNotification getSbn();
+ /**
+ * Returns the ranking that backs this row, if present
+ */
+ @Nullable
+ NotificationListenerService.Ranking getRanking();
+
+ void endLifetimeExtension(
+ @Nullable NotifLifetimeExtender.OnEndLifetimeExtensionCallback callback,
+ @NonNull NotifLifetimeExtender extender);
+
+
+ void onImportanceChanged();
+
+ /**
+ * Use when a change has been made to the underlying object that will both rerank the object
+ * in the shade and change something about its appearance to delay the appearance change until
+ * the ranking reordering is likely to have settled.
+ */
+ void markForUserTriggeredMovement();
+
+ /**
+ * Determines whether a row is considered 'high priority'.
+ *
+ * Notifications that are high priority are visible on the lock screen/status bar and in the top
+ * section in the shade.
+ */
+ boolean isHighPriority();
+
+ boolean isMarkedForUserTriggeredMovement();
+
+ void setInlineControlsShown(boolean currentlyVisible);
+
+ boolean isBlockable();
+
boolean canDragAndDrop();
boolean isBubble();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
index a5169865c3c9..2fce19c2becb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
@@ -19,6 +19,8 @@ package com.android.systemui.statusbar.notification.collection
import com.android.internal.logging.MetricsLogger
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.row.NotificationActionClickManager
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
@@ -34,6 +36,8 @@ constructor(
private val iconStyleProvider: NotificationIconStyleProvider,
private val visualStabilityCoordinator: VisualStabilityCoordinator,
private val notificationActionClickManager: NotificationActionClickManager,
+ private val highPriorityProvider: HighPriorityProvider,
+ private val headsUpManager: HeadsUpManager,
) : EntryAdapterFactory {
override fun create(entry: PipelineEntry): EntryAdapter {
return if (entry is NotificationEntry) {
@@ -44,10 +48,12 @@ constructor(
iconStyleProvider,
visualStabilityCoordinator,
notificationActionClickManager,
+ highPriorityProvider,
+ headsUpManager,
entry,
)
} else {
- BundleEntryAdapter((entry as BundleEntry))
+ BundleEntryAdapter(highPriorityProvider, (entry as BundleEntry))
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index b5ab0920a470..c94289c3befa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -1030,7 +1030,7 @@ public final class NotificationEntry extends ListEntry {
}
/**
- * Mark this entry for movement triggered by a user action (ex: changing the priorirty of a
+ * Mark this entry for movement triggered by a user action (ex: changing the priority of a
* conversation). This can then be used for custom animations.
*/
public void markForUserTriggeredMovement(boolean marked) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
index a23c5a3ea9f2..339a999e1535 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
@@ -17,10 +17,15 @@
package com.android.systemui.statusbar.notification.collection
import android.content.Context
+import android.os.SystemClock
+import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import com.android.internal.logging.MetricsLogger
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
import com.android.systemui.statusbar.notification.icon.IconPack
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -35,6 +40,8 @@ class NotificationEntryAdapter(
private val iconStyleProvider: NotificationIconStyleProvider,
private val visualStabilityCoordinator: VisualStabilityCoordinator,
private val notificationActionClickManager: NotificationActionClickManager,
+ private val highPriorityProvider: HighPriorityProvider,
+ private val headsUpManager: HeadsUpManager,
private val entry: NotificationEntry,
) : EntryAdapter {
@@ -110,6 +117,41 @@ class NotificationEntryAdapter(
return entry.sbn
}
+ override fun getRanking(): NotificationListenerService.Ranking? {
+ return entry.ranking
+ }
+
+ override fun endLifetimeExtension(
+ callback: NotifLifetimeExtender.OnEndLifetimeExtensionCallback?,
+ extender: NotifLifetimeExtender,
+ ) {
+ callback?.onEndLifetimeExtension(extender, entry)
+ }
+
+ override fun onImportanceChanged() {
+ visualStabilityCoordinator.temporarilyAllowSectionChanges(entry, SystemClock.uptimeMillis())
+ }
+
+ override fun markForUserTriggeredMovement() {
+ entry.markForUserTriggeredMovement(true)
+ }
+
+ override fun isMarkedForUserTriggeredMovement(): Boolean {
+ return entry.isMarkedForUserTriggeredMovement
+ }
+
+ override fun isHighPriority(): Boolean {
+ return highPriorityProvider.isHighPriority(entry)
+ }
+
+ override fun setInlineControlsShown(currentlyVisible: Boolean) {
+ headsUpManager.setGutsShown(entry, currentlyVisible)
+ }
+
+ override fun isBlockable(): Boolean {
+ return entry.isBlockable
+ }
+
override fun canDragAndDrop(): Boolean {
val canBubble: Boolean = entry.canBubble()
val notif = entry.sbn.notification
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
index 9045aac6ea6f..754f89191684 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
@@ -18,9 +18,10 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.util.ArraySet
import com.android.systemui.Dumpable
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.notification.collection.PipelineEntry
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.PipelineEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
@@ -28,6 +29,7 @@ import com.android.systemui.statusbar.notification.collection.render.NotifGutsVi
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
import com.android.systemui.statusbar.notification.row.NotificationGuts
import com.android.systemui.statusbar.notification.row.NotificationGutsManager
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.util.asIndenting
import com.android.systemui.util.printCollection
import com.android.systemui.util.println
@@ -38,23 +40,25 @@ import javax.inject.Inject
private const val TAG = "GutsCoordinator"
/**
- * Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline.
- * Specifically, this just adds the lifetime extension necessary to keep guts from disappearing.
+ * Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline. Specifically,
+ * this just adds the lifetime extension necessary to keep guts from disappearing.
*/
@CoordinatorScope
-class GutsCoordinator @Inject constructor(
+class GutsCoordinator
+@Inject
+constructor(
private val notifGutsViewManager: NotifGutsViewManager,
private val logger: GutsCoordinatorLogger,
- dumpManager: DumpManager
+ dumpManager: DumpManager,
) : Coordinator, Dumpable {
- /** Keys of any Notifications for which we've been told the guts are open */
+ /** Keys of any Notifications for which we've been told the guts are open */
private val notifsWithOpenGuts = ArraySet<String>()
- /** Keys of any Notifications we've extended the lifetime for, based on guts */
+ /** Keys of any Notifications we've extended the lifetime for, based on guts */
private val notifsExtendingLifetime = ArraySet<String>()
- /** Callback for ending lifetime extension */
+ /** Callback for ending lifetime extension */
private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null
init {
@@ -66,55 +70,77 @@ class GutsCoordinator @Inject constructor(
pipeline.addNotificationLifetimeExtender(mLifetimeExtender)
}
- override fun dump(pw: PrintWriter, args: Array<String>) = pw.asIndenting().run {
- withIncreasedIndent {
- printCollection("notifsWithOpenGuts", notifsWithOpenGuts)
- printCollection("notifsExtendingLifetime", notifsExtendingLifetime)
- println("onEndLifetimeExtensionCallback", onEndLifetimeExtensionCallback)
+ override fun dump(pw: PrintWriter, args: Array<String>) =
+ pw.asIndenting().run {
+ withIncreasedIndent {
+ printCollection("notifsWithOpenGuts", notifsWithOpenGuts)
+ printCollection("notifsExtendingLifetime", notifsExtendingLifetime)
+ println("onEndLifetimeExtensionCallback", onEndLifetimeExtensionCallback)
+ }
}
- }
- private val mLifetimeExtender: NotifLifetimeExtender = object : NotifLifetimeExtender {
- override fun getName(): String {
- return TAG
- }
+ private val mLifetimeExtender: NotifLifetimeExtender =
+ object : NotifLifetimeExtender {
+ override fun getName(): String {
+ return TAG
+ }
- override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
- onEndLifetimeExtensionCallback = callback
- }
+ override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
+ onEndLifetimeExtensionCallback = callback
+ }
- override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
- val isShowingGuts = isCurrentlyShowingGuts(entry)
- if (isShowingGuts) {
- notifsExtendingLifetime.add(entry.key)
+ override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
+ val isShowingGuts = isCurrentlyShowingGuts(entry)
+ if (isShowingGuts) {
+ notifsExtendingLifetime.add(entry.key)
+ }
+ return isShowingGuts
}
- return isShowingGuts
- }
- override fun cancelLifetimeExtension(entry: NotificationEntry) {
- notifsExtendingLifetime.remove(entry.key)
+ override fun cancelLifetimeExtension(entry: NotificationEntry) {
+ notifsExtendingLifetime.remove(entry.key)
+ }
}
- }
- private val mGutsListener: NotifGutsViewListener = object : NotifGutsViewListener {
- override fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts) {
- logger.logGutsOpened(entry.key, guts)
- if (guts.isLeavebehind) {
- // leave-behind guts should not extend the lifetime of the notification
+ private val mGutsListener: NotifGutsViewListener =
+ object : NotifGutsViewListener {
+ override fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts) {
+ NotificationBundleUi.assertInLegacyMode()
+ logger.logGutsOpened(entry.key, guts)
+ if (guts.isLeavebehind) {
+ // leave-behind guts should not extend the lifetime of the notification
+ closeGutsAndEndLifetimeExtension(entry)
+ } else {
+ notifsWithOpenGuts.add(entry.key)
+ }
+ }
+
+ override fun onGutsClose(entry: NotificationEntry) {
+ NotificationBundleUi.assertInLegacyMode()
+ logger.logGutsClosed(entry.key)
closeGutsAndEndLifetimeExtension(entry)
- } else {
- notifsWithOpenGuts.add(entry.key)
}
- }
- override fun onGutsClose(entry: NotificationEntry) {
- logger.logGutsClosed(entry.key)
- closeGutsAndEndLifetimeExtension(entry)
+ override fun onGutsOpen(entryAdapter: EntryAdapter, guts: NotificationGuts) {
+ NotificationBundleUi.isUnexpectedlyInLegacyMode()
+ logger.logGutsOpened(entryAdapter.key, guts)
+ if (guts.isLeavebehind) {
+ // leave-behind guts should not extend the lifetime of the notification
+ closeGutsAndEndLifetimeExtension(entryAdapter)
+ } else {
+ notifsWithOpenGuts.add(entryAdapter.key)
+ }
+ }
+
+ override fun onGutsClose(entryAdapter: EntryAdapter) {
+ NotificationBundleUi.isUnexpectedlyInLegacyMode()
+ logger.logGutsClosed(entryAdapter.key)
+ closeGutsAndEndLifetimeExtension(entryAdapter)
+ }
}
- }
private fun isCurrentlyShowingGuts(entry: PipelineEntry) =
- notifsWithOpenGuts.contains(entry.key)
+ notifsWithOpenGuts.contains(entry.key)
private fun closeGutsAndEndLifetimeExtension(entry: NotificationEntry) {
notifsWithOpenGuts.remove(entry.key)
@@ -122,4 +148,11 @@ class GutsCoordinator @Inject constructor(
onEndLifetimeExtensionCallback?.onEndLifetimeExtension(mLifetimeExtender, entry)
}
}
+
+ private fun closeGutsAndEndLifetimeExtension(entryAdapter: EntryAdapter) {
+ notifsWithOpenGuts.remove(entryAdapter.key)
+ if (notifsExtendingLifetime.remove(entryAdapter.key)) {
+ entryAdapter.endLifetimeExtension(onEndLifetimeExtensionCallback, mLifetimeExtender)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
index a987c544bb50..341cc09aafc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
@@ -20,9 +20,9 @@ import android.content.Context
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.notification.AssistantFeedbackController
-import com.android.systemui.statusbar.notification.collection.PipelineEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.PipelineEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
import com.android.systemui.statusbar.notification.collection.render.NotifRowController
@@ -79,6 +79,6 @@ internal constructor(
(mAutoExpandFirstNotification && entry == entryToExpand)
)
// Show/hide the feedback icon
- controller.setFeedbackIcon(mAssistantFeedbackController.getFeedbackIcon(entry))
+ controller.setFeedbackIcon(mAssistantFeedbackController.getFeedbackIcon(entry.ranking))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
index 03b4076ba6fb..ca3d2e2a2a35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.Di
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import javax.inject.Inject;
@@ -83,6 +84,7 @@ public class OnUserInteractionCallbackImpl implements OnUserInteractionCallback
@Override
public void onImportanceChanged(NotificationEntry entry) {
+ NotificationBundleUi.assertInLegacyMode();
mVisualStabilityCoordinator.temporarilyAllowSectionChanges(
entry,
UseElapsedRealtimeForCreationTime.getCurrentTime());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
index 129f6b1750e6..9e49083e4d04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
@@ -15,16 +15,21 @@
*/
package com.android.systemui.statusbar.notification.collection.render
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.NotificationGuts
-/**
- * Interface for listening to guts open and close events.
- */
+/** Interface for listening to guts open and close events. */
interface NotifGutsViewListener {
/** A notification's guts are being opened */
fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts)
/** A notification's guts are being closed */
fun onGutsClose(entry: NotificationEntry)
+
+ /** A notification's guts are being opened */
+ fun onGutsOpen(entryAdapter: EntryAdapter, guts: NotificationGuts)
+
+ /** A notification's guts are being closed */
+ fun onGutsClose(entryAdapter: EntryAdapter)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt
index 777392df67cc..fdbd75bd33ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt
@@ -226,7 +226,7 @@ private val PromotedNotificationContentModel.layoutResource: Int?
private class AODPromotedNotificationViewUpdater(root: View) {
private val alertedIcon: ImageView? = root.findViewById(R.id.alerted_icon)
private val alternateExpandTarget: View? = root.findViewById(R.id.alternate_expand_target)
- private val appNameDivider: View? = root.findViewById(R.id.app_name_divider)
+ private val appNameDivider: TextView? = root.findViewById(R.id.app_name_divider)
private val appNameText: TextView? = root.findViewById(R.id.app_name_text)
private val bigPicture: BigPictureNotificationImageView? = root.findViewById(R.id.big_picture)
private val bigText: ImageFloatingTextView? = root.findViewById(R.id.big_text)
@@ -241,9 +241,9 @@ private class AODPromotedNotificationViewUpdater(root: View) {
)
private val expandButton: NotificationExpandButton? = root.findViewById(R.id.expand_button)
private val headerText: TextView? = root.findViewById(R.id.header_text)
- private val headerTextDivider: View? = root.findViewById(R.id.header_text_divider)
+ private val headerTextDivider: TextView? = root.findViewById(R.id.header_text_divider)
private val headerTextSecondary: TextView? = root.findViewById(R.id.header_text_secondary)
- private val headerTextSecondaryDivider: View? =
+ private val headerTextSecondaryDivider: TextView? =
root.findViewById(R.id.header_text_secondary_divider)
private val icon: NotificationRowIconView? = root.findViewById(R.id.icon)
private val leftIcon: ImageView? = root.findViewById(R.id.left_icon)
@@ -256,9 +256,9 @@ private class AODPromotedNotificationViewUpdater(root: View) {
private val rightIcon: ImageView? = root.findViewById(R.id.right_icon)
private val text: ImageFloatingTextView? = root.findViewById(R.id.text)
private val time: DateTimeView? = root.findViewById(R.id.time)
- private val timeDivider: View? = root.findViewById(R.id.time_divider)
+ private val timeDivider: TextView? = root.findViewById(R.id.time_divider)
private val title: TextView? = root.findViewById(R.id.title)
- private val verificationDivider: View? = root.findViewById(R.id.verification_divider)
+ private val verificationDivider: TextView? = root.findViewById(R.id.verification_divider)
private val verificationIcon: ImageView? = root.findViewById(R.id.verification_icon)
private val verificationText: TextView? = root.findViewById(R.id.verification_text)
@@ -283,6 +283,12 @@ private class AODPromotedNotificationViewUpdater(root: View) {
?.mutate()
?.setColorFilter(SecondaryText.colorInt, PorterDuff.Mode.SRC_IN)
+ setTextViewColor(appNameDivider, SecondaryText)
+ setTextViewColor(headerTextDivider, SecondaryText)
+ setTextViewColor(headerTextSecondaryDivider, SecondaryText)
+ setTextViewColor(timeDivider, SecondaryText)
+ setTextViewColor(verificationDivider, SecondaryText)
+
if (Flags.notificationsRedesignTemplates()) {
(mainColumn?.layoutParams as? MarginLayoutParams)?.let { mainColumnMargins ->
mainColumnMargins.topMargin =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
index 40897dae4c44..d80d5e101294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
@@ -45,7 +45,6 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.util.Compile;
public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsContent {
@@ -58,7 +57,6 @@ public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsC
private PackageManager mPm;
private String mAppName;
private String mPkg;
- private NotificationEntry mEntry;
private IStatusBarService mStatusBarService;
private AssistantFeedbackController mFeedbackController;
@@ -73,16 +71,15 @@ public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsC
public void bindGuts(
final PackageManager pm,
final StatusBarNotification sbn,
- final NotificationEntry entry,
+ final NotificationListenerService.Ranking ranking,
final ExpandableNotificationRow row,
final AssistantFeedbackController controller,
final IStatusBarService statusBarService,
final NotificationGutsManager notificationGutsManager) {
mPkg = sbn.getPackageName();
mPm = pm;
- mEntry = entry;
mExpandableNotificationRow = row;
- mRanking = entry.getRanking();
+ mRanking = ranking;
mFeedbackController = controller;
mAppName = mPkg;
mStatusBarService = statusBarService;
@@ -143,7 +140,7 @@ public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsC
@SuppressLint("DefaultLocale")
private String getPrompt() {
StringBuilder sb = new StringBuilder();
- int status = mFeedbackController.getFeedbackStatus(mEntry);
+ int status = mFeedbackController.getFeedbackStatus(mRanking);
if (DEBUG) {
sb.append(String.format(
"[DEBUG]: oldImportance=%d, newImportance=%d, ranking=%f\n\n",
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 57ceafcd15c6..f17ae571d3ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -1392,7 +1392,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
mPromotedNotificationContentExtractor.extractContent(mEntry,
recoveredBuilder, mBindParams.redactionType, imageModelProvider);
mLogger.logAsyncTaskProgress(logKey, "extracted promoted notification content: "
- + promotedContent);
+ + (promotedContent != null ? promotedContent.toRedactedString() : null));
result.mPromotedContent = promotedContent;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 3c7d9ef8e71d..2cf3b14bb8c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -49,6 +49,7 @@ import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.transition.ChangeBounds;
@@ -72,7 +73,9 @@ import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.notification.NmSummarizationUiFlag;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.wmshell.BubblesManager;
@@ -104,6 +107,8 @@ public class NotificationConversationInfo extends LinearLayout implements
private ShortcutInfo mShortcutInfo;
private NotificationEntry mEntry;
private StatusBarNotification mSbn;
+ private EntryAdapter mEntryAdapter;
+ private NotificationListenerService.Ranking mRanking;
@Nullable private Notification.BubbleMetadata mBubbleMetadata;
private Context mUserContext;
private boolean mIsDeviceProvisioned;
@@ -200,9 +205,10 @@ public class NotificationConversationInfo extends LinearLayout implements
INotificationManager iNotificationManager,
OnUserInteractionCallback onUserInteractionCallback,
String pkg,
- NotificationChannel notificationChannel,
NotificationEntry entry,
- Notification.BubbleMetadata bubbleMetadata,
+ EntryAdapter entryAdapter,
+ NotificationListenerService.Ranking ranking,
+ StatusBarNotification sbn,
OnSettingsClickListener onSettingsClick,
NotificationInfo.OnFeedbackClickListener onFeedbackClickListener,
ConversationIconFactory conversationIconFactory,
@@ -218,25 +224,27 @@ public class NotificationConversationInfo extends LinearLayout implements
mOnUserInteractionCallback = onUserInteractionCallback;
mPackageName = pkg;
mEntry = entry;
- mSbn = entry.getSbn();
+ mSbn = sbn;
+ mRanking = ranking;
+ mEntryAdapter = entryAdapter;
mPm = pm;
mUm = um;
mAppName = mPackageName;
mOnSettingsClickListener = onSettingsClick;
- mNotificationChannel = notificationChannel;
+ mNotificationChannel = ranking.getChannel();
mAppUid = mSbn.getUid();
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
mOnConversationSettingsClickListener = onConversationSettingsClickListener;
mIconFactory = conversationIconFactory;
mUserContext = userContext;
- mBubbleMetadata = bubbleMetadata;
+ mBubbleMetadata = sbn.getNotification().getBubbleMetadata();
mBubblesManagerOptional = bubblesManagerOptional;
mShadeController = shadeController;
mMainHandler = mainHandler;
mBgHandler = bgHandler;
mShortcutManager = shortcutManager;
- mShortcutInfo = entry.getRanking().getConversationShortcutInfo();
+ mShortcutInfo = ranking.getConversationShortcutInfo();
mFeedbackClickListener = onFeedbackClickListener;
if (mShortcutInfo == null) {
throw new IllegalArgumentException("Does not have required information");
@@ -308,11 +316,11 @@ public class NotificationConversationInfo extends LinearLayout implements
private void bindFeedback() {
View feedbackButton = findViewById(R.id.feedback);
if (!NmSummarizationUiFlag.isEnabled()
- || TextUtils.isEmpty(mEntry.getRanking().getSummarization())) {
+ || TextUtils.isEmpty(mRanking.getSummarization())) {
feedbackButton.setVisibility(GONE);
} else {
Intent intent = NotificationInfo.getAssistantFeedbackIntent(
- mINotificationManager, mPm, mEntry);
+ mINotificationManager, mPm, mSbn.getKey(), mRanking);
if (intent == null) {
feedbackButton.setVisibility(GONE);
} else {
@@ -551,10 +559,17 @@ public class NotificationConversationInfo extends LinearLayout implements
mBgHandler.post(
new UpdateChannelRunnable(mINotificationManager, mPackageName,
mAppUid, mSelectedAction, mNotificationChannel));
- mEntry.markForUserTriggeredMovement(true);
- mMainHandler.postDelayed(
- () -> mOnUserInteractionCallback.onImportanceChanged(mEntry),
- StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ if (NotificationBundleUi.isEnabled()) {
+ mEntryAdapter.markForUserTriggeredMovement();
+ mMainHandler.postDelayed(
+ () -> mEntryAdapter.onImportanceChanged(),
+ StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ } else {
+ mEntry.markForUserTriggeredMovement(true);
+ mMainHandler.postDelayed(
+ () -> mOnUserInteractionCallback.onImportanceChanged(mEntry),
+ StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ }
}
private boolean willBypassDnd() {
@@ -658,8 +673,13 @@ public class NotificationConversationInfo extends LinearLayout implements
BUBBLE_PREFERENCE_SELECTED);
}
if (mBubblesManagerOptional.isPresent()) {
- post(() -> mBubblesManagerOptional.get()
- .onUserSetImportantConversation(mEntry));
+ if (NotificationBundleUi.isEnabled()) {
+ post(() -> mBubblesManagerOptional.get()
+ .onUserSetImportantConversation(mEntryAdapter));
+ } else {
+ post(() -> mBubblesManagerOptional.get()
+ .onUserSetImportantConversation(mEntry));
+ }
}
}
mChannelToUpdate.setImportance(Math.max(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index f4e01bf718d9..6c7c7a79348f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -33,6 +33,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.IconDrawableFactory;
@@ -66,7 +67,6 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener;
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
@@ -289,10 +289,21 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
@VisibleForTesting
protected boolean bindGuts(final ExpandableNotificationRow row,
NotificationMenuRowPlugin.MenuItem item) {
- NotificationEntry entry = row.getEntry();
+
+ StatusBarNotification sbn = NotificationBundleUi.isEnabled()
+ ? row.getEntryAdapter().getSbn()
+ : row.getEntryLegacy().getSbn();
+ NotificationListenerService.Ranking ranking = NotificationBundleUi.isEnabled()
+ ? row.getEntryAdapter().getRanking()
+ : row.getEntryLegacy().getRanking();
+
+ if (sbn == null || ranking == null) {
+ // only valid for notification rows
+ return false;
+ }
row.setGutsView(item);
- row.setTag(entry.getSbn().getPackageName());
+ row.setTag(sbn.getPackageName());
row.getGuts().setClosedListener((NotificationGuts g) -> {
row.onGutsClosed();
if (!g.willBeRemoved() && !row.isRemoved()) {
@@ -304,28 +315,37 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
mGutsMenuItem = null;
}
if (mGutsListener != null) {
- mGutsListener.onGutsClose(entry);
+ if (NotificationBundleUi.isEnabled()) {
+ mGutsListener.onGutsClose(row.getEntryAdapter());
+ row.updateBubbleButton();
+ } else {
+ mGutsListener.onGutsClose(row.getEntryLegacy());
+ }
+ }
+ if(NotificationBundleUi.isEnabled()) {
+ row.getEntryAdapter().setInlineControlsShown(false);
+ } else {
+ mHeadsUpManager.setGutsShown(row.getEntryLegacy(), false);
}
- mHeadsUpManager.setGutsShown(row.getEntry(), false);
});
View gutsView = item.getGutsView();
try {
if (gutsView instanceof NotificationSnooze) {
- initializeSnoozeView(row, (NotificationSnooze) gutsView);
+ initializeSnoozeView(row, sbn, ranking, (NotificationSnooze) gutsView);
} else if (gutsView instanceof NotificationInfo) {
- initializeNotificationInfo(row, (NotificationInfo) gutsView);
+ initializeNotificationInfo(row, sbn, ranking, (NotificationInfo) gutsView);
} else if (gutsView instanceof NotificationConversationInfo) {
initializeConversationNotificationInfo(
- row, (NotificationConversationInfo) gutsView);
+ row, sbn, ranking, (NotificationConversationInfo) gutsView);
} else if (gutsView instanceof PartialConversationInfo) {
- initializePartialConversationNotificationInfo(row,
+ initializePartialConversationNotificationInfo(row, sbn, ranking,
(PartialConversationInfo) gutsView);
} else if (gutsView instanceof FeedbackInfo) {
- initializeFeedbackInfo(row, (FeedbackInfo) gutsView);
+ initializeFeedbackInfo(row, sbn, ranking, (FeedbackInfo) gutsView);
} else if (gutsView instanceof PromotedPermissionGutsContent) {
- initializeDemoteView(row, (PromotedPermissionGutsContent) gutsView);
+ initializeDemoteView(row, sbn, (PromotedPermissionGutsContent) gutsView);
}
return true;
} catch (Exception e) {
@@ -342,13 +362,14 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
*/
private void initializeSnoozeView(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
NotificationSnooze notificationSnoozeView) {
NotificationGuts guts = row.getGuts();
- StatusBarNotification sbn = row.getEntry().getSbn();
notificationSnoozeView.setSnoozeListener(mListContainer.getSwipeActionHelper());
notificationSnoozeView.setStatusBarNotification(sbn);
- notificationSnoozeView.setSnoozeOptions(row.getEntry().getSnoozeCriteria());
+ notificationSnoozeView.setSnoozeOptions(ranking.getSnoozeCriteria());
guts.setHeightChangedListener((NotificationGuts g) -> {
mListContainer.onHeightChanged(row, row.isShown() /* needsAnimation */);
});
@@ -362,8 +383,8 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
*/
private void initializeDemoteView(
final ExpandableNotificationRow row,
+ StatusBarNotification sbn,
PromotedPermissionGutsContent demoteGuts) {
- StatusBarNotification sbn = row.getEntry().getSbn();
demoteGuts.setStatusBarNotification(sbn);
demoteGuts.setOnDemoteAction(new View.OnClickListener() {
@Override
@@ -387,16 +408,17 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
*/
private void initializeFeedbackInfo(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
FeedbackInfo feedbackInfo) {
- if (mAssistantFeedbackController.getFeedbackIcon(row.getEntry()) == null) {
+ if (mAssistantFeedbackController.getFeedbackIcon(ranking) == null) {
return;
}
- StatusBarNotification sbn = row.getEntry().getSbn();
UserHandle userHandle = sbn.getUser();
PackageManager pmUser = CentralSurfaces.getPackageManagerForUser(mContext,
userHandle.getIdentifier());
- feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController,
+ feedbackInfo.bindGuts(pmUser, sbn, ranking, row, mAssistantFeedbackController,
mStatusBarService, this);
}
@@ -408,9 +430,10 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
@VisibleForTesting
void initializeNotificationInfo(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
NotificationInfo notificationInfoView) throws Exception {
NotificationGuts guts = row.getGuts();
- StatusBarNotification sbn = row.getEntry().getSbn();
String packageName = sbn.getPackageName();
// Settings link is only valid for notifications that specify a non-system user
NotificationInfo.OnSettingsClickListener onSettingsClick = null;
@@ -449,18 +472,22 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
mChannelEditorDialogController,
mPackageDemotionInteractor,
packageName,
- row.getEntry().getChannel(),
- row.getEntry(),
+ ranking,
+ sbn,
+ NotificationBundleUi.isEnabled() ? null : row.getEntryLegacy(),
+ NotificationBundleUi.isEnabled() ? row.getEntryAdapter() : null,
onSettingsClick,
onAppSettingsClick,
onNasFeedbackClick,
mUiEventLogger,
mDeviceProvisionedController.isDeviceProvisioned(),
NotificationBundleUi.isEnabled()
- ? !row.getEntry().isBlockable()
+ ? !row.getEntryAdapter().isBlockable()
: row.getIsNonblockable(),
row.canViewBeDismissed(),
- mHighPriorityProvider.isHighPriority(row.getEntry()),
+ NotificationBundleUi.isEnabled()
+ ? row.getEntryAdapter().isHighPriority()
+ : mHighPriorityProvider.isHighPriority(row.getEntryLegacy()),
mAssistantFeedbackController,
mMetricsLogger,
row.getCloseButtonOnClickListener(row));
@@ -474,9 +501,10 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
@VisibleForTesting
void initializePartialConversationNotificationInfo(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
PartialConversationInfo notificationInfoView) throws Exception {
NotificationGuts guts = row.getGuts();
- StatusBarNotification sbn = row.getEntry().getSbn();
String packageName = sbn.getPackageName();
// Settings link is only valid for notifications that specify a non-system user
NotificationInfo.OnSettingsClickListener onSettingsClick = null;
@@ -499,12 +527,12 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
mNotificationManager,
mChannelEditorDialogController,
packageName,
- row.getEntry().getChannel(),
- row.getEntry(),
+ ranking,
+ sbn,
onSettingsClick,
mDeviceProvisionedController.isDeviceProvisioned(),
NotificationBundleUi.isEnabled()
- ? !row.getEntry().isBlockable()
+ ? !row.getEntryAdapter().isBlockable()
: row.getIsNonblockable());
}
@@ -516,10 +544,10 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
@VisibleForTesting
void initializeConversationNotificationInfo(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
NotificationConversationInfo notificationInfoView) throws Exception {
NotificationGuts guts = row.getGuts();
- NotificationEntry entry = row.getEntry();
- StatusBarNotification sbn = entry.getSbn();
String packageName = sbn.getPackageName();
// Settings link is only valid for notifications that specify a non-system user
NotificationConversationInfo.OnSettingsClickListener onSettingsClick = null;
@@ -567,9 +595,10 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
mNotificationManager,
mOnUserInteractionCallback,
packageName,
- entry.getChannel(),
- entry,
- entry.getBubbleMetadata(),
+ NotificationBundleUi.isEnabled() ? null : row.getEntryLegacy(),
+ NotificationBundleUi.isEnabled() ? row.getEntryAdapter() : null,
+ ranking,
+ sbn,
onSettingsClick,
onNasFeedbackClick,
iconFactoryLoader,
@@ -746,13 +775,21 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
row::onGutsOpened);
if (mGutsListener != null) {
- mGutsListener.onGutsOpen(row.getEntry(), guts);
+ if(NotificationBundleUi.isEnabled()) {
+ mGutsListener.onGutsOpen(row.getEntryAdapter(), guts);
+ } else {
+ mGutsListener.onGutsOpen(row.getEntryLegacy(), guts);
+ }
}
row.closeRemoteInput();
mListContainer.onHeightChanged(row, true /* needsAnimation */);
mGutsMenuItem = menuItem;
- mHeadsUpManager.setGutsShown(row.getEntry(), true);
+ if(NotificationBundleUi.isEnabled()) {
+ row.getEntryAdapter().setInlineControlsShown(true);
+ } else {
+ mHeadsUpManager.setGutsShown(row.getEntryLegacy(), true);
+ }
}
};
guts.post(mOpenRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index b6f4ffce8e00..571006bc21e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -50,6 +50,7 @@ import android.metrics.LogMaker;
import android.os.Handler;
import android.os.RemoteException;
import android.service.notification.NotificationAssistantService;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.Html;
import android.text.TextUtils;
@@ -73,10 +74,12 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor;
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import java.lang.annotation.Retention;
import java.util.List;
@@ -124,6 +127,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private boolean mIsDismissable;
private NotificationEntry mEntry;
private StatusBarNotification mSbn;
+ private NotificationListenerService.Ranking mRanking;
+ private EntryAdapter mEntryAdapter;
private boolean mIsDeviceProvisioned;
private boolean mIsSystemRegisteredCall;
@@ -198,8 +203,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
ChannelEditorDialogController channelEditorDialogController,
PackageDemotionInteractor packageDemotionInteractor,
String pkg,
- NotificationChannel notificationChannel,
+ NotificationListenerService.Ranking ranking,
+ StatusBarNotification sbn,
NotificationEntry entry,
+ EntryAdapter entryAdapter,
OnSettingsClickListener onSettingsClick,
OnAppSettingsClickListener onAppSettingsClick,
OnFeedbackClickListener onFeedbackClickListener,
@@ -220,14 +227,16 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mChannelEditorDialogController = channelEditorDialogController;
mAssistantFeedbackController = assistantFeedbackController;
mPackageName = pkg;
+ mSbn = sbn;
+ mRanking = ranking;
mEntry = entry;
- mSbn = entry.getSbn();
+ mEntryAdapter = entryAdapter;
mPm = pm;
mAppSettingsClickListener = onAppSettingsClick;
mFeedbackClickListener = onFeedbackClickListener;
mAppName = mPackageName;
mOnSettingsClickListener = onSettingsClick;
- mSingleNotificationChannel = notificationChannel;
+ mSingleNotificationChannel = ranking.getChannel();
mStartingChannelImportance = mSingleNotificationChannel.getImportance();
mWasShownHighPriority = wasShownHighPriority;
mIsNonblockable = isNonblockable;
@@ -301,7 +310,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
View automatic = findViewById(R.id.automatic);
if (mShowAutomaticSetting) {
mAutomaticDescriptionView.setText(Html.fromHtml(mContext.getText(
- mAssistantFeedbackController.getInlineDescriptionResource(mEntry)).toString()));
+ mAssistantFeedbackController.getInlineDescriptionResource(mRanking))
+ .toString()));
automatic.setVisibility(VISIBLE);
automatic.setOnClickListener(mOnAutomatic);
} else {
@@ -381,7 +391,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private void bindFeedback() {
View feedbackButton = findViewById(R.id.feedback);
- Intent intent = getAssistantFeedbackIntent(mINotificationManager, mPm, mEntry);
+ Intent intent = getAssistantFeedbackIntent(
+ mINotificationManager, mPm, mSbn.getKey(), mRanking);
if (!android.app.Flags.notificationClassificationUi() || intent == null) {
feedbackButton.setVisibility(GONE);
} else {
@@ -395,7 +406,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
public static Intent getAssistantFeedbackIntent(INotificationManager inm, PackageManager pm,
- NotificationEntry entry) {
+ String key, NotificationListenerService.Ranking ranking) {
try {
ComponentName assistant = inm.getAllowedNotificationAssistant();
if (assistant == null) {
@@ -414,9 +425,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
final ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
intent.setClassName(activityInfo.packageName, activityInfo.name);
- intent.putExtra(NotificationAssistantService.EXTRA_NOTIFICATION_KEY, entry.getKey());
+ intent.putExtra(NotificationAssistantService.EXTRA_NOTIFICATION_KEY, key);
intent.putExtra(NotificationAssistantService.EXTRA_NOTIFICATION_ADJUSTMENT,
- entry.getRanking().getSummarization() != null ? KEY_SUMMARIZATION : KEY_TYPE);
+ ranking.getSummarization() != null ? KEY_SUMMARIZATION : KEY_TYPE);
return intent;
} catch (Exception e) {
Slog.d(TAG, "no assistant?", e);
@@ -526,7 +537,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
mSingleNotificationChannel,
mStartingChannelImportance, newImportance, mIsAutomaticChosen));
- mOnUserInteractionCallback.onImportanceChanged(mEntry);
+ if (NotificationBundleUi.isEnabled()) {
+ mEntryAdapter.onImportanceChanged();
+ } else {
+ mOnUserInteractionCallback.onImportanceChanged(mEntry);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index 4f1b90544403..efc90c91092a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -710,7 +710,7 @@ constructor(
.also {
logger.logAsyncTaskProgress(
entry.logKey,
- "extracted promoted notification content: $it",
+ "extracted promoted notification content: ${it?.toRedactedString()}",
)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index 60e98a5c317a..3b795796020c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -24,6 +24,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -35,6 +36,7 @@ import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
@@ -79,18 +81,18 @@ public class PartialConversationInfo extends LinearLayout implements
INotificationManager iNotificationManager,
ChannelEditorDialogController channelEditorDialogController,
String pkg,
- NotificationChannel notificationChannel,
- NotificationEntry entry,
+ NotificationListenerService.Ranking ranking,
+ StatusBarNotification sbn,
NotificationInfo.OnSettingsClickListener onSettingsClick,
boolean isDeviceProvisioned,
boolean isNonBlockable) {
mINotificationManager = iNotificationManager;
mPackageName = pkg;
- mSbn = entry.getSbn();
+ mSbn = sbn;
mPm = pm;
mAppName = mPackageName;
mOnSettingsClickListener = onSettingsClick;
- mNotificationChannel = notificationChannel;
+ mNotificationChannel = ranking.getChannel();
mAppUid = mSbn.getUid();
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java
index 769f0b5a4fa4..2cb208932943 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java
@@ -21,6 +21,7 @@ import android.app.NotificationChannel;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.RemoteException;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.Log;
@@ -30,6 +31,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor;
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
@@ -60,8 +62,10 @@ public class PromotedNotificationInfo extends NotificationInfo {
ChannelEditorDialogController channelEditorDialogController,
PackageDemotionInteractor packageDemotionInteractor,
String pkg,
- NotificationChannel notificationChannel,
+ NotificationListenerService.Ranking ranking,
+ StatusBarNotification sbn,
NotificationEntry entry,
+ EntryAdapter entryAdapter,
OnSettingsClickListener onSettingsClick,
OnAppSettingsClickListener onAppSettingsClick,
OnFeedbackClickListener feedbackClickListener,
@@ -73,17 +77,17 @@ public class PromotedNotificationInfo extends NotificationInfo {
AssistantFeedbackController assistantFeedbackController,
MetricsLogger metricsLogger, OnClickListener onCloseClick) throws RemoteException {
super.bindNotification(pm, iNotificationManager, appIconProvider, iconStyleProvider,
- onUserInteractionCallback, channelEditorDialogController, packageDemotionInteractor,
- pkg, notificationChannel,
- entry, onSettingsClick, onAppSettingsClick, feedbackClickListener, uiEventLogger,
- isDeviceProvisioned, isNonblockable, isDismissable, wasShownHighPriority,
- assistantFeedbackController, metricsLogger, onCloseClick);
+ onUserInteractionCallback, channelEditorDialogController,
+ packageDemotionInteractor,pkg, ranking, sbn,
+ entry, entryAdapter, onSettingsClick, onAppSettingsClick, feedbackClickListener,
+ uiEventLogger, isDeviceProvisioned, isDismissable, isNonblockable,
+ wasShownHighPriority, assistantFeedbackController, metricsLogger, onCloseClick);
mNotificationManager = iNotificationManager;
mPackageDemotionInteractor = packageDemotionInteractor;
- bindDemote(entry.getSbn(), pkg);
+ bindDemote(sbn, pkg);
}
protected void bindDemote(StatusBarNotification sbn, String packageName) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 503256accff0..afa988dd8e89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -6076,7 +6076,9 @@ public class NotificationStackScrollLayout
if (mBlurRadius > 0) {
mBlurEffect =
RenderEffect.createBlurEffect(mBlurRadius, mBlurRadius, Shader.TileMode.CLAMP);
+ spewLog("Setting up blur RenderEffect for NotificationStackScrollLayout");
} else {
+ spewLog("Clearing the blur RenderEffect setup for NotificationStackScrollLayout");
mBlurEffect = null;
}
}
@@ -6252,6 +6254,7 @@ public class NotificationStackScrollLayout
@Override
protected void dispatchDraw(@NonNull Canvas canvas) {
if (mBlurEffect != null) {
+ spewLog("Applying blur RenderEffect to NotificationStackScrollLayout");
// reuse the cached RenderNode to blur
mBlurNode.setPosition(0, 0, canvas.getWidth(), canvas.getHeight());
mBlurNode.setRenderEffect(mBlurEffect);
@@ -7025,4 +7028,10 @@ public class NotificationStackScrollLayout
SceneContainerFlag.assertInLegacyMode();
mMaxTopPadding = maxTopPadding;
}
+
+ private void spewLog(String logMsg) {
+ if (SPEW) {
+ Log.v(TAG, logMsg);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 612c19fc6696..66c9b17ef235 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -420,10 +420,15 @@ public class NotificationStackScrollLayoutController implements Dumpable {
return;
}
if (view instanceof ExpandableNotificationRow row) {
- mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
- .setType(MetricsEvent.TYPE_ACTION)
- );
+ StatusBarNotification sbn = NotificationBundleUi.isEnabled()
+ ? row.getEntryAdapter().getSbn()
+ : row.getEntryLegacy().getSbn();
+ if (sbn != null) {
+ mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION)
+ );
+ }
}
mNotificationGutsManager.openGuts(view, x, y, item);
}
@@ -440,9 +445,14 @@ public class NotificationStackScrollLayoutController implements Dumpable {
@Override
public void onMenuShown(View row) {
if (row instanceof ExpandableNotificationRow notificationRow) {
- mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
- .setType(MetricsEvent.TYPE_ACTION));
+ StatusBarNotification sbn = NotificationBundleUi.isEnabled()
+ ? notificationRow.getEntryAdapter().getSbn()
+ : notificationRow.getEntryLegacy().getSbn();
+ if (sbn != null) {
+ mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION));
+ }
mSwipeHelper.onMenuShown(row);
mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
@@ -1355,11 +1365,15 @@ public class NotificationStackScrollLayoutController implements Dumpable {
*/
public void setBlurRadius(float blurRadius) {
if (blurRadius > 0.0f) {
+ debugLog(
+ "Setting blur RenderEffect for NotificationStackScrollLayoutController with "
+ + "radius " + blurRadius);
mView.setRenderEffect(RenderEffect.createBlurEffect(
blurRadius,
blurRadius,
Shader.TileMode.CLAMP));
} else {
+ debugLog("Resetting blur RenderEffect for NotificationStackScrollLayoutController");
mView.setRenderEffect(null);
}
}
@@ -2175,4 +2189,10 @@ public class NotificationStackScrollLayoutController implements Dumpable {
&& !mSwipeHelper.isSwiping();
}
}
+
+ private void debugLog(String msg) {
+ if (DEBUG) {
+ Log.d(TAG, msg);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 8a447f7395d4..60f1777e80bc 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -64,6 +64,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -618,6 +619,28 @@ public class BubblesManager {
}
/**
+ * When a notification is set as important, make it a bubble
+ *
+ * @param entryAdapter the important notification.
+ */
+ public void onUserSetImportantConversation(EntryAdapter entryAdapter) {
+ if (entryAdapter.getSbn() != null
+ && entryAdapter.getSbn().getNotification().getBubbleMetadata() == null) {
+ // No bubble metadata, nothing to do.
+ return;
+ }
+ try {
+ int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ mBarService.onNotificationBubbleChanged(entryAdapter.getKey(), true, flags);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage());
+ }
+ mShadeController.collapseShade(true);
+ // NotificationGutsManager will refresh the ENR when the guts close and update the
+ // bubble button if needed
+ }
+
+ /**
* Called when a user has indicated that an active notification should be shown as a bubble.
* <p>
* This method will collapse the shade, create the bubble without a flyout or dot, and suppress
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
index 798aa428e73e..eb72acc0dade 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
@@ -109,6 +109,7 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@@ -151,8 +152,10 @@ public class MediaSwitchingControllerTest extends SysuiTestCase {
private MediaDevice mMediaDevice1;
@Mock
private MediaDevice mMediaDevice2;
- @Mock
- private NearbyDevice mNearbyDevice1;
+ @Mock private MediaDevice mMediaDevice3;
+ @Mock private MediaDevice mMediaDevice4;
+ @Mock private MediaDevice mMediaDevice5;
+ @Mock private NearbyDevice mNearbyDevice1;
@Mock
private NearbyDevice mNearbyDevice2;
@Mock
@@ -1550,6 +1553,89 @@ public class MediaSwitchingControllerTest extends SysuiTestCase {
assertThat(items.get(1).getMediaDevice().get()).isEqualTo(mMediaDevice2);
}
+ @EnableFlags(Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING)
+ @Test
+ public void selectedDevicesAddedInSameOrderWhenRlpDoesNotExist() {
+ setUpSelectedDevicesAndOrdering();
+
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
+
+ List<MediaDevice> devices =
+ mMediaSwitchingController.getMediaItemList().stream()
+ .filter(item -> item.getMediaDevice().isPresent())
+ .map(item -> item.getMediaDevice().orElse(null))
+ .collect(Collectors.toList());
+ assertThat(devices)
+ .containsExactly(
+ mMediaDevice4,
+ mMediaDevice3,
+ mMediaDevice5,
+ mMediaDevice1,
+ mMediaDevice2)
+ .inOrder();
+ }
+
+ @DisableFlags(Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING)
+ @Test
+ public void selectedDevicesAddedInSortedOrderWhenRlpDoesNotExist() {
+ setUpSelectedDevicesAndOrdering();
+
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
+
+ List<MediaDevice> devices =
+ mMediaSwitchingController.getMediaItemList().stream()
+ .filter(item -> item.getMediaDevice().isPresent())
+ .map(item -> item.getMediaDevice().orElse(null))
+ .collect(Collectors.toList());
+
+ assertThat(devices)
+ .containsExactly(
+ mMediaDevice5,
+ mMediaDevice4,
+ mMediaDevice3,
+ mMediaDevice1,
+ mMediaDevice2)
+ .inOrder();
+ }
+
+ private void setUpSelectedDevicesAndOrdering() {
+ when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID);
+ when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
+ when(mMediaDevice3.getId()).thenReturn(TEST_DEVICE_3_ID);
+ when(mMediaDevice4.getId()).thenReturn(TEST_DEVICE_4_ID);
+ when(mMediaDevice5.getId()).thenReturn(TEST_DEVICE_5_ID);
+ mMediaDevices.clear();
+ Collections.addAll(
+ mMediaDevices,
+ mMediaDevice2,
+ mMediaDevice1,
+ mMediaDevice4,
+ mMediaDevice3,
+ mMediaDevice5);
+ List<MediaDevice> selectedMediaDevices = new ArrayList<>();
+ Collections.addAll(selectedMediaDevices, mMediaDevice3, mMediaDevice4, mMediaDevice5);
+ doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice();
+ // Sort the media devices in the order they appear in the deviceOrder list
+ List<MediaDevice> deviceOrder = new ArrayList<>();
+ Collections.addAll(
+ deviceOrder,
+ mMediaDevice1,
+ mMediaDevice2,
+ mMediaDevice3,
+ mMediaDevice4,
+ mMediaDevice5);
+ for (int i = 0; i < deviceOrder.size(); i++) {
+ for (int j = i + 1; j < deviceOrder.size(); j++) {
+ when(deviceOrder.get(i).compareTo(deviceOrder.get(j))).thenReturn(-1);
+ when(deviceOrder.get(j).compareTo(deviceOrder.get(i))).thenReturn(1);
+ }
+ }
+ when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(false);
+ mMediaSwitchingController.start(mCb);
+ reset(mCb);
+ mMediaSwitchingController.getMediaItemList().clear();
+ }
+
@DisableFlags(Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING)
@Test
public void selectedDevicesAddedInReverseOrder() {
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 bc7ab9d4fe3c..eae23e70027b 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
@@ -78,6 +78,8 @@ import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryAdapter;
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
@@ -1023,6 +1025,8 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
mock(NotificationIconStyleProvider.class),
mock(VisualStabilityCoordinator.class),
mock(NotificationActionClickManager.class),
+ mock(HighPriorityProvider.class),
+ mock(HeadsUpManager.class),
entry);
row.setEntryAdapter(entryAdapter);
} else {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 3061842c386c..2c800bd87ef5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -89,8 +89,16 @@ import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
+import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
import com.android.systemui.wmshell.BubblesManager;
import com.android.systemui.wmshell.BubblesTestActivity;
@@ -127,6 +135,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
private NotificationChannel mConversationChannel;
private StatusBarNotification mSbn;
private NotificationEntry mEntry;
+ private EntryAdapter mEntryAdapter;
private StatusBarNotification mBubbleSbn;
private NotificationEntry mBubbleEntry;
@Mock
@@ -228,7 +237,21 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, applicationInfo);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
notification, UserHandle.CURRENT, null, 0);
- mEntry = new NotificationEntryBuilder().setSbn(mSbn).setShortcutInfo(mShortcutInfo).build();
+ mEntry = new NotificationEntryBuilder().setSbn(mSbn).setShortcutInfo(mShortcutInfo)
+ .updateRanking(rankingBuilder -> {
+ rankingBuilder.setChannel(mNotificationChannel);
+ })
+ .build();
+ mEntryAdapter = new EntryAdapterFactoryImpl(
+ mock(NotificationActivityStarter.class),
+ mock(MetricsLogger.class),
+ mock(PeopleNotificationIdentifier.class),
+ mock(NotificationIconStyleProvider.class),
+ mock(VisualStabilityCoordinator.class),
+ mock(NotificationActionClickManager.class),
+ mock(HighPriorityProvider.class),
+ mock(HeadsUpManager.class)
+ ).create(mEntry);
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0,
new Intent(mContext, BubblesTestActivity.class),
@@ -264,9 +287,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- mBubbleMetadata,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
null,
mIconFactory,
@@ -367,9 +391,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- entry,
- mBubbleMetadata,
+ mEntry,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
null,
mIconFactory,
@@ -404,9 +429,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- mBubbleMetadata,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
(View v, Intent intent) -> {
latch.countDown();
@@ -444,9 +470,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- mBubbleMetadata,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mConversationChannel, c);
latch.countDown();
@@ -483,9 +510,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- mBubbleMetadata,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
@@ -553,6 +581,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mConversationChannel.setImportance(IMPORTANCE_HIGH);
mConversationChannel.setImportantConversation(false);
mConversationChannel.setAllowBubbles(false);
+ mSbn.getNotification().setBubbleMetadata(null);
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
@@ -561,9 +590,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- null,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
null,
mIconFactory,
@@ -583,6 +613,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mConversationChannel.setImportance(IMPORTANCE_HIGH);
mConversationChannel.setImportantConversation(false);
mConversationChannel.setAllowBubbles(false);
+ mSbn.getNotification().setBubbleMetadata(null);
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
@@ -591,9 +622,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- null,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
null,
mIconFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
index 10de86644015..49ebc8c83ea7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
@@ -63,13 +63,16 @@ import com.android.systemui.statusbar.NotificationEntryHelper
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.AssistantFeedbackController
import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.notification.collection.provider.mockHighPriorityProvider
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor
import com.android.systemui.statusbar.notification.row.icon.appIconProvider
import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.notificationLockscreenUserManager
import com.android.systemui.statusbar.policy.deviceProvisionedController
@@ -233,14 +236,22 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
assertEquals(View.INVISIBLE.toLong(), guts.visibility.toLong())
executor.runAllReady()
verify(guts).openControls(any<Int>(), any<Int>(), any<Boolean>(), any<Runnable>())
- verify(headsUpManager).setGutsShown(realRow!!.entry, true)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(true))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow!!.entry, true)
+ }
assertEquals(View.VISIBLE.toLong(), guts.visibility.toLong())
gutsManager.closeAndSaveGuts(false, false, true, 0, 0, false)
verify(guts)
.closeControls(any<Boolean>(), any<Boolean>(), any<Int>(), any<Int>(), any<Boolean>())
verify(row, times(1)).setGutsView(any())
executor.runAllReady()
- verify(headsUpManager).setGutsShown(realRow.entry, false)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(false))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow!!.entry, false)
+ }
}
@Test
@@ -385,16 +396,23 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
@Throws(Exception::class)
fun testInitializeNotificationInfoView_highPriority() {
val notificationInfoView = mock<NotificationInfo>()
- val row = spy(helper.createRow())
- val entry = row.entry
+ val row = createTestNotificationRow()
+ val entry = row!!.entry
NotificationEntryHelper.modifyRanking(entry)
.setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE)
.setImportance(NotificationManager.IMPORTANCE_HIGH)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
+
whenever(highPriorityProvider.isHighPriority(entry)).thenReturn(true)
+ whenever(kosmos.mockHighPriorityProvider.isHighPriority(entry)).thenReturn(true)
val statusBarNotification = entry.sbn
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
any<PackageManager>(),
@@ -405,15 +423,17 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
eq(channelEditorDialogController),
eq(packageDemotionInteractor),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
eq(true),
eq(false),
- eq(true),
+ eq(false),
eq(true),
eq(assistantFeedbackController),
any<MetricsLogger>(),
@@ -425,14 +445,19 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
@Throws(Exception::class)
fun testInitializeNotificationInfoView_PassesAlongProvisionedState() {
val notificationInfoView = mock<NotificationInfo>()
- val row = spy(helper.createRow())
+ val row = createTestNotificationRow()
NotificationEntryHelper.modifyRanking(row.entry)
.setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
val statusBarNotification = row.entry.sbn
val entry = row.entry
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
any<PackageManager>(),
@@ -443,15 +468,17 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
eq(channelEditorDialogController),
eq(packageDemotionInteractor),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
eq(true),
eq(false),
- eq(true), /* wasShownHighPriority */
+ eq(false), /* wasShownHighPriority */
eq(false),
eq(assistantFeedbackController),
any<MetricsLogger>(),
@@ -470,7 +497,15 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
whenever(row.canViewBeDismissed()).thenReturn(true)
val statusBarNotification = row.entry.sbn
val entry = row.entry
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+ val entryAdapter = kosmos.entryAdapterFactory.create(entry)
+ row.entryAdapter = entryAdapter
+
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
any<PackageManager>(),
@@ -481,8 +516,10 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
eq(channelEditorDialogController),
eq(packageDemotionInteractor),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
@@ -497,7 +534,7 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
)
}
- private fun createTestNotificationRow(): ExpandableNotificationRow? {
+ private fun createTestNotificationRow(): ExpandableNotificationRow {
val nb =
Notification.Builder(mContext, testNotificationChannel.id)
.setContentTitle("foo")
@@ -505,16 +542,10 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
.setColor(Color.RED)
.setFlag(Notification.FLAG_CAN_COLORIZE, true)
.setSmallIcon(R.drawable.sym_def_app_icon)
- return try {
- val row = helper.createRow(nb.build())
- NotificationEntryHelper.modifyRanking(row.entry)
- .setChannel(testNotificationChannel)
- .build()
- row
- } catch (_: Exception) {
- Assert.fail()
- null
- }
+ val row = helper.createRow(nb.build())
+ NotificationEntryHelper.modifyRanking(row.entry).setChannel(testNotificationChannel).build()
+ row.entryAdapter = kosmos.entryAdapterFactory.create(row.entry)
+ return row
}
private fun setIsLockscreenOrShadeVisible(isVisible: Boolean) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCaseExt.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCaseExt.kt
index c86ba6ccf47f..ebf89e9e3889 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCaseExt.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCaseExt.kt
@@ -19,14 +19,40 @@ package com.android.systemui
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.useStandardTestDispatcher
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
-fun SysuiTestCase.testKosmos(): Kosmos = Kosmos().apply { testCase = this@testKosmos }
+/**
+ * This definition, which uses standard dispatcher, is eventually going away.
+ *
+ * If you are calling this method, and want the new default behavior, call `testKosmosNew`, and you
+ * will be migrated to the new behavior (unconfined dispatcher). If you want to maintain the old
+ * behavior, directly call testKosmosNew().useStandardTestDispatcher().
+ *
+ * The migration will proceed in multiple steps:
+ * 1. All calls to testKosmos will be converted to testKosmosLegacy, maybe over several CLs.
+ * 2. When there are zero references to testKosmos, it will be briefly deleted
+ * 3. A new testKosmos will be introduced that uses unconfined test dispatcher
+ * 4. All callers to testKosmosNew that have been introduced since step 1 will be migrated to this
+ * new definition of testKosmos
+ * 5. testKosmosNew will be deleted
+ * 6. Over time, test authors will be encouraged to migrate away from testKosmosLegacy
+ *
+ * For details, see go/thetiger
+ */
+// TODO(b/342622417)
+fun SysuiTestCase.testKosmos(): Kosmos = testKosmosLegacy()
+
+/**
+ * Create a new Kosmos instance using the unconfined test dispatcher. See migration notes on
+ * [testKosmos]
+ */
+fun SysuiTestCase.testKosmosNew(): Kosmos =
+ Kosmos().apply { testCase = this@testKosmosNew }.useUnconfinedTestDispatcher()
/**
* This should not be called directly. Instead, you can use:
- * - testKosmos() to use the default dispatcher (which will soon be unconfined, see go/thetiger)
- * - testKosmos().useStandardTestDispatcher() to explicitly choose the standard dispatcher
- * - testKosmos().useUnconfinedTestDispatcher() to explicitly choose the unconfined dispatcher
+ * - testKosmosNew().useStandardTestDispatcher() to explicitly choose the standard dispatcher
+ * - testKosmosNew() to explicitly choose the unconfined dispatcher (which is the new sysui default)
*
* For details, see go/thetiger
*/
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorKosmos.kt
index 1a5c61a04c9f..aba4942b44e4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorKosmos.kt
@@ -32,6 +32,7 @@ import com.android.systemui.statusbar.notification.stack.data.repository.headsUp
import com.android.systemui.statusbar.notification.visibilityLocationProvider
import com.android.systemui.statusbar.policy.keyguardStateController
import com.android.systemui.util.kotlin.JavaAdapter
+import org.mockito.kotlin.mock
var Kosmos.visualStabilityCoordinator: VisualStabilityCoordinator by
Kosmos.Fixture {
@@ -54,3 +55,5 @@ var Kosmos.visualStabilityCoordinator: VisualStabilityCoordinator by
visualStabilityCoordinatorLogger,
)
}
+
+var Kosmos.mockVisualStabilityCoordinator: VisualStabilityCoordinator by Kosmos.Fixture { mock() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProviderKosmos.kt
new file mode 100644
index 000000000000..aa30828d4375
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProviderKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.provider
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.mockHighPriorityProvider: HighPriorityProvider by Kosmos.Fixture { mock() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
index 067e420b89c3..4b699702d54f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
@@ -19,7 +19,9 @@ package com.android.systemui.statusbar.notification.row
import com.android.internal.logging.metricsLogger
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
-import com.android.systemui.statusbar.notification.collection.coordinator.visualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.coordinator.mockVisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.provider.mockHighPriorityProvider
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
import com.android.systemui.statusbar.notification.mockNotificationActivityStarter
import com.android.systemui.statusbar.notification.people.peopleNotificationIdentifier
import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
@@ -31,7 +33,9 @@ val Kosmos.entryAdapterFactory by
metricsLogger,
peopleNotificationIdentifier,
notificationIconStyleProvider,
- visualStabilityCoordinator,
+ mockVisualStabilityCoordinator,
mockNotificationActionClickManager,
+ mockHighPriorityProvider,
+ mockHeadsUpManager,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index 6a674ca29ca4..b6acf477b660 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -60,6 +60,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl
@@ -376,6 +377,8 @@ class ExpandableNotificationRowBuilder(
Mockito.mock(NotificationIconStyleProvider::class.java),
Mockito.mock(VisualStabilityCoordinator::class.java),
Mockito.mock(NotificationActionClickManager::class.java),
+ Mockito.mock(HighPriorityProvider::class.java),
+ Mockito.mock(HeadsUpManager::class.java),
)
.create(entry)
diff --git a/ravenwood/tools/hoststubgen/README.md b/ravenwood/tools/hoststubgen/README.md
index 615e7671bea1..9f72611953c2 100644
--- a/ravenwood/tools/hoststubgen/README.md
+++ b/ravenwood/tools/hoststubgen/README.md
@@ -17,62 +17,3 @@ AndroidHeuristicsFilter has hardcoded heuristics to detect AIDL generated classe
- More Android specific build files and code are stored in `frameworks/base/Ravenwood.bp`
`frameworks/base/ravenwood`.
-
-## Directories and files
-
-- `src/`
-
- HostStubGen tool source code.
-
-- `annotations-src/` See `Android.bp`.
-- `helper-framework-buildtime-src/` See `Android.bp`.
-- `helper-framework-runtime-src/` See `Android.bp`.
-- `helper-runtime-src/` See `Android.bp`.
-
-- `test-tiny-framework/` See `README.md` in it.
-
-- `scripts`
- - `dump-jar.sh`
-
- A script to dump the content of `*.class` and `*.jar` files.
-
- - `run-all-tests.sh`
-
- Run all tests. Many tests may fail, but at least this should run til the end.
- (It should print `run-all-tests.sh finished` at the end)
-
-## Build and run
-
-### Building `HostStubGen` binary
-
-```
-m hoststubgen
-```
-
-### Run the tests
-
-- Run all relevant tests and test scripts. All of it is expected to pass, and it'll print
- "Ready to submit" at the end.
-
- However, because some of the script it executes depend on internal file paths to Soong's
- intermediate directory, some of it might fail when something changes in the build system.
-
- We need proper build system integration to fix them.
-```
-$ ./scripts/run-all-tests.sh
-```
-
-- See also `README.md` in `test-*` directories.
-
-## TODOs, etc
-
- - Make sure the parent's visibility is not smaller than the member's.
-
-- @HostSideTestNativeSubstitutionClass should automatically add class-keep to the substitute class.
- (or at least check it.)
-
- - The `HostStubGenTest-framework-test-host-test-lib` jar somehow contain all ASM classes? Figure out where the dependency is coming from.
-
-- At some point, we can move or delete all Android specific code to `frameworks/base/ravenwood`.
- - `helper-framework-*-src` should be moved to `frameworks/base/ravenwood`
- - `test-framework` should be deleted.
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
index f8bb526d0a86..760999f5e129 100644
--- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
@@ -60,7 +60,7 @@ class ClassWidePolicyPropagatingFilter(
}
return p.withReason(policy.reason)
- .wrapReason("class-wide in $className")
+ .wrapReason("class-wide in $className", policy.statsLabelOverride)
}
// If the class's policy is remove, then remove it.
if (policy.policy == FilterPolicy.Remove) {
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
index 7358a0bfb3e6..e082bbb0a119 100644
--- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
@@ -41,7 +41,7 @@ enum class StatsLabel(val statValue: Int, val label: String) {
data class FilterPolicyWithReason (
val policy: FilterPolicy,
val reason: String = "",
- private val statsLabelOverride: StatsLabel? = null
+ val statsLabelOverride: StatsLabel? = null
) {
/**
* Return a new [FilterPolicy] with an updated reason, while keeping the original reason
@@ -51,7 +51,7 @@ data class FilterPolicyWithReason (
return FilterPolicyWithReason(
policy,
"$reason [inner-reason: ${this.reason}]",
- statsLabelOverride = statsLabelOverride,
+ statsLabelOverride = statsLabelOverride ?: this.statsLabelOverride,
)
}
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index 97fc35302528..cdcea4c15820 100644
--- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -528,7 +528,8 @@ class TextFileFilterPolicyParser {
)
}
val p = policy.withReason(
- "$FILTER_REASON (special-class AIDL)"
+ "$FILTER_REASON (special-class AIDL)",
+ StatsLabel.SupportedButBoring,
)
processor.onSpecialClassPolicy(classType, p)
aidlPolicy = p
@@ -541,7 +542,8 @@ class TextFileFilterPolicyParser {
)
}
val p = policy.withReason(
- "$FILTER_REASON (special-class feature flags)"
+ "$FILTER_REASON (special-class feature flags)",
+ StatsLabel.SupportedButBoring,
)
processor.onSpecialClassPolicy(classType, p)
featureFlagsPolicy = p
@@ -554,7 +556,8 @@ class TextFileFilterPolicyParser {
)
}
val p = policy.withReason(
- "$FILTER_REASON (special-class sysprops)"
+ "$FILTER_REASON (special-class sysprops)",
+ StatsLabel.SupportedButBoring,
)
processor.onSpecialClassPolicy(classType, p)
syspropsPolicy = p
@@ -567,7 +570,8 @@ class TextFileFilterPolicyParser {
)
}
val p = policy.withReason(
- "$FILTER_REASON (special-class R file)"
+ "$FILTER_REASON (special-class R file)",
+ StatsLabel.SupportedButBoring,
)
processor.onSpecialClassPolicy(classType, p)
rFilePolicy = p
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/README.md b/ravenwood/tools/hoststubgen/test-tiny-framework/README.md
deleted file mode 100644
index 344b4e953b23..000000000000
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# HostStubGen: tiny-framework test
-
-This directory contains a small classes that "simulates" framework.jar, and tests against it.
-
-This test is agnostic to Android, and it doesn't use any android framework code or knowledge.
-
-## How to run
-
-- With `atest`. This is the proper way to run it, but `atest` has known problems that may
- affect the result. If you see weird problems, try the next `run-ravenwood-test` command.
-
-```
-$ atest hoststubgen-test-tiny-test
-```
-
-- `run-test-manually.sh` also run the test, but it builds the stub/impl jars and the test without
- using the build system. This is useful for debugging the tool.
-
-```
-$ ./run-test-manually.sh
-``` \ No newline at end of file
diff --git a/services/Android.bp b/services/Android.bp
index efd35ce8f1a3..8657bfc79316 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -181,7 +181,7 @@ art_profile_java_defaults {
conditions_default: {
dex_preopt: {
app_image: true,
- profile: "art-profile",
+ profile: ":art-profile-combined",
},
},
},
@@ -391,9 +391,14 @@ platform_compat_config {
src: ":services",
}
-filegroup {
- name: "art-profile",
- srcs: ["art-profile"],
+genrule {
+ name: "art-profile-combined",
+ srcs: [
+ "art-profile",
+ "art-profile-extra",
+ ],
+ out: ["art-profile-combined"],
+ cmd: "cat $(location art-profile) $(location art-profile-extra) > $(location art-profile-combined)",
}
// API stub
diff --git a/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java b/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java
index edcf5748a8fc..8cf94b464a1a 100644
--- a/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java
@@ -160,24 +160,16 @@ public class HearingDevicePhoneCallNotificationController {
mHearingDevice = null;
}
if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
- if (com.android.server.accessibility.Flags.hearingInputChangeWhenCommDevice()) {
- AudioDeviceInfo commDevice = mAudioManager.getCommunicationDevice();
- if (commDevice == null) {
- return;
- }
- mHearingDevice = getSupportedInputHearingDeviceInfo(List.of(commDevice));
- if (mHearingDevice != null) {
- showNotificationIfNeeded();
- } else {
- addOnCommunicationDeviceChangedListenerIfNeeded(mCommDeviceChangedExecutor,
- mCommDeviceChangedListener);
- }
+ AudioDeviceInfo commDevice = mAudioManager.getCommunicationDevice();
+ if (commDevice == null) {
+ return;
+ }
+ mHearingDevice = getSupportedInputHearingDeviceInfo(List.of(commDevice));
+ if (mHearingDevice != null) {
+ showNotificationIfNeeded();
} else {
- mHearingDevice = getSupportedInputHearingDeviceInfo(
- mAudioManager.getAvailableCommunicationDevices());
- if (mHearingDevice != null) {
- showNotificationIfNeeded();
- }
+ addOnCommunicationDeviceChangedListenerIfNeeded(mCommDeviceChangedExecutor,
+ mCommDeviceChangedListener);
}
}
}
diff --git a/services/art-profile-extra b/services/art-profile-extra
new file mode 100644
index 000000000000..54362411e5ea
--- /dev/null
+++ b/services/art-profile-extra
@@ -0,0 +1 @@
+HSPLcom/android/server/am/ActivityManagerService$LocalService;->checkContentProviderAccess(Ljava/lang/String;I)Ljava/lang/String;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5395d2a914ec..c15915ba39a4 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -790,7 +790,7 @@ public final class ActiveServices {
"SHORT_FGS_TIMEOUT");
this.mServiceFGAnrTimer = new ServiceAnrTimer(service,
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG,
- "SERVICE_FOREGROUND_TIMEOUT");
+ "SERVICE_FOREGROUND_TIMEOUT", new AnrTimer.Args().extend(true));
}
void systemServicesReady() {
@@ -7702,6 +7702,11 @@ public final class ActiveServices {
super(Objects.requireNonNull(am).mHandler, msg, label);
}
+ ServiceAnrTimer(ActivityManagerService am, int msg, String label,
+ @NonNull AnrTimer.Args args) {
+ super(Objects.requireNonNull(am).mHandler, msg, label, args);
+ }
+
@Override
public int getPid(@NonNull ServiceRecord service) {
return (service.app != null) ? service.app.getPid() : 0;
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 225c7ca2ca9e..83db027e1b41 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -2264,8 +2264,8 @@ public class AppProfiler {
final int idleTime = mProcessCpuTracker.getLastIdleTime();
bstats.addCpuStatsLocked(totalUTime, totalSTime, userTime,
systemTime, iowaitTime, irqTime, softIrqTime, idleTime);
+ bstats.finishAddingCpuStatsLocked();
}
- bstats.finishAddingCpuStatsLocked();
}
if (mLastWriteTime < (now - BATTERY_STATS_TIME)) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 5ff6999e40b3..6b4a99cc4fae 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -211,7 +211,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub
private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000;
private static final String DEVICE_CONFIG_NAMESPACE = "backstage_power";
private static final String MIN_CONSUMED_POWER_THRESHOLD_KEY = "min_consumed_power_threshold";
- private static final String EMPTY = "Empty";
private final HandlerThread mHandlerThread;
private final Handler mHandler;
@@ -336,55 +335,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
- @Override
- public String getSubsystemLowPowerStats() {
- synchronized (mPowerStatsLock) {
- if (mPowerStatsInternal == null || mEntityNames.isEmpty() || mStateNames.isEmpty()) {
- return EMPTY;
- }
- }
-
- final StateResidencyResult[] results;
- try {
- results = mPowerStatsInternal.getStateResidencyAsync(new int[0])
- .get(POWER_STATS_QUERY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- } catch (Exception e) {
- Slog.e(TAG, "Failed to getStateResidencyAsync", e);
- return EMPTY;
- }
-
- if (results == null || results.length == 0) return EMPTY;
-
- int charsLeft = MAX_LOW_POWER_STATS_SIZE;
- StringBuilder builder = new StringBuilder("SubsystemPowerState");
- for (int i = 0; i < results.length; i++) {
- final StateResidencyResult result = results[i];
- StringBuilder subsystemBuilder = new StringBuilder();
- subsystemBuilder.append(" subsystem_" + i);
- subsystemBuilder.append(" name=" + mEntityNames.get(result.id));
-
- for (int j = 0; j < result.stateResidencyData.length; j++) {
- final StateResidency stateResidency = result.stateResidencyData[j];
- subsystemBuilder.append(" state_" + j);
- subsystemBuilder.append(" name=" + mStateNames.get(result.id).get(
- stateResidency.id));
- subsystemBuilder.append(" time=" + stateResidency.totalTimeInStateMs);
- subsystemBuilder.append(" count=" + stateResidency.totalStateEntryCount);
- subsystemBuilder.append(" last entry=" + stateResidency.lastEntryTimestampMs);
- }
-
- if (subsystemBuilder.length() <= charsLeft) {
- charsLeft -= subsystemBuilder.length();
- builder.append(subsystemBuilder);
- } else {
- Slog.e(TAG, "getSubsystemLowPowerStats: buffer not enough");
- break;
- }
- }
-
- return builder.toString();
- }
-
private ConnectivityManager.NetworkCallback mNetworkCallback =
new ConnectivityManager.NetworkCallback() {
@Override
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index c2ed4d557e69..4eadab27aa26 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -317,8 +317,6 @@ public class SettingsToPropertiesMapper {
private final String[] mDeviceConfigScopes;
- private final String[] mDeviceConfigAconfigScopes;
-
private final ContentResolver mContentResolver;
@VisibleForTesting
@@ -329,7 +327,6 @@ public class SettingsToPropertiesMapper {
mContentResolver = contentResolver;
mGlobalSettings = globalSettings;
mDeviceConfigScopes = deviceConfigScopes;
- mDeviceConfigAconfigScopes = deviceConfigAconfigScopes;
}
@VisibleForTesting
@@ -375,36 +372,6 @@ public class SettingsToPropertiesMapper {
return;
}
setProperty(propertyName, properties.getString(key, null));
-
- // for legacy namespaces, they can also be used for trunk stable
- // purposes. so push flag also into trunk stable slot in sys prop,
- // later all legacy usage will be refactored and the sync to old
- // sys prop slot can be removed.
- String aconfigPropertyName = makeAconfigFlagPropertyName(scope, key);
- if (aconfigPropertyName == null) {
- logErr("unable to construct system property for " + scope + "/"
- + key);
- return;
- }
- setProperty(aconfigPropertyName, properties.getString(key, null));
- }
- });
- }
-
- for (String deviceConfigAconfigScope : mDeviceConfigAconfigScopes) {
- DeviceConfig.addOnPropertiesChangedListener(
- deviceConfigAconfigScope,
- AsyncTask.THREAD_POOL_EXECUTOR,
- (DeviceConfig.Properties properties) -> {
- String scope = properties.getNamespace();
- for (String key : properties.getKeyset()) {
- String aconfigPropertyName = makeAconfigFlagPropertyName(scope, key);
- if (aconfigPropertyName == null) {
- logErr("unable to construct system property for " + scope + "/"
- + key);
- return;
- }
- setProperty(aconfigPropertyName, properties.getString(key, null));
}
});
}
@@ -420,34 +387,6 @@ public class SettingsToPropertiesMapper {
stageFlagsInNewStorage(properties);
return;
}
-
- for (String flagName : properties.getKeyset()) {
- String flagValue = properties.getString(flagName, null);
- if (flagName == null || flagValue == null) {
- continue;
- }
-
- int idx = flagName.indexOf(NAMESPACE_REBOOT_STAGING_DELIMITER);
- if (idx == -1 || idx == flagName.length() - 1 || idx == 0) {
- logErr("invalid staged flag: " + flagName);
- continue;
- }
-
- String actualNamespace = flagName.substring(0, idx);
- String actualFlagName = flagName.substring(idx+1);
- String propertyName = "next_boot." + makeAconfigFlagPropertyName(
- actualNamespace, actualFlagName);
-
- if (Flags.supportLocalOverridesSysprops()) {
- // Don't propagate if there is a local override.
- String overrideName = actualNamespace + ":" + actualFlagName;
- if (DeviceConfig.getProperty(NAMESPACE_LOCAL_OVERRIDES, overrideName) != null) {
- continue;
- }
- }
- setProperty(propertyName, flagValue);
- }
-
});
// add prop sync callback for flag local overrides
@@ -459,42 +398,6 @@ public class SettingsToPropertiesMapper {
setLocalOverridesInNewStorage(properties);
return;
}
-
- if (Flags.supportLocalOverridesSysprops()) {
- String overridesNamespace = properties.getNamespace();
- for (String key : properties.getKeyset()) {
- String realNamespace = key.split(":")[0];
- String realFlagName = key.split(":")[1];
- String aconfigPropertyName =
- makeAconfigFlagPropertyName(realNamespace, realFlagName);
- if (aconfigPropertyName == null) {
- logErr("unable to construct system property for " + realNamespace + "/"
- + key);
- return;
- }
-
- if (properties.getString(key, null) == null) {
- String deviceConfigValue =
- DeviceConfig.getProperty(realNamespace, realFlagName);
- String stagedDeviceConfigValue =
- DeviceConfig.getProperty(NAMESPACE_REBOOT_STAGING,
- realNamespace + "*" + realFlagName);
-
- setProperty(aconfigPropertyName, deviceConfigValue);
- if (stagedDeviceConfigValue == null) {
- setProperty("next_boot." + aconfigPropertyName, deviceConfigValue);
- } else {
- setProperty("next_boot." + aconfigPropertyName, stagedDeviceConfigValue);
- }
- } else {
- // Otherwise, propagate the override to sysprops.
- setProperty(aconfigPropertyName, properties.getString(key, null));
- // If there's a staged value, make sure it's the override value.
- setProperty("next_boot." + aconfigPropertyName,
- properties.getString(key, null));
- }
- }
- }
});
}
@@ -822,28 +725,6 @@ public class SettingsToPropertiesMapper {
sendAconfigdRequests(requests);
}
- /**
- * system property name constructing rule for aconfig flags:
- * "persist.device_config.aconfig_flags.[category_name].[flag_name]".
- * If the name contains invalid characters or substrings for system property name,
- * will return null.
- * @param categoryName
- * @param flagName
- * @return
- */
- @VisibleForTesting
- static String makeAconfigFlagPropertyName(String categoryName, String flagName) {
- String propertyName = SYSTEM_PROPERTY_PREFIX + "aconfig_flags." +
- categoryName + "." + flagName;
-
- if (!propertyName.matches(SYSTEM_PROPERTY_VALID_CHARACTERS_REGEX)
- || propertyName.contains(SYSTEM_PROPERTY_INVALID_SUBSTRING)) {
- return null;
- }
-
- return propertyName;
- }
-
private void setProperty(String key, String value) {
// Check if need to clear the property
if (value == null) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 5ecac2253b49..2e229ca9d10f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -55,7 +55,6 @@ import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM_OPS;
import static android.app.AppOpsManager.SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE;
-import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
import static android.app.AppOpsManager._NUM_OP;
import static android.app.AppOpsManager.extractFlagsFromKey;
@@ -464,7 +463,19 @@ public class AppOpsService extends IAppOpsService.Stub {
Clock.SYSTEM_CLOCK, mConstants);
mUidStateTracker.addUidStateChangedCallback(new HandlerExecutor(mHandler),
- this::onUidStateChanged);
+ new AppOpsUidStateTracker.UidStateChangedCallback() {
+ @Override
+ public void onUidStateChanged(int uid, int uidState,
+ boolean foregroundModeMayChange) {
+ AppOpsService.this
+ .onUidStateChanged(uid, uidState, foregroundModeMayChange);
+ }
+
+ @Override
+ public void onUidProcessDeath(int uid) {
+ AppOpsService.this.onUidProcessDeath(uid);
+ }
+ });
}
return mUidStateTracker;
}
@@ -1500,9 +1511,6 @@ public class AppOpsService extends IAppOpsService.Stub {
// The callback method from AppOpsUidStateTracker
private void onUidStateChanged(int uid, int state, boolean foregroundModeMayChange) {
synchronized (this) {
- if (state == UID_STATE_NONEXISTENT) {
- onUidProcessDeathLocked(uid);
- }
UidState uidState = getUidStateLocked(uid, false);
boolean hasForegroundWatchers = false;
@@ -1590,11 +1598,6 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
- if (state == UID_STATE_NONEXISTENT) {
- // For UID_STATE_NONEXISTENT, we don't call onUidStateChanged for AttributedOps
- return;
- }
-
if (uidState != null) {
int numPkgs = uidState.pkgOps.size();
for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
@@ -1619,31 +1622,32 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
- @GuardedBy("this")
- private void onUidProcessDeathLocked(int uid) {
- if (!mUidStates.contains(uid) || !Flags.finishRunningOpsForKilledPackages()) {
- return;
- }
- final SparseLongArray chainsToFinish = new SparseLongArray();
- doForAllAttributedOpsInUidLocked(uid, (attributedOp) -> {
- attributedOp.doForAllInProgressStartOpEvents((event) -> {
- if (event == null) {
- return;
- }
- int chainId = event.getAttributionChainId();
- if (chainId != ATTRIBUTION_CHAIN_ID_NONE) {
- long currentEarliestStartTime =
- chainsToFinish.get(chainId, Long.MAX_VALUE);
- if (event.getStartTime() < currentEarliestStartTime) {
- // Store the earliest chain link we're finishing, so that we can go back
- // and finish any links in the chain that started after this one
- chainsToFinish.put(chainId, event.getStartTime());
+ private void onUidProcessDeath(int uid) {
+ synchronized (this) {
+ if (!mUidStates.contains(uid) || !Flags.finishRunningOpsForKilledPackages()) {
+ return;
+ }
+ final SparseLongArray chainsToFinish = new SparseLongArray();
+ doForAllAttributedOpsInUidLocked(uid, (attributedOp) -> {
+ attributedOp.doForAllInProgressStartOpEvents((event) -> {
+ if (event == null) {
+ return;
}
- }
- attributedOp.finished(event.getClientId());
+ int chainId = event.getAttributionChainId();
+ if (chainId != ATTRIBUTION_CHAIN_ID_NONE) {
+ long currentEarliestStartTime =
+ chainsToFinish.get(chainId, Long.MAX_VALUE);
+ if (event.getStartTime() < currentEarliestStartTime) {
+ // Store the earliest chain link we're finishing, so that we can go back
+ // and finish any links in the chain that started after this one
+ chainsToFinish.put(chainId, event.getStartTime());
+ }
+ }
+ attributedOp.finished(event.getClientId());
+ });
});
- });
- finishChainsLocked(chainsToFinish);
+ finishChainsLocked(chainsToFinish);
+ }
}
@GuardedBy("this")
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
index 268b286d8fe1..9bd72990f7b7 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
@@ -19,6 +19,7 @@ package com.android.server.appop;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
@@ -27,8 +28,10 @@ import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
+import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
import static android.app.AppOpsManager.UID_STATE_TOP;
+import static android.permission.flags.Flags.finishRunningOpsForKilledPackages;
import android.annotation.CallbackExecutor;
import android.util.SparseArray;
@@ -68,6 +71,14 @@ interface AppOpsUidStateTracker {
return UID_STATE_BACKGROUND;
}
+ if (finishRunningOpsForKilledPackages()) {
+ if (procState < PROCESS_STATE_NONEXISTENT) {
+ return UID_STATE_CACHED;
+ }
+
+ return UID_STATE_NONEXISTENT;
+ }
+
// UID_STATE_NONEXISTENT is deliberately excluded here
return UID_STATE_CACHED;
}
@@ -119,6 +130,8 @@ interface AppOpsUidStateTracker {
* evaluated result may have changed.
*/
void onUidStateChanged(int uid, int uidState, boolean foregroundModeMayChange);
+
+ void onUidProcessDeath(int uid);
}
void dumpUidState(PrintWriter pw, int uid, long nowElapsed);
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index 6f8c241a86ae..1a1077ad0e7b 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -21,7 +21,6 @@ import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
-import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.ProcessCapability;
import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
import static android.app.AppOpsManager.MODE_ALLOWED;
@@ -32,6 +31,7 @@ import static android.app.AppOpsManager.OP_CONTROL_AUDIO;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
@@ -75,7 +75,6 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
private SparseBooleanArray mAppWidgetVisible = new SparseBooleanArray();
private SparseBooleanArray mPendingAppWidgetVisible = new SparseBooleanArray();
private SparseLongArray mPendingCommitTime = new SparseLongArray();
- private SparseBooleanArray mPendingGone = new SparseBooleanArray();
private ArrayMap<UidStateChangedCallback, Executor>
mUidStateChangedCallbacks = new ArrayMap<>();
@@ -221,11 +220,12 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
public void updateUidProcState(int uid, int procState, int capability) {
int uidState = processStateToUidState(procState);
- int prevUidState = mUidStates.get(uid, AppOpsManager.MIN_PRIORITY_UID_STATE);
+ int prevUidState = mUidStates.get(uid, AppOpsManager.UID_STATE_NONEXISTENT);
int prevCapability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
- int pendingUidState = mPendingUidStates.get(uid, MIN_PRIORITY_UID_STATE);
+ int pendingUidState = mPendingUidStates.get(uid, UID_STATE_NONEXISTENT);
int pendingCapability = mPendingCapability.get(uid, PROCESS_CAPABILITY_NONE);
long pendingStateCommitTime = mPendingCommitTime.get(uid, 0);
+
if ((pendingStateCommitTime == 0
&& (uidState != prevUidState || capability != prevCapability))
|| (pendingStateCommitTime != 0
@@ -239,8 +239,7 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
boolean hasLostCapability = (prevCapability & ~capability) != 0;
- if (procState == PROCESS_STATE_NONEXISTENT) {
- mPendingGone.put(uid, true);
+ if (uidState == UID_STATE_NONEXISTENT) {
commitUidPendingState(uid);
} else if (uidState < prevUidState) {
// We are moving to a more important state, or the new state may be in the
@@ -342,7 +341,7 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
private void commitUidPendingState(int uid) {
- int uidState = mUidStates.get(uid, MIN_PRIORITY_UID_STATE);
+ int uidState = mUidStates.get(uid, UID_STATE_NONEXISTENT);
int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
boolean appWidgetVisible = mAppWidgetVisible.get(uid, false);
@@ -350,18 +349,23 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
int pendingCapability = mPendingCapability.get(uid, capability);
boolean pendingAppWidgetVisible = mPendingAppWidgetVisible.get(uid, appWidgetVisible);
- boolean foregroundChange = uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
- != pendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+ // UID_STATE_NONEXISTENT is a state that isn't used outside of this class, nonexistent
+ // processes have always been represented as CACHED
+ int externalUidState = Math.min(uidState, UID_STATE_CACHED);
+ int externalPendingUidState = Math.min(pendingUidState, UID_STATE_CACHED);
+
+ boolean foregroundChange = externalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+ != externalPendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
|| capability != pendingCapability
|| appWidgetVisible != pendingAppWidgetVisible;
- if (uidState != pendingUidState
+ if (externalUidState != externalPendingUidState
|| capability != pendingCapability
|| appWidgetVisible != pendingAppWidgetVisible) {
if (foregroundChange) {
// To save on memory usage, log only interesting changes.
- mEventLog.logCommitUidState(uid, pendingUidState, pendingCapability,
+ mEventLog.logCommitUidState(uid, externalPendingUidState, pendingCapability,
pendingAppWidgetVisible, appWidgetVisible != pendingAppWidgetVisible);
}
@@ -370,24 +374,23 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
Executor executor = mUidStateChangedCallbacks.valueAt(i);
executor.execute(PooledLambda.obtainRunnable(
- UidStateChangedCallback::onUidStateChanged, cb, uid, pendingUidState,
- foregroundChange));
+ UidStateChangedCallback::onUidStateChanged, cb, uid,
+ externalPendingUidState, foregroundChange));
}
}
- if (mPendingGone.get(uid, false)) {
+ if (pendingUidState == UID_STATE_NONEXISTENT && uidState != pendingUidState) {
mUidStates.delete(uid);
mCapability.delete(uid);
mAppWidgetVisible.delete(uid);
- mPendingGone.delete(uid);
if (finishRunningOpsForKilledPackages()) {
for (int i = 0; i < mUidStateChangedCallbacks.size(); i++) {
UidStateChangedCallback cb = mUidStateChangedCallbacks.keyAt(i);
Executor executor = mUidStateChangedCallbacks.valueAt(i);
+ // If foregroundness changed it should be handled in earlier callback invocation
executor.execute(PooledLambda.obtainRunnable(
- UidStateChangedCallback::onUidStateChanged, cb, uid,
- UID_STATE_NONEXISTENT, foregroundChange));
+ UidStateChangedCallback::onUidProcessDeath, cb, uid));
}
}
} else {
diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
index b4df1f76dccb..569a426b80d5 100644
--- a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
+++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
@@ -111,13 +111,14 @@ class DisplayTopologyCoordinator {
* @param info The display info
*/
void onDisplayAdded(DisplayInfo info) {
- if (!isDisplayAllowedInTopology(info)) {
+ if (!isDisplayAllowedInTopology(info, /* shouldLog= */ true)) {
return;
}
synchronized (mSyncRoot) {
addDisplayIdMappingLocked(info);
mDensities.put(info.displayId, info.logicalDensityDpi);
mTopology.addDisplay(info.displayId, getWidth(info), getHeight(info));
+ Slog.i(TAG, "Display " + info.displayId + " added, new topology: " + mTopology);
restoreTopologyLocked();
sendTopologyUpdateLocked();
}
@@ -128,7 +129,7 @@ class DisplayTopologyCoordinator {
* @param info The new display info
*/
void onDisplayChanged(DisplayInfo info) {
- if (!isDisplayAllowedInTopology(info)) {
+ if (!isDisplayAllowedInTopology(info, /* shouldLog= */ false)) {
return;
}
synchronized (mSyncRoot) {
@@ -149,6 +150,7 @@ class DisplayTopologyCoordinator {
synchronized (mSyncRoot) {
mDensities.delete(displayId);
if (mTopology.removeDisplay(displayId)) {
+ Slog.i(TAG, "Display " + displayId + " removed, new topology: " + mTopology);
removeDisplayIdMappingLocked(displayId);
restoreTopologyLocked();
sendTopologyUpdateLocked();
@@ -249,22 +251,28 @@ class DisplayTopologyCoordinator {
return pxToDp(info.logicalHeight, info.logicalDensityDpi);
}
- private boolean isDisplayAllowedInTopology(DisplayInfo info) {
+ private boolean isDisplayAllowedInTopology(DisplayInfo info, boolean shouldLog) {
if (info.type != Display.TYPE_INTERNAL && info.type != Display.TYPE_EXTERNAL
&& info.type != Display.TYPE_OVERLAY) {
- Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
- + "type is not INTERNAL, EXTERNAL or OVERLAY");
+ if (shouldLog) {
+ Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
+ + "type is not INTERNAL, EXTERNAL or OVERLAY");
+ }
return false;
}
if (info.type == Display.TYPE_INTERNAL && info.displayId != Display.DEFAULT_DISPLAY) {
- Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
- + "it is a non-default internal display");
+ if (shouldLog) {
+ Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
+ + "it is a non-default internal display");
+ }
return false;
}
if ((info.type == Display.TYPE_EXTERNAL || info.type == Display.TYPE_OVERLAY)
&& !mIsExtendedDisplayAllowed.getAsBoolean()) {
- Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
- + "type is EXTERNAL or OVERLAY and !mIsExtendedDisplayAllowed");
+ if (shouldLog) {
+ Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
+ + "type is EXTERNAL or OVERLAY and !mIsExtendedDisplayAllowed");
+ }
return false;
}
return true;
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 60b7fca99e7b..228e6f1c4ddb 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -130,6 +130,14 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
private static final String OVERLAY_DISPLAY_FLAG_FIXED_CONTENT_MODE =
"fixed_content_mode";
+ /**
+ * When this flag is set, disables support for moving and resizing the overlay window.
+ * As the window is made non-touchable, this also makes it possible to directly interact with
+ * the content underneath.
+ */
+ private static final String OVERLAY_DISPLAY_FLAG_DISABLE_WINDOW_INTERACTION =
+ "disable_window_interaction";
+
// Gravity flags to decide where the overlay should be shown.
private static final String GRAVITY_TOP_LEFT = "gravity_top_left";
private static final String GRAVITY_BOTTOM_RIGHT = "gravity_bottom_right";
@@ -571,9 +579,9 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
@Override
public void run() {
OverlayMode mode = mModes.get(mActiveMode);
- OverlayDisplayWindow window = new OverlayDisplayWindow(getContext(),
- mName, mode.mWidth, mode.mHeight, mode.mDensityDpi, mGravity,
- mFlags.mSecure, OverlayDisplayHandle.this);
+ OverlayDisplayWindow window = new OverlayDisplayWindow(getContext(), mName,
+ mode.mWidth, mode.mHeight, mode.mDensityDpi, mGravity, mFlags.mSecure,
+ mFlags.mDisableWindowInteraction, OverlayDisplayHandle.this);
window.show();
synchronized (getSyncRoot()) {
@@ -655,6 +663,9 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
/** See {@link #OVERLAY_DISPLAY_FLAG_FIXED_CONTENT_MODE}. */
final boolean mFixedContentMode;
+ /** See {@link #OVERLAY_DISPLAY_FLAG_DISABLE_WINDOW_INTERACTION}. */
+ final boolean mDisableWindowInteraction;
+
final int mGravity;
OverlayFlags(
@@ -662,11 +673,13 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
boolean ownContentOnly,
boolean shouldShowSystemDecorations,
boolean fixedContentMode,
+ boolean disableWindowInteraction,
int gravity) {
mSecure = secure;
mOwnContentOnly = ownContentOnly;
mShouldShowSystemDecorations = shouldShowSystemDecorations;
mFixedContentMode = fixedContentMode;
+ mDisableWindowInteraction = disableWindowInteraction;
mGravity = gravity;
}
@@ -677,6 +690,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
false /* ownContentOnly */,
false /* shouldShowSystemDecorations */,
false /* fixedContentMode */,
+ false /* disableWindowInteraction */,
Gravity.NO_GRAVITY);
}
@@ -684,6 +698,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
boolean ownContentOnly = false;
boolean shouldShowSystemDecorations = false;
boolean fixedContentMode = false;
+ boolean disableWindowInteraction = false;
int gravity = Gravity.NO_GRAVITY;
for (String flag: flagString.split(FLAG_SPLITTER)) {
if (OVERLAY_DISPLAY_FLAG_SECURE.equals(flag)) {
@@ -694,12 +709,14 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
shouldShowSystemDecorations = true;
} else if (OVERLAY_DISPLAY_FLAG_FIXED_CONTENT_MODE.equals(flag)) {
fixedContentMode = true;
+ } else if (OVERLAY_DISPLAY_FLAG_DISABLE_WINDOW_INTERACTION.equals(flag)) {
+ disableWindowInteraction = true;
} else {
gravity = parseOverlayGravity(flag);
}
}
return new OverlayFlags(secure, ownContentOnly, shouldShowSystemDecorations,
- fixedContentMode, gravity);
+ fixedContentMode, disableWindowInteraction, gravity);
}
@Override
@@ -709,6 +726,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
.append(", ownContentOnly=").append(mOwnContentOnly)
.append(", shouldShowSystemDecorations=").append(mShouldShowSystemDecorations)
.append(", fixedContentMode=").append(mFixedContentMode)
+ .append(", disableWindowInteraction=").append(mDisableWindowInteraction)
.append(", gravity").append(Gravity.toString(mGravity))
.append("}")
.toString();
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index 3fd58e8641c3..523bbfa7d69a 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -69,6 +69,7 @@ final class OverlayDisplayWindow implements DumpUtils.Dump {
private int mDensityDpi;
private final int mGravity;
private final boolean mSecure;
+ private final boolean mDisableWindowInteraction;
private final Listener mListener;
private String mTitle;
@@ -96,15 +97,15 @@ final class OverlayDisplayWindow implements DumpUtils.Dump {
private float mLiveTranslationY;
private float mLiveScale = 1.0f;
- public OverlayDisplayWindow(Context context, String name,
- int width, int height, int densityDpi, int gravity, boolean secure,
- Listener listener) {
+ OverlayDisplayWindow(Context context, String name, int width, int height, int densityDpi,
+ int gravity, boolean secure, boolean disableWindowInteraction, Listener listener) {
// Workaround device freeze (b/38372997)
ThreadedRenderer.disableVsync();
mContext = context;
mName = name;
mGravity = gravity;
mSecure = secure;
+ mDisableWindowInteraction = disableWindowInteraction;
mListener = listener;
mDisplayManager = (DisplayManager)context.getSystemService(
@@ -226,8 +227,10 @@ final class OverlayDisplayWindow implements DumpUtils.Dump {
if (mSecure) {
mWindowParams.flags |= WindowManager.LayoutParams.FLAG_SECURE;
}
- if (DISABLE_MOVE_AND_RESIZE) {
+ if (DISABLE_MOVE_AND_RESIZE || mDisableWindowInteraction) {
mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ mWindowParams.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
}
mWindowParams.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 52ddb800fa40..695bf612ccc3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -82,4 +82,11 @@ public interface NotificationManagerInternal {
byte[] getBackupPayload(int user, BackupRestoreEventLogger logger);
void applyRestore(byte[] payload, int user, BackupRestoreEventLogger logger);
+
+ /**
+ * Notifies NotificationManager that the system decorations should be removed from the display.
+ *
+ * @param displayId display ID
+ */
+ void onDisplayRemoveSystemDecorations(int displayId);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 06fc9b083086..6ce1746ed3f6 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8214,6 +8214,18 @@ public class NotificationManagerService extends SystemService {
// This can also throw IllegalStateException if called too late.
mZenModeHelper.setDeviceEffectsApplier(applier);
}
+
+ @Override
+ public void onDisplayRemoveSystemDecorations(int displayId) {
+ synchronized (mToastQueue) {
+ for (int i = mToastQueue.size() - 1; i >= 0; i--) {
+ final ToastRecord toast = mToastQueue.get(i);
+ if (toast.displayId == displayId) {
+ cancelToastLocked(i);
+ }
+ }
+ }
+ }
};
private static boolean isBigPictureWithBitmapOrIcon(Notification n) {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 2dd679818ada..5160319c8cf6 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -379,9 +379,10 @@ public class LauncherAppsService extends SystemService {
public List<UserHandle> getUserProfiles() {
int[] userIds;
if (!canAccessHiddenProfile(getCallingUid(), getCallingPid())) {
- userIds = mUm.getProfileIdsExcludingHidden(getCallingUserId(), /* enabled= */ true);
+ userIds = mUserManagerInternal.getProfileIdsExcludingHidden(getCallingUserId(),
+ /* enabled= */ true);
} else {
- userIds = mUm.getEnabledProfileIds(getCallingUserId());
+ userIds = mUserManagerInternal.getProfileIds(getCallingUserId(), true);
}
final List<UserHandle> result = new ArrayList<>(userIds.length);
for (int userId : userIds) {
@@ -398,9 +399,10 @@ public class LauncherAppsService extends SystemService {
int[] userIds;
if (!canAccessHiddenProfile(callingUid, Binder.getCallingPid())) {
- userIds = mUm.getProfileIdsExcludingHidden(getCallingUserId(), /* enabled= */ true);
+ userIds = mUserManagerInternal.getProfileIdsExcludingHidden(getCallingUserId(),
+ /* enabled= */ true);
} else {
- userIds = mUm.getEnabledProfileIds(getCallingUserId());
+ userIds = mUserManagerInternal.getProfileIds(getCallingUserId(), true);
}
final long token = Binder.clearCallingIdentity();
@@ -503,16 +505,11 @@ public class LauncherAppsService extends SystemService {
return true;
}
- long ident = injectClearCallingIdentity();
- try {
- final UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
- if (callingUserInfo != null && callingUserInfo.isProfile()) {
- Slog.w(TAG, message + " for another profile "
- + targetUserId + " from " + callingUserId + " not allowed");
- return false;
- }
- } finally {
- injectRestoreCallingIdentity(ident);
+ final UserInfo callingUserInfo = mUserManagerInternal.getUserInfo(callingUserId);
+ if (callingUserInfo != null && callingUserInfo.isProfile()) {
+ Slog.w(TAG, message + " for another profile "
+ + targetUserId + " from " + callingUserId + " not allowed");
+ return false;
}
if (isHiddenProfile(UserHandle.of(targetUserId))
@@ -529,9 +526,9 @@ public class LauncherAppsService extends SystemService {
return false;
}
- long identity = injectClearCallingIdentity();
try {
- UserProperties properties = mUm.getUserProperties(targetUser);
+ UserProperties properties = mUserManagerInternal
+ .getUserProperties(targetUser.getIdentifier());
if (properties == null) {
return false;
}
@@ -540,8 +537,6 @@ public class LauncherAppsService extends SystemService {
== UserProperties.PROFILE_API_VISIBILITY_HIDDEN;
} catch (IllegalArgumentException e) {
return false;
- } finally {
- injectRestoreCallingIdentity(identity);
}
}
@@ -686,7 +681,7 @@ public class LauncherAppsService extends SystemService {
final int callingUid = injectBinderCallingUid();
final long ident = injectClearCallingIdentity();
try {
- if (mUm.getUserInfo(user.getIdentifier()).isManagedProfile()) {
+ if (mUserManagerInternal.getUserInfo(user.getIdentifier()).isManagedProfile()) {
// Managed profile should not show hidden apps
return launcherActivities;
}
@@ -1713,7 +1708,7 @@ public class LauncherAppsService extends SystemService {
}
final long identity = Binder.clearCallingIdentity();
try {
- String userType = mUm.getUserInfo(user.getIdentifier()).userType;
+ String userType = mUserManagerInternal.getUserInfo(user.getIdentifier()).userType;
Set<String> preInstalledPackages = mUm.getPreInstallableSystemPackages(userType);
if (preInstalledPackages == null) {
return new ArrayList<>();
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index e98176b0e82b..41ce4fa81668 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -368,6 +368,21 @@ public abstract class UserManagerInternal {
public abstract @NonNull int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly);
/**
+ * Returns a list of the users that are associated with the specified user, including the user
+ * itself. This includes the user, its profiles, its parent, and its parent's other profiles,
+ * as applicable.
+ *
+ * <p>Note that this includes only profile types that are not hidden.
+ *
+ * @param userId id of the user to return profiles for
+ * @param enabledOnly whether return only {@link UserInfo#isEnabled() enabled} profiles
+ * @return A non-empty array of ids of profiles associated with the specified user if the user
+ * exists. Otherwise, an empty array.
+ */
+ public abstract @NonNull int[] getProfileIdsExcludingHidden(@UserIdInt int userId,
+ boolean enabledOnly);
+
+ /**
* Checks if the {@code callingUserId} and {@code targetUserId} are same or in same group
* and that the {@code callingUserId} is not a profile and {@code targetUserId} is enabled.
*
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 053b4aae90dd..0ea9af4b9c38 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -8049,6 +8049,14 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
+ public int[] getProfileIdsExcludingHidden(@UserIdInt int userId, boolean enabledOnly) {
+ synchronized (mUsersLock) {
+ return getProfileIdsLU(userId, null /* userType */, enabledOnly, /* excludeHidden */
+ true).toArray();
+ }
+ }
+
+ @Override
public @Nullable LauncherUserInfo getLauncherUserInfo(@UserIdInt int userId) {
UserInfo userInfo;
synchronized (mUsersLock) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e9f522d08328..8cf0481b1dc3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4633,6 +4633,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@SuppressLint("MissingPermission")
private void injectBackGesture(long downtime) {
+ if (mActivityTaskManagerInternal.requestBackGesture()) {
+ return;
+ }
// Create and inject down event
KeyEvent downEvent = new KeyEvent(downtime, downtime, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3eac4b54cd2b..bef505867a14 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -130,12 +130,12 @@ import com.android.internal.util.LatencyTracker;
import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
import com.android.server.LockGuard;
+import com.android.server.PackageWatchdog;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
-import com.android.server.crashrecovery.CrashRecoveryHelper;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
@@ -4113,7 +4113,7 @@ public final class PowerManagerService extends SystemService
}
}
if (mHandler == null || !mSystemReady) {
- if (CrashRecoveryHelper.isRecoveryTriggeredReboot()) {
+ if (PackageWatchdog.isRecoveryTriggeredReboot()) {
// If we're stuck in a really low-level reboot loop, and a
// rescue party is trying to prompt the user for a factory data
// reset, we must GET TO DA CHOPPA!
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index d209ea90f3ca..4ae1b4e119fa 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -59,7 +59,7 @@ import android.view.SurfaceControl;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.crashrecovery.CrashRecoveryHelper;
+import com.android.server.PackageWatchdog;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -339,7 +339,7 @@ public final class ShutdownThread extends Thread {
com.android.internal.R.string.reboot_to_update_reboot));
}
} else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
- if (CrashRecoveryHelper.isRecoveryTriggeredReboot()) {
+ if (PackageWatchdog.isRecoveryTriggeredReboot()) {
// We're not actually doing a factory reset yet; we're rebooting
// to ask the user if they'd like to reset, so give them a less
// scary dialog message.
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 5ee9b7d09fdd..46c497d04f9e 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -176,7 +176,9 @@ public class ThermalManagerService extends SystemService {
try {
final HeadroomCallbackData data;
synchronized (mTemperatureWatcher.mSamples) {
- Slog.d(TAG, "Updating skin threshold: " + threshold);
+ if (DEBUG) {
+ Slog.d(TAG, "Updating skin threshold: " + threshold);
+ }
mTemperatureWatcher.updateTemperatureThresholdLocked(threshold, true);
data = mTemperatureWatcher.getHeadroomCallbackDataLocked();
}
@@ -454,7 +456,9 @@ public class ThermalManagerService extends SystemService {
&& temperature.getType() == Temperature.TYPE_SKIN) {
final HeadroomCallbackData data;
synchronized (mTemperatureWatcher.mSamples) {
- Slog.d(TAG, "Updating new temperature: " + temperature);
+ if (DEBUG) {
+ Slog.d(TAG, "Updating new temperature: " + temperature);
+ }
mTemperatureWatcher.updateTemperatureSampleLocked(System.currentTimeMillis(),
temperature);
mTemperatureWatcher.mCachedHeadrooms.clear();
@@ -1878,6 +1882,7 @@ public class ThermalManagerService extends SystemService {
@VisibleForTesting
long mInactivityThresholdMillis = INACTIVITY_THRESHOLD_MILLIS;
+ @GuardedBy("mSamples")
private final Handler mHandler = BackgroundThread.getHandler();
/**
@@ -1900,6 +1905,9 @@ public class ThermalManagerService extends SystemService {
@GuardedBy("mSamples")
private long mLastForecastCallTimeMillis = 0;
+ private final Runnable mGetAndUpdateTemperatureSamplesRunnable =
+ this::getAndUpdateTemperatureSamples;
+
void getAndUpdateThresholds() {
List<TemperatureThreshold> thresholds =
mHalWrapper.getTemperatureThresholds(true, Temperature.TYPE_SKIN);
@@ -1930,7 +1938,9 @@ public class ThermalManagerService extends SystemService {
return;
}
if (override) {
- Slog.d(TAG, "Headroom cache cleared on threshold update " + threshold);
+ if (DEBUG) {
+ Slog.d(TAG, "Headroom cache cleared on threshold update " + threshold);
+ }
mCachedHeadrooms.clear();
Arrays.fill(mHeadroomThresholds, Float.NaN);
}
@@ -1962,7 +1972,7 @@ public class ThermalManagerService extends SystemService {
< mInactivityThresholdMillis) {
// Trigger this again after a second as long as forecast has been called more
// recently than the inactivity timeout
- mHandler.postDelayed(this::getAndUpdateTemperatureSamples, 1000);
+ mHandler.postDelayed(mGetAndUpdateTemperatureSamplesRunnable, 1000);
} else {
// Otherwise, we've been idle for at least 10 seconds, so we should
// shut down
@@ -1974,6 +1984,9 @@ public class ThermalManagerService extends SystemService {
long now = SystemClock.elapsedRealtime();
final List<Temperature> temperatures = mHalWrapper.getCurrentTemperatures(true,
Temperature.TYPE_SKIN);
+ if (DEBUG) {
+ Slog.d(TAG, "Thermal HAL getCurrentTemperatures result: " + temperatures);
+ }
for (Temperature temperature : temperatures) {
updateTemperatureSampleLocked(now, temperature);
}
@@ -2080,10 +2093,16 @@ public class ThermalManagerService extends SystemService {
}
synchronized (mSamples) {
mLastForecastCallTimeMillis = SystemClock.elapsedRealtime();
- if (mSamples.isEmpty()) {
+ if (!mHandler.hasCallbacks(mGetAndUpdateTemperatureSamplesRunnable)) {
+ if (DEBUG) {
+ Slog.d(TAG, "No temperature update callback, scheduling one");
+ }
getAndUpdateTemperatureSamples();
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Temperature update callback already exists");
+ }
}
-
// If somehow things take much longer than expected or there are no temperatures
// to sample, return early
if (mSamples.isEmpty()) {
@@ -2103,8 +2122,11 @@ public class ThermalManagerService extends SystemService {
Binder.getCallingUid(),
FrameworkStatsLog.THERMAL_HEADROOM_CALLED__API_STATUS__SUCCESS,
headroom, forecastSeconds);
- Slog.d(TAG, "Headroom forecast in " + forecastSeconds + "s served from cache: "
- + headroom);
+ if (DEBUG) {
+ Slog.d(TAG,
+ "Headroom forecast in " + forecastSeconds + "s served from cache: "
+ + headroom);
+ }
return headroom;
}
@@ -2133,7 +2155,10 @@ public class ThermalManagerService extends SystemService {
Binder.getCallingUid(),
FrameworkStatsLog.THERMAL_HEADROOM_CALLED__API_STATUS__SUCCESS,
headroom, 0);
- Slog.d(TAG, "Headroom forecast in 0s served from cache: " + headroom);
+ if (DEBUG) {
+ Slog.d(TAG,
+ "Headroom forecast in 0s served from cache: " + headroom);
+ }
return headroom;
}
// Don't try to forecast, just use the latest one we have
@@ -2182,7 +2207,9 @@ public class ThermalManagerService extends SystemService {
getForecast(DEFAULT_FORECAST_SECONDS),
DEFAULT_FORECAST_SECONDS,
Arrays.copyOf(mHeadroomThresholds, mHeadroomThresholds.length));
- Slog.d(TAG, "New headroom callback data: " + data);
+ if (DEBUG) {
+ Slog.d(TAG, "New headroom callback data: " + data);
+ }
return data;
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
index f90da644c0ce..a9896e96a08f 100644
--- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
@@ -272,15 +272,6 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat
mHandler.removeMessages(SYNC_WAKELOCK_CHANGE);
}
- @Override
- public void scheduleSyncDueToBatteryLevelChange(long delayMillis) {
- synchronized (BatteryExternalStatsWorker.this) {
- scheduleDelayedSyncLocked(SYNC_BATTERY_LEVEL_CHANGE,
- () -> scheduleSync("battery-level", UPDATE_ALL),
- delayMillis);
- }
- }
-
@GuardedBy("this")
private void cancelSyncDueToBatteryLevelChangeLocked() {
mHandler.removeMessages(SYNC_BATTERY_LEVEL_CHANGE);
diff --git a/services/core/java/com/android/server/power/stats/BatteryHistoryStepDetailsProvider.java b/services/core/java/com/android/server/power/stats/BatteryHistoryStepDetailsProvider.java
new file mode 100644
index 000000000000..cd7612523b3e
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/BatteryHistoryStepDetailsProvider.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import android.hardware.power.stats.PowerEntity;
+import android.hardware.power.stats.State;
+import android.hardware.power.stats.StateResidency;
+import android.hardware.power.stats.StateResidencyResult;
+import android.os.BatteryStats;
+import android.power.PowerStatsInternal;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.server.LocalServices;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+class BatteryHistoryStepDetailsProvider {
+ public static final String TAG = "BatteryHistoryStepDetails";
+ private static final boolean DEBUG = false;
+
+ private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000;
+ private static final int MAX_LOW_POWER_STATS_SIZE = 32768;
+
+ private final BatteryStatsImpl mBatteryStats;
+
+ private final BatteryStats.HistoryStepDetails mDetails = new BatteryStats.HistoryStepDetails();
+
+ private boolean mHasHistoryStepDetails;
+
+ /**
+ * Total time (in milliseconds) spent executing in user code.
+ */
+ private long mLastStepCpuUserTimeMs;
+ private long mCurStepCpuUserTimeMs;
+ /**
+ * Total time (in milliseconds) spent executing in kernel code.
+ */
+ private long mLastStepCpuSystemTimeMs;
+ private long mCurStepCpuSystemTimeMs;
+ /**
+ * Times from /proc/stat (but measured in milliseconds).
+ */
+ private long mLastStepStatUserTimeMs;
+ private long mLastStepStatSystemTimeMs;
+ private long mLastStepStatIOWaitTimeMs;
+ private long mLastStepStatIrqTimeMs;
+ private long mLastStepStatSoftIrqTimeMs;
+ private long mLastStepStatIdleTimeMs;
+ private long mCurStepStatUserTimeMs;
+ private long mCurStepStatSystemTimeMs;
+ private long mCurStepStatIOWaitTimeMs;
+ private long mCurStepStatIrqTimeMs;
+ private long mCurStepStatSoftIrqTimeMs;
+ private long mCurStepStatIdleTimeMs;
+
+ private PowerStatsInternal mPowerStatsInternal;
+ private final Map<Integer, String> mEntityNames = new HashMap<>();
+ private final Map<Integer, Map<Integer, String>> mStateNames = new HashMap<>();
+
+ BatteryHistoryStepDetailsProvider(BatteryStatsImpl batteryStats) {
+ mBatteryStats = batteryStats;
+ }
+
+ void onSystemReady() {
+ mPowerStatsInternal = LocalServices.getService(PowerStatsInternal.class);
+ if (mPowerStatsInternal != null) {
+ populatePowerEntityMaps();
+ }
+ }
+
+ void requestUpdate() {
+ mBatteryStats.mHandler.post(this::update);
+ }
+
+ void update() {
+ mHasHistoryStepDetails = false;
+ mBatteryStats.updateCpuDetails();
+ calculateHistoryStepDetails();
+ updateStateResidency();
+ mBatteryStats.getHistory().recordHistoryStepDetails(mDetails,
+ mBatteryStats.mClock.elapsedRealtime(),
+ mBatteryStats.mClock.uptimeMillis());
+ }
+
+ private void calculateHistoryStepDetails() {
+ if (!mHasHistoryStepDetails) {
+ return;
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTimeMs + " sys="
+ + mLastStepStatSystemTimeMs + " io=" + mLastStepStatIOWaitTimeMs
+ + " irq=" + mLastStepStatIrqTimeMs + " sirq="
+ + mLastStepStatSoftIrqTimeMs + " idle=" + mLastStepStatIdleTimeMs);
+ Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTimeMs + " sys="
+ + mCurStepStatSystemTimeMs + " io=" + mCurStepStatIOWaitTimeMs
+ + " irq=" + mCurStepStatIrqTimeMs + " sirq="
+ + mCurStepStatSoftIrqTimeMs + " idle=" + mCurStepStatIdleTimeMs);
+ }
+ mDetails.userTime = (int) (mCurStepCpuUserTimeMs - mLastStepCpuUserTimeMs);
+ mDetails.systemTime = (int) (mCurStepCpuSystemTimeMs - mLastStepCpuSystemTimeMs);
+ mDetails.statUserTime = (int) (mCurStepStatUserTimeMs - mLastStepStatUserTimeMs);
+ mDetails.statSystemTime =
+ (int) (mCurStepStatSystemTimeMs - mLastStepStatSystemTimeMs);
+ mDetails.statIOWaitTime =
+ (int) (mCurStepStatIOWaitTimeMs - mLastStepStatIOWaitTimeMs);
+ mDetails.statIrqTime = (int) (mCurStepStatIrqTimeMs - mLastStepStatIrqTimeMs);
+ mDetails.statSoftIrqTime =
+ (int) (mCurStepStatSoftIrqTimeMs - mLastStepStatSoftIrqTimeMs);
+ mDetails.statIdlTime = (int) (mCurStepStatIdleTimeMs - mLastStepStatIdleTimeMs);
+ mDetails.appCpuUid1 = mDetails.appCpuUid2 = mDetails.appCpuUid3 = -1;
+ mDetails.appCpuUTime1 = mDetails.appCpuUTime2 = mDetails.appCpuUTime3 = 0;
+ mDetails.appCpuSTime1 = mDetails.appCpuSTime2 = mDetails.appCpuSTime3 = 0;
+ SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
+ final int uidCount = uidStats.size();
+ for (int i = 0; i < uidCount; i++) {
+ final BatteryStatsImpl.Uid uid = (BatteryStatsImpl.Uid) uidStats.valueAt(i);
+ final int totalUTimeMs =
+ (int) (uid.mCurStepUserTimeMs - uid.mLastStepUserTimeMs);
+ final int totalSTimeMs =
+ (int) (uid.mCurStepSystemTimeMs - uid.mLastStepSystemTimeMs);
+ final int totalTimeMs = totalUTimeMs + totalSTimeMs;
+ uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs;
+ uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs;
+ if (totalTimeMs <= (mDetails.appCpuUTime3 + mDetails.appCpuSTime3)) {
+ continue;
+ }
+ if (totalTimeMs <= (mDetails.appCpuUTime2 + mDetails.appCpuSTime2)) {
+ mDetails.appCpuUid3 = uid.mUid;
+ mDetails.appCpuUTime3 = totalUTimeMs;
+ mDetails.appCpuSTime3 = totalSTimeMs;
+ } else {
+ mDetails.appCpuUid3 = mDetails.appCpuUid2;
+ mDetails.appCpuUTime3 = mDetails.appCpuUTime2;
+ mDetails.appCpuSTime3 = mDetails.appCpuSTime2;
+ if (totalTimeMs <= (mDetails.appCpuUTime1 + mDetails.appCpuSTime1)) {
+ mDetails.appCpuUid2 = uid.mUid;
+ mDetails.appCpuUTime2 = totalUTimeMs;
+ mDetails.appCpuSTime2 = totalSTimeMs;
+ } else {
+ mDetails.appCpuUid2 = mDetails.appCpuUid1;
+ mDetails.appCpuUTime2 = mDetails.appCpuUTime1;
+ mDetails.appCpuSTime2 = mDetails.appCpuSTime1;
+ mDetails.appCpuUid1 = uid.mUid;
+ mDetails.appCpuUTime1 = totalUTimeMs;
+ mDetails.appCpuSTime1 = totalSTimeMs;
+ }
+ }
+ }
+ mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs;
+ mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs;
+ mLastStepStatUserTimeMs = mCurStepStatUserTimeMs;
+ mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs;
+ mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs;
+ mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs;
+ mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs;
+ mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
+ }
+
+ public void addCpuStats(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs,
+ int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs,
+ int statSoftIrqTimeMs, int statIdleTimeMs) {
+ if (DEBUG) {
+ Slog.d(TAG, "Adding cpu: tuser=" + totalUTimeMs + " tsys=" + totalSTimeMs
+ + " user=" + statUserTimeMs + " sys=" + statSystemTimeMs
+ + " io=" + statIOWaitTimeMs + " irq=" + statIrqTimeMs
+ + " sirq=" + statSoftIrqTimeMs + " idle=" + statIdleTimeMs);
+ }
+ mCurStepCpuUserTimeMs += totalUTimeMs;
+ mCurStepCpuSystemTimeMs += totalSTimeMs;
+ mCurStepStatUserTimeMs += statUserTimeMs;
+ mCurStepStatSystemTimeMs += statSystemTimeMs;
+ mCurStepStatIOWaitTimeMs += statIOWaitTimeMs;
+ mCurStepStatIrqTimeMs += statIrqTimeMs;
+ mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs;
+ mCurStepStatIdleTimeMs += statIdleTimeMs;
+ }
+
+ public void finishAddingCpuLocked() {
+ mHasHistoryStepDetails = true;
+ }
+
+ public void reset() {
+ mHasHistoryStepDetails = false;
+ mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs = 0;
+ mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs = 0;
+ mLastStepStatUserTimeMs = mCurStepStatUserTimeMs = 0;
+ mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs = 0;
+ mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs = 0;
+ mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs = 0;
+ mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs = 0;
+ mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs = 0;
+ }
+
+ private void updateStateResidency() {
+ mDetails.statSubsystemPowerState = null;
+
+ if (mPowerStatsInternal == null || mEntityNames.isEmpty() || mStateNames.isEmpty()) {
+ return;
+ }
+
+ final StateResidencyResult[] results;
+ try {
+ results = mPowerStatsInternal.getStateResidencyAsync(new int[0])
+ .get(POWER_STATS_QUERY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to getStateResidencyAsync", e);
+ return;
+ }
+
+ if (results == null || results.length == 0) {
+ return;
+ }
+
+ StringBuilder builder = new StringBuilder("SubsystemPowerState");
+ for (int i = 0; i < results.length; i++) {
+ final StateResidencyResult result = results[i];
+ int length = builder.length();
+ builder.append(" subsystem_").append(i);
+ builder.append(" name=").append(mEntityNames.get(result.id));
+
+ for (int j = 0; j < result.stateResidencyData.length; j++) {
+ final StateResidency stateResidency = result.stateResidencyData[j];
+ builder.append(" state_").append(j);
+ builder.append(" name=").append(mStateNames.get(result.id).get(
+ stateResidency.id));
+ builder.append(" time=").append(stateResidency.totalTimeInStateMs);
+ builder.append(" count=").append(stateResidency.totalStateEntryCount);
+ builder.append(" last entry=").append(stateResidency.lastEntryTimestampMs);
+ }
+
+ if (builder.length() > MAX_LOW_POWER_STATS_SIZE) {
+ Slog.e(TAG, "updateStateResidency: buffer not enough");
+ builder.setLength(length);
+ break;
+ }
+ }
+
+ mDetails.statSubsystemPowerState = builder.toString();
+ }
+
+ private void populatePowerEntityMaps() {
+ PowerEntity[] entities = mPowerStatsInternal.getPowerEntityInfo();
+ if (entities == null) {
+ return;
+ }
+
+ for (final PowerEntity entity : entities) {
+ Map<Integer, String> states = new HashMap<>();
+ for (int j = 0; j < entity.states.length; j++) {
+ final State state = entity.states[j];
+ states.put(state.id, state.name);
+ }
+
+ mEntityNames.put(entity.id, entity.name);
+ mStateNames.put(entity.id, states);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 2cf6b7efcb48..0af50805d756 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -117,7 +117,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsHistory;
-import com.android.internal.os.BatteryStatsHistory.HistoryStepDetailsCalculator;
import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.internal.os.BinderCallsStats;
import com.android.internal.os.BinderTransactionNameResolver;
@@ -653,7 +652,6 @@ public class BatteryStatsImpl extends BatteryStats {
public interface PlatformIdleStateCallback {
public void fillLowPowerStats(RpmStats rpmStats);
- public String getSubsystemLowPowerStats();
}
/** interface to update rail information for power monitor */
@@ -1065,10 +1063,6 @@ public class BatteryStatsImpl extends BatteryStats {
*/
void cancelCpuSyncDueToWakelockChange();
- /**
- * Schedules a sync caused by the battery level change
- */
- void scheduleSyncDueToBatteryLevelChange(long delayMillis);
/** Schedule removal of UIDs corresponding to a removed user */
void scheduleCleanupDueToRemovedUser(int userId);
/** Schedule a sync because of a process state change */
@@ -1131,8 +1125,8 @@ public class BatteryStatsImpl extends BatteryStats {
private boolean mShuttingDown;
private final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
- private final HistoryStepDetailsCalculatorImpl mStepDetailsCalculator =
- new HistoryStepDetailsCalculatorImpl();
+ private final BatteryHistoryStepDetailsProvider mStepDetailsProvider =
+ new BatteryHistoryStepDetailsProvider(this);
private boolean mHaveBatteryLevel = false;
private boolean mBatteryPluggedIn;
@@ -4553,184 +4547,6 @@ public class BatteryStatsImpl extends BatteryStats {
return kmt;
}
- private class HistoryStepDetailsCalculatorImpl implements HistoryStepDetailsCalculator {
- private final HistoryStepDetails mDetails = new HistoryStepDetails();
-
- private boolean mHasHistoryStepDetails;
- private boolean mUpdateRequested;
-
- /**
- * Total time (in milliseconds) spent executing in user code.
- */
- private long mLastStepCpuUserTimeMs;
- private long mCurStepCpuUserTimeMs;
- /**
- * Total time (in milliseconds) spent executing in kernel code.
- */
- private long mLastStepCpuSystemTimeMs;
- private long mCurStepCpuSystemTimeMs;
- /**
- * Times from /proc/stat (but measured in milliseconds).
- */
- private long mLastStepStatUserTimeMs;
- private long mLastStepStatSystemTimeMs;
- private long mLastStepStatIOWaitTimeMs;
- private long mLastStepStatIrqTimeMs;
- private long mLastStepStatSoftIrqTimeMs;
- private long mLastStepStatIdleTimeMs;
- private long mCurStepStatUserTimeMs;
- private long mCurStepStatSystemTimeMs;
- private long mCurStepStatIOWaitTimeMs;
- private long mCurStepStatIrqTimeMs;
- private long mCurStepStatSoftIrqTimeMs;
- private long mCurStepStatIdleTimeMs;
-
- @Override
- public HistoryStepDetails getHistoryStepDetails() {
- if (!mUpdateRequested) {
- mUpdateRequested = true;
- // Perform a CPU update right after we do this collection, so we have started
- // collecting good data for the next step.
- requestImmediateCpuUpdate();
-
- if (mPlatformIdleStateCallback != null) {
- mDetails.statSubsystemPowerState =
- mPlatformIdleStateCallback.getSubsystemLowPowerStats();
- if (DEBUG) {
- Slog.i(TAG,
- "WRITE SubsystemPowerState:" + mDetails.statSubsystemPowerState);
- }
- }
- }
-
- if (!mHasHistoryStepDetails) {
- // We are not generating a delta, so all we need to do is reset the stats
- // we will later be doing a delta from.
- final int uidCount = mUidStats.size();
- for (int i = 0; i < uidCount; i++) {
- final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
- uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs;
- uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs;
- }
- mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs;
- mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs;
- mLastStepStatUserTimeMs = mCurStepStatUserTimeMs;
- mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs;
- mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs;
- mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs;
- mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs;
- mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
- return null;
- } else {
- if (DEBUG) {
- Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTimeMs + " sys="
- + mLastStepStatSystemTimeMs + " io=" + mLastStepStatIOWaitTimeMs
- + " irq=" + mLastStepStatIrqTimeMs + " sirq="
- + mLastStepStatSoftIrqTimeMs + " idle=" + mLastStepStatIdleTimeMs);
- Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTimeMs + " sys="
- + mCurStepStatSystemTimeMs + " io=" + mCurStepStatIOWaitTimeMs
- + " irq=" + mCurStepStatIrqTimeMs + " sirq="
- + mCurStepStatSoftIrqTimeMs + " idle=" + mCurStepStatIdleTimeMs);
- }
- mDetails.userTime = (int) (mCurStepCpuUserTimeMs - mLastStepCpuUserTimeMs);
- mDetails.systemTime = (int) (mCurStepCpuSystemTimeMs - mLastStepCpuSystemTimeMs);
- mDetails.statUserTime = (int) (mCurStepStatUserTimeMs - mLastStepStatUserTimeMs);
- mDetails.statSystemTime =
- (int) (mCurStepStatSystemTimeMs - mLastStepStatSystemTimeMs);
- mDetails.statIOWaitTime =
- (int) (mCurStepStatIOWaitTimeMs - mLastStepStatIOWaitTimeMs);
- mDetails.statIrqTime = (int) (mCurStepStatIrqTimeMs - mLastStepStatIrqTimeMs);
- mDetails.statSoftIrqTime =
- (int) (mCurStepStatSoftIrqTimeMs - mLastStepStatSoftIrqTimeMs);
- mDetails.statIdlTime = (int) (mCurStepStatIdleTimeMs - mLastStepStatIdleTimeMs);
- mDetails.appCpuUid1 = mDetails.appCpuUid2 = mDetails.appCpuUid3 = -1;
- mDetails.appCpuUTime1 = mDetails.appCpuUTime2 = mDetails.appCpuUTime3 = 0;
- mDetails.appCpuSTime1 = mDetails.appCpuSTime2 = mDetails.appCpuSTime3 = 0;
- final int uidCount = mUidStats.size();
- for (int i = 0; i < uidCount; i++) {
- final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
- final int totalUTimeMs =
- (int) (uid.mCurStepUserTimeMs - uid.mLastStepUserTimeMs);
- final int totalSTimeMs =
- (int) (uid.mCurStepSystemTimeMs - uid.mLastStepSystemTimeMs);
- final int totalTimeMs = totalUTimeMs + totalSTimeMs;
- uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs;
- uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs;
- if (totalTimeMs <= (mDetails.appCpuUTime3 + mDetails.appCpuSTime3)) {
- continue;
- }
- if (totalTimeMs <= (mDetails.appCpuUTime2 + mDetails.appCpuSTime2)) {
- mDetails.appCpuUid3 = uid.mUid;
- mDetails.appCpuUTime3 = totalUTimeMs;
- mDetails.appCpuSTime3 = totalSTimeMs;
- } else {
- mDetails.appCpuUid3 = mDetails.appCpuUid2;
- mDetails.appCpuUTime3 = mDetails.appCpuUTime2;
- mDetails.appCpuSTime3 = mDetails.appCpuSTime2;
- if (totalTimeMs <= (mDetails.appCpuUTime1 + mDetails.appCpuSTime1)) {
- mDetails.appCpuUid2 = uid.mUid;
- mDetails.appCpuUTime2 = totalUTimeMs;
- mDetails.appCpuSTime2 = totalSTimeMs;
- } else {
- mDetails.appCpuUid2 = mDetails.appCpuUid1;
- mDetails.appCpuUTime2 = mDetails.appCpuUTime1;
- mDetails.appCpuSTime2 = mDetails.appCpuSTime1;
- mDetails.appCpuUid1 = uid.mUid;
- mDetails.appCpuUTime1 = totalUTimeMs;
- mDetails.appCpuSTime1 = totalSTimeMs;
- }
- }
- }
- mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs;
- mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs;
- mLastStepStatUserTimeMs = mCurStepStatUserTimeMs;
- mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs;
- mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs;
- mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs;
- mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs;
- mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
- return mDetails;
- }
- }
-
- public void addCpuStats(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs,
- int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs,
- int statSoftIrqTimeMs, int statIdleTimeMs) {
- if (DEBUG) {
- Slog.d(TAG, "Adding cpu: tuser=" + totalUTimeMs + " tsys=" + totalSTimeMs
- + " user=" + statUserTimeMs + " sys=" + statSystemTimeMs
- + " io=" + statIOWaitTimeMs + " irq=" + statIrqTimeMs
- + " sirq=" + statSoftIrqTimeMs + " idle=" + statIdleTimeMs);
- }
- mCurStepCpuUserTimeMs += totalUTimeMs;
- mCurStepCpuSystemTimeMs += totalSTimeMs;
- mCurStepStatUserTimeMs += statUserTimeMs;
- mCurStepStatSystemTimeMs += statSystemTimeMs;
- mCurStepStatIOWaitTimeMs += statIOWaitTimeMs;
- mCurStepStatIrqTimeMs += statIrqTimeMs;
- mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs;
- mCurStepStatIdleTimeMs += statIdleTimeMs;
- }
-
- public void finishAddingCpuLocked() {
- mHasHistoryStepDetails = true;
- mUpdateRequested = false;
- }
-
- @Override
- public void clear() {
- mHasHistoryStepDetails = false;
- mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs = 0;
- mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs = 0;
- mLastStepStatUserTimeMs = mCurStepStatUserTimeMs = 0;
- mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs = 0;
- mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs = 0;
- mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs = 0;
- mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs = 0;
- mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs = 0;
- }
- }
-
@GuardedBy("this")
@Override
public void commitCurrentHistoryBatchLocked() {
@@ -5557,7 +5373,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void addCpuStatsLocked(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs,
int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs,
int statSoftIrqTimeMs, int statIdleTimeMs) {
- mStepDetailsCalculator.addCpuStats(totalUTimeMs, totalSTimeMs, statUserTimeMs,
+ mStepDetailsProvider.addCpuStats(totalUTimeMs, totalSTimeMs, statUserTimeMs,
statSystemTimeMs, statIOWaitTimeMs, statIrqTimeMs,
statSoftIrqTimeMs, statIdleTimeMs);
}
@@ -5567,7 +5383,7 @@ public class BatteryStatsImpl extends BatteryStats {
*/
@GuardedBy("this")
public void finishAddingCpuStatsLocked() {
- mStepDetailsCalculator.finishAddingCpuLocked();
+ mStepDetailsProvider.finishAddingCpuLocked();
}
public void noteProcessDiedLocked(int uid, int pid) {
@@ -11515,8 +11331,7 @@ public class BatteryStatsImpl extends BatteryStats {
mBatteryHistoryDirectory = batteryHistoryDirectory;
mHistory = new BatteryStatsHistory(null /* historyBuffer */, mConstants.MAX_HISTORY_BUFFER,
- mBatteryHistoryDirectory, mStepDetailsCalculator, mClock, mMonotonicClock,
- traceDelegate, eventLogger);
+ mBatteryHistoryDirectory, mClock, mMonotonicClock, traceDelegate, eventLogger);
mCpuPowerStatsCollector = new CpuPowerStatsCollector(mPowerStatsCollectorInjector);
mCpuPowerStatsCollector.addConsumer(this::recordPowerStats);
@@ -11723,6 +11538,12 @@ public class BatteryStatsImpl extends BatteryStats {
mCallback = cb;
}
+ void updateCpuDetails() {
+ if (mCallback != null) {
+ mCallback.batteryNeedsCpuUpdate();
+ }
+ }
+
public void setRadioScanningTimeoutLocked(long timeoutUs) {
if (mPhoneSignalScanningTimer != null) {
mPhoneSignalScanningTimer.setTimeout(timeoutUs);
@@ -12343,6 +12164,8 @@ public class BatteryStatsImpl extends BatteryStats {
mWakeupReasonStats.clear();
}
+ mStepDetailsProvider.reset();
+
if (mTmpRailStats != null) {
mTmpRailStats.reset();
}
@@ -14948,6 +14771,8 @@ public class BatteryStatsImpl extends BatteryStats {
mCpuUidFreqTimeReader.onSystemReady();
}
+ mStepDetailsProvider.onSystemReady();
+
mPowerStatsCollectorInjector.setContext(context);
mCpuPowerStatsCollector.setEnabled(
@@ -15270,6 +15095,7 @@ public class BatteryStatsImpl extends BatteryStats {
reportChangesToStatsLog(status, plugType, level);
+ boolean requestStepDetails = false;
final boolean onBattery = isOnBattery(plugType, status);
if (!mHaveBatteryLevel) {
mHaveBatteryLevel = true;
@@ -15289,6 +15115,7 @@ public class BatteryStatsImpl extends BatteryStats {
mMaxChargeStepLevel = mMinDischargeStepLevel =
mLastChargeStepLevel = mLastDischargeStepLevel = level;
+ requestStepDetails = true;
} else if (mBatteryLevel != level || mOnBattery != onBattery) {
recordDailyStatsIfNeededLocked(level >= 100 && onBattery, currentTimeMs);
}
@@ -15332,16 +15159,13 @@ public class BatteryStatsImpl extends BatteryStats {
}
mBatteryChargeUah = chargeUah;
setOnBatteryLocked(elapsedRealtimeMs, uptimeMs, onBattery, oldStatus, level, chargeUah);
+ requestStepDetails = true;
} else {
boolean changed = false;
if (mBatteryLevel != level) {
mBatteryLevel = level;
changed = true;
-
- // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
- // which will pull external stats.
- mExternalSync.scheduleSyncDueToBatteryLevelChange(
- mConstants.BATTERY_LEVEL_COLLECTION_DELAY_MS);
+ requestStepDetails = true;
}
if (mBatteryStatus != status) {
mBatteryStatus = status;
@@ -15462,6 +15286,9 @@ public class BatteryStatsImpl extends BatteryStats {
if (mAccumulateBatteryUsageStats) {
mBatteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(this, mHandler);
}
+ if (requestStepDetails) {
+ mStepDetailsProvider.requestUpdate();
+ }
}
public static boolean isOnBattery(int plugType, int status) {
diff --git a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
index 8c3b7c606f04..3ece07c84080 100644
--- a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
+++ b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
@@ -17,6 +17,7 @@
package com.android.server.security.advancedprotection;
import static android.provider.Settings.Secure.ADVANCED_PROTECTION_MODE;
+import static android.provider.Settings.Secure.AAPM_USB_DATA_PROTECTION;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.Manifest;
@@ -69,6 +70,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/** @hide */
public class AdvancedProtectionService extends IAdvancedProtectionService.Stub {
@@ -129,7 +131,10 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
Slog.e(TAG, "Failed to initialize DisallowCellular2g", e);
}
}
- if (android.security.Flags.aapmFeatureUsbDataProtection()) {
+ if (android.security.Flags.aapmFeatureUsbDataProtection()
+ // Usb data protection is enabled by default
+ && mStore.retrieveInt(AAPM_USB_DATA_PROTECTION, AdvancedProtectionStore.ON)
+ == AdvancedProtectionStore.ON) {
try {
mHooks.add(new UsbDataAdvancedProtectionHook(mContext, enabled));
} catch (Exception e) {
@@ -183,7 +188,7 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
// Without permission check
private boolean isAdvancedProtectionEnabledInternal() {
- return mStore.retrieve();
+ return mStore.retrieveAdvancedProtectionModeEnabled();
}
@Override
@@ -217,7 +222,7 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
try {
synchronized (mCallbacks) {
if (enabled != isAdvancedProtectionEnabledInternal()) {
- mStore.store(enabled);
+ mStore.storeAdvancedProtectionModeEnabled(enabled);
sendModeChanged(enabled);
logAdvancedProtectionEnabled(enabled);
}
@@ -227,6 +232,34 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
}
}
+ public void setUsbDataProtectionEnabled(boolean enabled) {
+ int value = enabled ? AdvancedProtectionStore.ON
+ : AdvancedProtectionStore.OFF;
+ setAdvancedProtectionSubSettingInt(AAPM_USB_DATA_PROTECTION, value);
+ }
+
+ private void setAdvancedProtectionSubSettingInt(String key, int value) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mCallbacks) {
+ mStore.storeInt(key, value);
+ Slog.i(TAG, "Advanced protection: subsetting" + key + " is " + value);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ public boolean isUsbDataProtectionEnabled() {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mStore.retrieveInt(AAPM_USB_DATA_PROTECTION, AdvancedProtectionStore.ON)
+ == AdvancedProtectionStore.ON;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
@Override
@EnforcePermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
public void logDialogShown(@FeatureId int featureId, @SupportDialogType int type,
@@ -419,8 +452,8 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
@VisibleForTesting
static class AdvancedProtectionStore {
private final Context mContext;
- private static final int APM_ON = 1;
- private static final int APM_OFF = 0;
+ static final int ON = 1;
+ static final int OFF = 0;
private final UserManagerInternal mUserManager;
AdvancedProtectionStore(@NonNull Context context) {
@@ -428,15 +461,26 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
mUserManager = LocalServices.getService(UserManagerInternal.class);
}
- void store(boolean enabled) {
+ void storeAdvancedProtectionModeEnabled(boolean enabled) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ ADVANCED_PROTECTION_MODE, enabled ? ON : OFF,
+ mUserManager.getMainUserId());
+ }
+
+ boolean retrieveAdvancedProtectionModeEnabled() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ ADVANCED_PROTECTION_MODE, OFF, mUserManager.getMainUserId()) == ON;
+ }
+
+ void storeInt(String key, int value) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- ADVANCED_PROTECTION_MODE, enabled ? APM_ON : APM_OFF,
+ key, value,
mUserManager.getMainUserId());
}
- boolean retrieve() {
+ int retrieveInt(String key, int defaultValue) {
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- ADVANCED_PROTECTION_MODE, APM_OFF, mUserManager.getMainUserId()) == APM_ON;
+ key, defaultValue, mUserManager.getMainUserId());
}
}
diff --git a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionShellCommand.java b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionShellCommand.java
index 42505ad2de3f..ae17a459010b 100644
--- a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionShellCommand.java
+++ b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionShellCommand.java
@@ -45,6 +45,10 @@ class AdvancedProtectionShellCommand extends ShellCommand {
return setProtectionEnabled();
case "is-protection-enabled":
return isProtectionEnabled(pw);
+ case "set-usb-data-protection-enabled":
+ return setUsbDataProtectedEnabled();
+ case "is-usb-data-protection-enabled":
+ return isUsbDataProtectedEnabled(pw);
}
} catch (RemoteException e) {
pw.println("Remote exception: " + e);
@@ -64,6 +68,10 @@ class AdvancedProtectionShellCommand extends ShellCommand {
pw.println(" Print this help text.");
pw.println(" set-protection-enabled [true|false]");
pw.println(" is-protection-enabled");
+ if(android.security.Flags.aapmFeatureUsbDataProtection()) {
+ pw.println(" set-usb-data-protection-enabled [true|false]");
+ pw.println(" is-usb-data-protection-enabled");
+ }
}
@SuppressLint("AndroidFrameworkRequiresPermission")
@@ -79,4 +87,22 @@ class AdvancedProtectionShellCommand extends ShellCommand {
pw.println(protectionMode);
return 0;
}
+
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ private int setUsbDataProtectedEnabled() throws RemoteException {
+ if(android.security.Flags.aapmFeatureUsbDataProtection()) {
+ String protectionMode = getNextArgRequired();
+ mService.setUsbDataProtectionEnabled(Boolean.parseBoolean(protectionMode));
+ }
+ return 0;
+ }
+
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ private int isUsbDataProtectedEnabled(@NonNull PrintWriter pw) throws RemoteException {
+ if(android.security.Flags.aapmFeatureUsbDataProtection()) {
+ boolean protectionMode = mService.isUsbDataProtectionEnabled();
+ pw.println(protectionMode);
+ }
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
index 70fc6bace868..ee173a2a6a35 100644
--- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
+++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
@@ -131,6 +131,10 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer,
mCache = cache;
}
+ void setSnapshotReleaser(Consumer<HardwareBuffer> releaser) {
+ mCache.setSafeSnapshotReleaser(releaser);
+ }
+
void setSnapshotEnabled(boolean enabled) {
mSnapshotEnabled = enabled;
}
diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotCache.java b/services/core/java/com/android/server/wm/ActivitySnapshotCache.java
index ed07afd2eab5..a0e537231071 100644
--- a/services/core/java/com/android/server/wm/ActivitySnapshotCache.java
+++ b/services/core/java/com/android/server/wm/ActivitySnapshotCache.java
@@ -31,6 +31,7 @@ class ActivitySnapshotCache extends SnapshotCache<ActivityRecord> {
void putSnapshot(ActivityRecord ar, TaskSnapshot snapshot) {
final int hasCode = System.identityHashCode(ar);
snapshot.addReference(TaskSnapshot.REFERENCE_CACHE);
+ snapshot.setSafeRelease(mSafeSnapshotReleaser);
synchronized (mLock) {
final CacheEntry entry = mRunningCache.get(hasCode);
if (entry != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 21b730e13585..7123a7c1160f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -803,4 +803,10 @@ public abstract class ActivityTaskManagerInternal {
/** Returns whether assist data is allowed. */
public abstract boolean isAssistDataAllowed();
+
+ /**
+ * Delegate back gesture request from shell.
+ * Returns true if the back gesture request was successful, false otherwise.
+ */
+ public abstract boolean requestBackGesture();
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 46d24b0d3201..a0c38dd82037 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1892,6 +1892,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
+ @Override
+ public void registerBackGestureDelegate(RemoteCallback requestObserver) {
+ mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
+ "registerBackGestureDelegate()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ mBackNavigationController.registerBackGestureDelegate(requestObserver);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
/**
* Public API to check if the client is allowed to start an activity on specified display.
*
@@ -7571,6 +7583,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public boolean isAssistDataAllowed() {
return ActivityTaskManagerService.this.isAssistDataAllowed();
}
+
+ @Override
+ public boolean requestBackGesture() {
+ return mBackNavigationController.requestBackGesture();
+ }
}
/** Cache the return value for {@link #isPip2ExperimentEnabled()} */
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index dfe323c43abb..819e4abaa9d3 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -85,6 +85,7 @@ class BackNavigationController {
private boolean mShowWallpaper;
private Runnable mPendingAnimation;
private final NavigationMonitor mNavigationMonitor = new NavigationMonitor();
+ private RemoteCallback mGestureRequest;
private AnimationHandler mAnimationHandler;
@@ -113,6 +114,35 @@ class BackNavigationController {
mNavigationMonitor.onEmbeddedWindowGestureTransferred(host);
}
+ void registerBackGestureDelegate(@NonNull RemoteCallback requestObserver) {
+ if (!sPredictBackEnable) {
+ return;
+ }
+ synchronized (mWindowManagerService.mGlobalLock) {
+ mGestureRequest = requestObserver;
+ try {
+ requestObserver.getInterface().asBinder().linkToDeath(() -> {
+ synchronized (mWindowManagerService.mGlobalLock) {
+ mGestureRequest = null;
+ }
+ }, 0 /* flags */);
+ } catch (RemoteException r) {
+ Slog.e(TAG, "Failed to link to death");
+ mGestureRequest = null;
+ }
+ }
+ }
+
+ boolean requestBackGesture() {
+ synchronized (mWindowManagerService.mGlobalLock) {
+ if (mGestureRequest == null) {
+ return false;
+ }
+ mGestureRequest.sendResult(null);
+ return true;
+ }
+ }
+
/**
* Set up the necessary leashes and build a {@link BackNavigationInfo} instance for an upcoming
* back gesture animation.
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 313b77ed4b20..f9eb0574d87c 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -137,6 +137,7 @@ import com.android.internal.view.AppearanceRegion;
import com.android.internal.widget.PointerLocationView;
import com.android.server.LocalServices;
import com.android.server.UiThread;
+import com.android.server.notification.NotificationManagerInternal;
import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -1925,6 +1926,11 @@ public class DisplayPolicy {
if (wpMgr != null) {
wpMgr.onDisplayRemoveSystemDecorations(displayId);
}
+ final NotificationManagerInternal notificationManager =
+ LocalServices.getService(NotificationManagerInternal.class);
+ if (notificationManager != null) {
+ notificationManager.onDisplayRemoveSystemDecorations(displayId);
+ }
});
}
diff --git a/services/core/java/com/android/server/wm/SnapshotCache.java b/services/core/java/com/android/server/wm/SnapshotCache.java
index 9812a88bfa5a..685bd3b355ed 100644
--- a/services/core/java/com/android/server/wm/SnapshotCache.java
+++ b/services/core/java/com/android/server/wm/SnapshotCache.java
@@ -16,12 +16,14 @@
package com.android.server.wm;
import android.annotation.Nullable;
+import android.hardware.HardwareBuffer;
import android.util.ArrayMap;
import android.window.TaskSnapshot;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* Base class for an app snapshot cache
@@ -38,12 +40,18 @@ abstract class SnapshotCache<TYPE extends WindowContainer> {
@GuardedBy("mLock")
protected final ArrayMap<Integer, CacheEntry> mRunningCache = new ArrayMap<>();
+ protected Consumer<HardwareBuffer> mSafeSnapshotReleaser;
+
SnapshotCache(String name) {
mName = name;
}
abstract void putSnapshot(TYPE window, TaskSnapshot snapshot);
+ void setSafeSnapshotReleaser(Consumer<HardwareBuffer> safeSnapshotReleaser) {
+ mSafeSnapshotReleaser = safeSnapshotReleaser;
+ }
+
void clearRunningCache() {
synchronized (mLock) {
mRunningCache.clear();
diff --git a/services/core/java/com/android/server/wm/SnapshotController.java b/services/core/java/com/android/server/wm/SnapshotController.java
index 3a7222ae6d51..48f0959214c1 100644
--- a/services/core/java/com/android/server/wm/SnapshotController.java
+++ b/services/core/java/com/android/server/wm/SnapshotController.java
@@ -26,13 +26,16 @@ import static android.view.WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import android.hardware.HardwareBuffer;
import android.os.Trace;
import android.util.ArrayMap;
import android.view.WindowManager;
import android.window.TaskSnapshot;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.function.Consumer;
/**
* Integrates common functionality from TaskSnapshotController and ActivitySnapshotController.
@@ -41,11 +44,30 @@ class SnapshotController {
private final SnapshotPersistQueue mSnapshotPersistQueue;
final TaskSnapshotController mTaskSnapshotController;
final ActivitySnapshotController mActivitySnapshotController;
+ private final WindowManagerService mService;
+ private final ArrayList<WeakReference<HardwareBuffer>> mObsoleteSnapshots = new ArrayList<>();
SnapshotController(WindowManagerService wms) {
+ mService = wms;
mSnapshotPersistQueue = new SnapshotPersistQueue();
mTaskSnapshotController = new TaskSnapshotController(wms, mSnapshotPersistQueue);
mActivitySnapshotController = new ActivitySnapshotController(wms, mSnapshotPersistQueue);
+ final Consumer<HardwareBuffer> releaser = hb -> {
+ mService.mH.post(() -> {
+ synchronized (mService.mGlobalLock) {
+ if (hb.isClosed()) {
+ return;
+ }
+ if (mService.mAtmService.getTransitionController().inTransition()) {
+ mObsoleteSnapshots.add(new WeakReference<>(hb));
+ } else {
+ hb.close();
+ }
+ }
+ });
+ };
+ mTaskSnapshotController.setSnapshotReleaser(releaser);
+ mActivitySnapshotController.setSnapshotReleaser(releaser);
}
void systemReady() {
@@ -168,6 +190,7 @@ class SnapshotController {
final boolean isTransitionClose = isTransitionClose(type);
if (!isTransitionOpen && !isTransitionClose && type < TRANSIT_FIRST_CUSTOM
|| (changeInfos.isEmpty())) {
+ closeObsoleteSnapshots();
return;
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "SnapshotController_analysis");
@@ -195,9 +218,22 @@ class SnapshotController {
}
}
}
+ closeObsoleteSnapshots();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
+ private void closeObsoleteSnapshots() {
+ if (mObsoleteSnapshots.isEmpty()) {
+ return;
+ }
+ for (int i = mObsoleteSnapshots.size() - 1; i >= 0; --i) {
+ final HardwareBuffer hb = mObsoleteSnapshots.remove(i).get();
+ if (hb != null && !hb.isClosed()) {
+ hb.close();
+ }
+ }
+ }
+
private static boolean isTransitionOpen(int type) {
return type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT
|| type == TRANSIT_PREPARE_BACK_NAVIGATION;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index cc957bd9ee42..1988f2630b6e 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -36,6 +36,7 @@ class TaskSnapshotCache extends SnapshotCache<Task> {
void putSnapshot(Task task, TaskSnapshot snapshot) {
synchronized (mLock) {
snapshot.addReference(TaskSnapshot.REFERENCE_CACHE);
+ snapshot.setSafeRelease(mSafeSnapshotReleaser);
final CacheEntry entry = mRunningCache.get(task.mTaskId);
if (entry != null) {
mAppIdMap.remove(entry.topApp);
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
index 026e72f117b4..d0226805224e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
@@ -26,15 +26,12 @@ import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUD
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_WIFI_SCAN;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
-import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
import static android.app.AppOpsManager.UID_STATE_TOP;
import static android.permission.flags.Flags.delayUidStateChangesFromCapabilityUpdates;
-import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -42,7 +39,6 @@ import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -64,7 +60,6 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.quality.Strictness;
import java.util.PriorityQueue;
@@ -94,7 +89,6 @@ public class AppOpsUidStateTrackerTest {
public void setUp() {
mSession = ExtendedMockito.mockitoSession()
.initMocks(this)
- .strictness(Strictness.LENIENT)
.startMocking();
mConstants.TOP_STATE_SETTLE_TIME = 10 * 1000L;
mConstants.FG_SERVICE_STATE_SETTLE_TIME = 5 * 1000L;
@@ -591,221 +585,6 @@ public class AppOpsUidStateTrackerTest {
}
@Test
- public void testUidStateChangedCallbackCachedToBackground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- ActivityManager.PROCESS_STATE_RECEIVER);
- }
-
- @Test
- public void testUidStateChangedCallbackCachedToForeground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- ActivityManager.PROCESS_STATE_BOUND_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackCachedToForegroundService() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
-
- @Test
- public void testUidStateChangedCallbackCachedToTop() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- ActivityManager.PROCESS_STATE_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToCached() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_RECEIVER,
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToForeground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_RECEIVER,
- ActivityManager.PROCESS_STATE_BOUND_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToForegroundService() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_RECEIVER,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToTop() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_RECEIVER,
- ActivityManager.PROCESS_STATE_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToCached() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_BOUND_TOP,
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToBackground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_BOUND_TOP,
- ActivityManager.PROCESS_STATE_RECEIVER);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToForegroundService() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_BOUND_TOP,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToTop() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_BOUND_TOP,
- ActivityManager.PROCESS_STATE_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToCached() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToBackground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- ActivityManager.PROCESS_STATE_RECEIVER);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToForeground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- ActivityManager.PROCESS_STATE_BOUND_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToTop() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- ActivityManager.PROCESS_STATE_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackTopToCached() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_TOP,
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
- }
-
- @Test
- public void testUidStateChangedCallbackTopToBackground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_TOP,
- ActivityManager.PROCESS_STATE_RECEIVER);
- }
-
- @Test
- public void testUidStateChangedCallbackTopToForeground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_TOP,
- ActivityManager.PROCESS_STATE_BOUND_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackTopToForegroundService() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_TOP,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
-
- @Test
- public void testUidStateChangedCallbackCachedToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .cachedState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .backgroundState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(false));
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .foregroundState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .foregroundServiceState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
- }
-
- @Test
- public void testUidStateChangedCallbackTopToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .topState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
- }
-
- @Test
public void testUidStateChangedBackgroundThenForegroundImmediately() {
procStateBuilder(UID)
.topState()
@@ -882,32 +661,6 @@ public class AppOpsUidStateTrackerTest {
assertEquals(UID_STATE_TOP, mIntf.getUidState(UID));
}
- public void testUidStateChangedCallback(int initialState, int finalState) {
- int initialUidState = processStateToUidState(initialState);
- int finalUidState = processStateToUidState(finalState);
- boolean foregroundChange = initialUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
- != finalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED;
- boolean finalUidStateIsBackgroundAndLessImportant =
- finalUidState > UID_STATE_MAX_LAST_NON_RESTRICTED
- && finalUidState > initialUidState;
-
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .setState(initialState)
- .update();
-
- procStateBuilder(UID)
- .setState(finalState)
- .update();
-
- if (finalUidStateIsBackgroundAndLessImportant) {
- mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1);
- }
-
- verify(cb, atLeastOnce())
- .onUidStateChanged(eq(UID), eq(finalUidState), eq(foregroundChange));
- }
private UidStateChangedCallback addUidStateChangeCallback() {
UidStateChangedCallback cb =
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTransitionCallbackTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTransitionCallbackTest.java
new file mode 100644
index 000000000000..60cdfee0834c
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTransitionCallbackTest.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appop;
+
+import static android.app.AppOpsManager.UID_STATE_CACHED;
+import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
+import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
+import static android.permission.flags.Flags.finishRunningOpsForKilledPackages;
+
+import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.internal.os.Clock;
+import com.android.server.appop.AppOpsUidStateTracker.UidStateChangedCallback;
+import com.android.server.appop.AppOpsUidStateTrackerImpl.DelayableExecutor;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.PriorityQueue;
+
+@RunWith(Parameterized.class)
+public class AppOpsUidStateTrackerTransitionCallbackTest {
+
+ private static final int UID = 10001;
+
+ private static final int STATE_TOP = ActivityManager.PROCESS_STATE_TOP;
+ private static final int STATE_FOREGROUND_SERVICE =
+ ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+ private static final int STATE_FOREGROUND = ActivityManager.PROCESS_STATE_BOUND_TOP;
+ private static final int STATE_BACKGROUND = ActivityManager.PROCESS_STATE_SERVICE;
+ private static final int STATE_CACHED = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+ private static final int STATE_NONEXISTENT = ActivityManager.PROCESS_STATE_NONEXISTENT;
+
+ private static final int[] STATES = {STATE_TOP, STATE_FOREGROUND_SERVICE, STATE_FOREGROUND,
+ STATE_BACKGROUND, STATE_CACHED, STATE_NONEXISTENT};
+ private static final String[] STATES_NAMES = {"TOP", "FOREGROUND_SERVICE", "FOREGROUND",
+ "BACKGROUND", "CACHED", "NONEXISTENT"};
+
+ @Mock
+ ActivityManagerInternal mAmi;
+
+ @Mock
+ AppOpsService.Constants mConstants;
+
+ AppOpsUidStateTrackerTestExecutor mExecutor = new AppOpsUidStateTrackerTestExecutor();
+
+ AppOpsUidStateTrackerTestClock mClock = new AppOpsUidStateTrackerTestClock(mExecutor);
+
+ AppOpsUidStateTracker mIntf;
+
+ StaticMockitoSession mSession;
+
+ private final int mInitialState;
+ private final int mMiddleState;
+ private final int mFinalState;
+
+ @Parameterized.Parameters(name = "{3} -> {4} -> {5}")
+ public static Collection<Object[]> getParameters() {
+ ArrayList<Object[]> parameters = new ArrayList<>();
+
+ for (int i = 0; i < STATES.length; i++) {
+ for (int j = 0; j < STATES.length; j++) {
+ for (int k = 0; k < STATES.length; k++) {
+ parameters
+ .add(new Object[]{STATES[i], STATES[j], STATES[k], STATES_NAMES[i],
+ STATES_NAMES[j], STATES_NAMES[k]});
+ }
+ }
+ }
+
+ return parameters;
+ }
+
+ public AppOpsUidStateTrackerTransitionCallbackTest(int initialState, int middleState,
+ int finalState, String ignoredInitialStateName, String ignoredMiddleStateName,
+ String ignoredFinalStateName) {
+ mInitialState = initialState;
+ mMiddleState = middleState;
+ mFinalState = finalState;
+ }
+
+ @Before
+ public void setUp() {
+ mSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .startMocking();
+ mConstants.TOP_STATE_SETTLE_TIME = 10 * 1000L;
+ mConstants.FG_SERVICE_STATE_SETTLE_TIME = 5 * 1000L;
+ mConstants.BG_STATE_SETTLE_TIME = 1 * 1000L;
+ mIntf = new AppOpsUidStateTrackerImpl(mAmi, mExecutor, mClock, mConstants,
+ Thread.currentThread());
+ }
+
+ @After
+ public void tearDown() {
+ mSession.finishMocking();
+ }
+
+ @Test
+ public void testUidStateChangedCallback() {
+ testUidStateTransition(mInitialState, mMiddleState, true);
+ testUidStateTransition(mMiddleState, mFinalState, false);
+ }
+
+ private void testUidStateTransition(int initialState, int finalState,
+ boolean initializeState) {
+ int initialUidState = processStateToUidState(initialState);
+ int finalUidState = processStateToUidState(finalState);
+
+ boolean expectUidProcessDeath =
+ finalUidState == UID_STATE_NONEXISTENT
+ && initialUidState != UID_STATE_NONEXISTENT
+ && finishRunningOpsForKilledPackages();
+
+ boolean foregroundChange = initialUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+ != finalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED;
+ boolean finalUidStateIsBackgroundAndLessImportant =
+ finalUidState > UID_STATE_MAX_LAST_NON_RESTRICTED
+ && finalUidState > initialUidState;
+
+ if (initializeState) {
+ mIntf.updateUidProcState(UID, initialState, ActivityManager.PROCESS_CAPABILITY_NONE);
+ }
+
+ UidStateChangedCallback cb = addUidStateChangeCallback();
+
+ mIntf.updateUidProcState(UID, finalState, ActivityManager.PROCESS_CAPABILITY_NONE);
+
+ if (finalUidStateIsBackgroundAndLessImportant) {
+ mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1);
+ }
+
+ int expectedInitialUidState = initialUidState == UID_STATE_NONEXISTENT
+ ? UID_STATE_CACHED : initialUidState;
+ int expectedFinalUidState = finalUidState == UID_STATE_NONEXISTENT
+ ? UID_STATE_CACHED : finalUidState;
+
+ if (expectedInitialUidState != expectedFinalUidState) {
+ verify(cb, times(1))
+ .onUidStateChanged(eq(UID), eq(expectedFinalUidState), eq(foregroundChange));
+ verify(cb, times(1))
+ .onUidStateChanged(anyInt(), anyInt(), anyBoolean());
+ } else {
+ verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
+ }
+ if (expectUidProcessDeath) {
+ verify(cb, times(1)).onUidProcessDeath(eq(UID));
+ verify(cb, times(1)).onUidProcessDeath(anyInt());
+ } else {
+ verify(cb, never()).onUidProcessDeath(anyInt());
+ }
+ }
+
+ private UidStateChangedCallback addUidStateChangeCallback() {
+ UidStateChangedCallback cb =
+ Mockito.mock(UidStateChangedCallback.class);
+ mIntf.addUidStateChangedCallback(r -> r.run(), cb);
+ return cb;
+ }
+
+ private static class AppOpsUidStateTrackerTestClock extends Clock {
+
+ private AppOpsUidStateTrackerTestExecutor mExecutor;
+ long mElapsedRealTime = 0x5f3759df;
+
+ AppOpsUidStateTrackerTestClock(AppOpsUidStateTrackerTestExecutor executor) {
+ mExecutor = executor;
+ executor.setUptime(mElapsedRealTime);
+ }
+
+ @Override
+ public long elapsedRealtime() {
+ return mElapsedRealTime;
+ }
+
+ void advanceTime(long time) {
+ mElapsedRealTime += time;
+ mExecutor.setUptime(mElapsedRealTime); // assume uptime == elapsedtime
+ }
+ }
+
+ private static class AppOpsUidStateTrackerTestExecutor implements DelayableExecutor {
+
+ private static class QueueElement implements Comparable<QueueElement> {
+
+ private long mExecutionTime;
+ private Runnable mRunnable;
+
+ private QueueElement(long executionTime, Runnable runnable) {
+ mExecutionTime = executionTime;
+ mRunnable = runnable;
+ }
+
+ @Override
+ public int compareTo(QueueElement queueElement) {
+ return Long.compare(mExecutionTime, queueElement.mExecutionTime);
+ }
+ }
+
+ private long mUptime = 0;
+
+ private PriorityQueue<QueueElement> mDelayedMessages = new PriorityQueue();
+
+ @Override
+ public void execute(Runnable runnable) {
+ runnable.run();
+ }
+
+ @Override
+ public void executeDelayed(Runnable runnable, long delay) {
+ if (delay <= 0) {
+ execute(runnable);
+ }
+
+ mDelayedMessages.add(new QueueElement(mUptime + delay, runnable));
+ }
+
+ private void setUptime(long uptime) {
+ while (!mDelayedMessages.isEmpty()
+ && mDelayedMessages.peek().mExecutionTime <= uptime) {
+ mDelayedMessages.poll().mRunnable.run();
+ }
+
+ mUptime = uptime;
+ }
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
index 2b152315eec4..a1cf94b994ab 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
@@ -26,16 +26,10 @@ import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import android.content.Context;
-import android.hardware.power.stats.Channel;
-import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyConsumerType;
-import android.hardware.power.stats.EnergyMeasurement;
-import android.hardware.power.stats.PowerEntity;
-import android.hardware.power.stats.StateResidencyResult;
import android.os.Handler;
import android.os.Looper;
import android.os.connectivity.WifiActivityEnergyInfo;
@@ -54,7 +48,6 @@ import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
-import java.util.concurrent.CompletableFuture;
/**
* Tests for {@link BatteryExternalStatsWorker}.
@@ -66,7 +59,7 @@ import java.util.concurrent.CompletableFuture;
@android.platform.test.annotations.DisabledOnRavenwood
public class BatteryExternalStatsWorkerTest {
private BatteryExternalStatsWorker mBatteryExternalStatsWorker;
- private TestPowerStatsInternal mPowerStatsInternal;
+ private MockPowerStatsInternal mPowerStatsInternal;
private Handler mHandler;
@Before
@@ -80,7 +73,7 @@ public class BatteryExternalStatsWorkerTest {
mHandler, null, null, null,
new PowerProfile(context, true /* forTest */), buildScalingPolicies(),
new PowerStatsUidResolver());
- mPowerStatsInternal = new TestPowerStatsInternal();
+ mPowerStatsInternal = new MockPowerStatsInternal();
mBatteryExternalStatsWorker =
new BatteryExternalStatsWorker(new TestInjector(context), batteryStats, mHandler);
}
@@ -260,102 +253,4 @@ public class BatteryExternalStatsWorkerTest {
freqsByPolicy.put(4, new int[]{300000, 1000000, 2500000, 3000000});
return new CpuScalingPolicies(freqsByPolicy, freqsByPolicy);
}
-
- private static class TestPowerStatsInternal extends PowerStatsInternal {
- private final SparseArray<EnergyConsumer> mEnergyConsumers = new SparseArray();
- private final SparseArray<EnergyConsumerResult> mEnergyConsumerResults = new SparseArray();
- private final int mTimeSinceBoot = 0;
-
- @Override
- public EnergyConsumer[] getEnergyConsumerInfo() {
- final int size = mEnergyConsumers.size();
- final EnergyConsumer[] consumers = new EnergyConsumer[size];
- for (int i = 0; i < size; i++) {
- consumers[i] = mEnergyConsumers.valueAt(i);
- }
- return consumers;
- }
-
- @Override
- public CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync(
- int[] energyConsumerIds) {
- final CompletableFuture<EnergyConsumerResult[]> future = new CompletableFuture();
- final EnergyConsumerResult[] results;
- final int length = energyConsumerIds.length;
- if (length == 0) {
- final int size = mEnergyConsumerResults.size();
- results = new EnergyConsumerResult[size];
- for (int i = 0; i < size; i++) {
- results[i] = mEnergyConsumerResults.valueAt(i);
- }
- } else {
- results = new EnergyConsumerResult[length];
- for (int i = 0; i < length; i++) {
- results[i] = mEnergyConsumerResults.get(energyConsumerIds[i]);
- }
- }
- future.complete(results);
- return future;
- }
-
- @Override
- public PowerEntity[] getPowerEntityInfo() {
- return new PowerEntity[0];
- }
-
- @Override
- public CompletableFuture<StateResidencyResult[]> getStateResidencyAsync(
- int[] powerEntityIds) {
- return new CompletableFuture<>();
- }
-
- @Override
- public Channel[] getEnergyMeterInfo() {
- return new Channel[0];
- }
-
- @Override
- public CompletableFuture<EnergyMeasurement[]> readEnergyMeterAsync(
- int[] channelIds) {
- return new CompletableFuture<>();
- }
-
- /**
- * Util method to add a new EnergyConsumer for testing
- *
- * @return the EnergyConsumer id of the new EnergyConsumer
- */
- public int addEnergyConsumer(@EnergyConsumerType byte type, int ordinal, String name) {
- final EnergyConsumer consumer = new EnergyConsumer();
- final int id = getNextAvailableId();
- consumer.id = id;
- consumer.type = type;
- consumer.ordinal = ordinal;
- consumer.name = name;
- mEnergyConsumers.put(id, consumer);
-
- final EnergyConsumerResult result = new EnergyConsumerResult();
- result.id = id;
- result.timestampMs = mTimeSinceBoot;
- result.energyUWs = 0;
- mEnergyConsumerResults.put(id, result);
- return id;
- }
-
- public void incrementEnergyConsumption(int id, long energyUWs) {
- EnergyConsumerResult result = mEnergyConsumerResults.get(id, null);
- assertNotNull(result);
- result.energyUWs += energyUWs;
- }
-
- private int getNextAvailableId() {
- final int size = mEnergyConsumers.size();
- // Just return the first index that does not match the key (aka the EnergyConsumer id)
- for (int i = size - 1; i >= 0; i--) {
- if (mEnergyConsumers.keyAt(i) == i) return i + 1;
- }
- // Otherwise return the lowest id
- return 0;
- }
- }
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryHistoryStepDetailsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryHistoryStepDetailsProviderTest.java
new file mode 100644
index 000000000000..850cd8868e67
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryHistoryStepDetailsProviderTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+import android.power.PowerStatsInternal;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.os.BatteryStatsHistoryIterator;
+import com.android.internal.os.MonotonicClock;
+import com.android.internal.os.PowerProfile;
+import com.android.server.LocalServices;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+@android.platform.test.annotations.DisabledOnRavenwood(reason =
+ "PowerStatsInternal is not supported under Ravenwood")
+@SuppressWarnings("GuardedBy")
+public class BatteryHistoryStepDetailsProviderTest {
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+ private final MockClock mMockClock = new MockClock();
+ private MockBatteryStatsImpl mBatteryStats;
+ private final Random mRandom = new Random();
+ private Handler mHandler;
+
+ @Before
+ public void setup() {
+ mMockClock.currentTime = 3000;
+ mHandler = new Handler(Looper.getMainLooper());
+ mBatteryStats = new MockBatteryStatsImpl(mMockClock, null, mHandler,
+ mock(PowerProfile.class));
+ mBatteryStats.setRecordAllHistoryLocked(true);
+ mBatteryStats.forceRecordAllHistory();
+ mBatteryStats.setNoAutoReset(true);
+ }
+
+ @Test
+ public void update() {
+ MockPowerStatsInternal powerStatsService = new MockPowerStatsInternal();
+ powerStatsService.addPowerEntity(42, "foo");
+ powerStatsService.addPowerEntityState(42, 0, "off");
+ powerStatsService.addPowerEntityState(42, 1, "on");
+ LocalServices.addService(PowerStatsInternal.class, powerStatsService);
+ mBatteryStats.onSystemReady(mock(Context.class));
+
+ mockUpdateCpuStats(100, 1_000_010, 1_000_010);
+ powerStatsService.addStateResidencyResult(42, 0, 1000, 2000, 3000);
+ powerStatsService.addStateResidencyResult(42, 1, 4000, 5000, 6000);
+
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0,
+ 1_000_000, 1_000_000, 1_000_000);
+ awaitCompletion();
+
+ mockUpdateCpuStats(200, 5_000_010, 5_000_010);
+ powerStatsService.reset();
+ powerStatsService.addStateResidencyResult(42, 0, 1111, 2222, 3333);
+ powerStatsService.addStateResidencyResult(42, 1, 4444, 5555, 6666);
+
+ // Battery level is unchanged, so we don't write battery level details in history
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0,
+ 5_500_000, 5_500_000, 5_000_000);
+ awaitCompletion();
+
+ // Not a battery state change event, so details are not written
+ mBatteryStats.noteAlarmStartLocked("wakeup", null, APP_UID, 6_000_000, 6_000_000);
+
+ mockUpdateCpuStats(300, 6_000_010, 6_000_010);
+ powerStatsService.reset();
+
+ // Battery level drops, so we write the accumulated battery level details
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 70, 72, 3700, 2_000_000, 4_000_000, 0,
+ 6_000_000, 6_000_000, 6_000_000);
+ awaitCompletion();
+
+ final BatteryStatsHistoryIterator iterator =
+ mBatteryStats.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
+
+ BatteryStats.HistoryItem item;
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.cmd).isEqualTo((int) BatteryStats.HistoryItem.CMD_RESET);
+ assertThat(item.stepDetails).isNull();
+
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.batteryLevel).isEqualTo(90);
+ assertThat(item.stepDetails.userTime).isEqualTo(100);
+ assertThat(item.stepDetails.statSubsystemPowerState).contains("subsystem_0 name=foo "
+ + "state_0 name=off time=1000 count=2000 last entry=3000 "
+ + "state_1 name=on time=4000 count=5000 last entry=6000");
+
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.batteryLevel).isEqualTo(80);
+ assertThat(item.stepDetails.userTime).isEqualTo(200);
+ assertThat(item.stepDetails.statSubsystemPowerState).contains("subsystem_0 name=foo "
+ + "state_0 name=off time=1111 count=2222 last entry=3333 "
+ + "state_1 name=on time=4444 count=5555 last entry=6666");
+
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.batteryLevel).isEqualTo(80);
+ assertThat(item.stepDetails).isNull();
+
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.batteryLevel).isEqualTo(70);
+ assertThat(item.stepDetails.userTime).isEqualTo(300);
+ assertThat(item.stepDetails.statSubsystemPowerState).isNull();
+
+ assertThat(iterator.next()).isNull();
+ }
+
+ private void mockUpdateCpuStats(int totalUTimeMs, long elapsedRealtime, long uptime) {
+ BatteryStatsImpl.BatteryCallback callback = mock(BatteryStatsImpl.BatteryCallback.class);
+ doAnswer(inv -> {
+ mMockClock.realtime = elapsedRealtime;
+ mMockClock.uptime = uptime;
+ synchronized (mBatteryStats) {
+ mBatteryStats.addCpuStatsLocked(totalUTimeMs, 0, 0, 0, 0, 0, 0, 0);
+ mBatteryStats.finishAddingCpuStatsLocked();
+ }
+ return null;
+ }).when(callback).batteryNeedsCpuUpdate();
+ mBatteryStats.setCallback(callback);
+ }
+
+ private void awaitCompletion() {
+ ConditionVariable done = new ConditionVariable();
+ mHandler.post(done::open);
+ done.block();
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
index 503e23347cf6..1b82ffdcf3e8 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
@@ -47,14 +47,12 @@ public class BatteryStatsHistoryIteratorTest {
private final MockClock mMockClock = new MockClock();
private MockBatteryStatsImpl mBatteryStats;
private final Random mRandom = new Random();
- private final MockExternalStatsSync mExternalStatsSync = new MockExternalStatsSync();
@Before
public void setup() {
final File historyDir = createTemporaryDirectory(getClass().getSimpleName());
mMockClock.currentTime = 3000;
mBatteryStats = new MockBatteryStatsImpl(mMockClock, historyDir);
- mBatteryStats.setDummyExternalStatsSync(mExternalStatsSync);
mBatteryStats.setRecordAllHistoryLocked(true);
mBatteryStats.forceRecordAllHistory();
mBatteryStats.setNoAutoReset(true);
@@ -227,72 +225,53 @@ public class BatteryStatsHistoryIteratorTest {
100, /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0,
1_000_000, 1_000_000, 1_000_000);
- mExternalStatsSync.updateCpuStats(100, 1_100_000, 1_100_000);
-
// Device was suspended for 3_000 seconds, note the difference in elapsed time and uptime
mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0,
5_000_000, 2_000_000, 5_000_000);
- mExternalStatsSync.updateCpuStats(200, 5_100_000, 2_100_000);
-
// Battery level is unchanged, so we don't write battery level details in history
- mBatteryStats.noteAlarmStartLocked("wakeup", null, APP_UID, 6_000_000, 3_000_000);
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0,
+ 5_500_000, 2_500_000, 5_000_000);
- assertThat(mExternalStatsSync.isSyncScheduled()).isFalse();
+ // Not a battery state change event, so details are not written
+ mBatteryStats.noteAlarmStartLocked("wakeup", null, APP_UID, 6_000_000, 3_000_000);
// Battery level drops, so we write the accumulated battery level details
mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
- 100, /* plugType */ 0, 79, 72, 3700, 2_000_000, 4_000_000, 0,
+ 100, /* plugType */ 0, 70, 72, 3700, 2_000_000, 4_000_000, 0,
7_000_000, 4_000_000, 6_000_000);
- mExternalStatsSync.updateCpuStats(300, 7_100_000, 4_100_000);
-
final BatteryStatsHistoryIterator iterator =
mBatteryStats.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
BatteryStats.HistoryItem item;
assertThat(item = iterator.next()).isNotNull();
assertThat(item.cmd).isEqualTo((int) BatteryStats.HistoryItem.CMD_RESET);
- assertThat(item.stepDetails).isNull();
assertThat(item = iterator.next()).isNotNull();
assertThat(item.batteryLevel).isEqualTo(90);
- assertThat(item.stepDetails).isNull();
-
- assertThat(item = iterator.next()).isNotNull();
- assertThat(item.batteryLevel).isEqualTo(90);
- assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS);
+ assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0);
assertThat(item = iterator.next()).isNotNull();
assertThat(item.batteryLevel).isEqualTo(90);
assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isEqualTo(0);
- assertThat(item.stepDetails.userTime).isEqualTo(100);
assertThat(item = iterator.next()).isNotNull();
assertThat(item.batteryLevel).isEqualTo(80);
assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0);
- assertThat(item.stepDetails.userTime).isEqualTo(0);
-
- assertThat(item = iterator.next()).isNotNull();
- assertThat(item.batteryLevel).isEqualTo(80);
- assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS);
assertThat(item = iterator.next()).isNotNull();
assertThat(item.batteryLevel).isEqualTo(80);
assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_ALARM_START);
- assertThat(item.stepDetails).isNull();
-
- assertThat(item = iterator.next()).isNotNull();
- assertThat(item.batteryLevel).isEqualTo(79);
assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0);
- assertThat(item.stepDetails.userTime).isEqualTo(200);
assertThat(item = iterator.next()).isNotNull();
- assertThat(item.batteryLevel).isEqualTo(79);
- assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS);
+ assertThat(item.batteryLevel).isEqualTo(70);
+ assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0);
- assertThat(item = iterator.next()).isNull();
+ assertThat(iterator.next()).isNull();
}
@Test
@@ -394,26 +373,4 @@ public class BatteryStatsHistoryIteratorTest {
assertThat(item.time).isEqualTo(elapsedTimeMs);
}
-
- private class MockExternalStatsSync extends MockBatteryStatsImpl.DummyExternalStatsSync {
- private boolean mSyncScheduled;
-
- @Override
- public void scheduleCpuSyncDueToWakelockChange(long delayMillis) {
- mSyncScheduled = true;
- }
-
- public boolean isSyncScheduled() {
- return mSyncScheduled;
- }
-
- public void updateCpuStats(int totalUTimeMs, long elapsedRealtime, long uptime) {
- assertThat(mExternalStatsSync.mSyncScheduled).isTrue();
- mBatteryStats.recordHistoryEventLocked(elapsedRealtime, uptime,
- BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, "wakelock-update", 0);
- mBatteryStats.addCpuStatsLocked(totalUTimeMs, 0, 0, 0, 0, 0, 0, 0);
- mBatteryStats.finishAddingCpuStatsLocked();
- mExternalStatsSync.mSyncScheduled = false;
- }
- }
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index 3ed4a52bed23..7acb93c0641e 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -26,7 +26,6 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
import android.os.BatteryConsumer;
import android.os.BatteryManager;
@@ -58,7 +57,8 @@ import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import java.io.File;
import java.io.IOException;
@@ -85,6 +85,8 @@ public class BatteryStatsHistoryTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private final Parcel mHistoryBuffer = Parcel.obtain();
private File mSystemDir;
@@ -97,14 +99,11 @@ public class BatteryStatsHistoryTest {
@Mock
private BatteryStatsHistory.TraceDelegate mTracer;
@Mock
- private BatteryStatsHistory.HistoryStepDetailsCalculator mStepDetailsCalculator;
- @Mock
private BatteryStatsHistory.EventLogger mEventLogger;
private List<String> mReadFiles = new ArrayList<>();
@Before
public void setUp() throws IOException {
- MockitoAnnotations.initMocks(this);
mSystemDir = Files.createTempDirectory("BatteryStatsHistoryTest").toFile();
mHistoryDir = new File(mSystemDir, "battery-history");
String[] files = mHistoryDir.list();
@@ -138,14 +137,10 @@ public class BatteryStatsHistoryTest {
mClock.currentTime = 1743645660000L; // 2025-04-03, 2:01:00 AM
mHistory = new BatteryStatsHistory(mHistoryBuffer, MAX_HISTORY_BUFFER_SIZE, mDirectory,
- mStepDetailsCalculator, mClock, mMonotonicClock, mTracer,
+ mClock, mMonotonicClock, mTracer,
mEventLogger);
mHistory.forceRecordAllHistory();
mHistory.startRecordingHistory(mClock.realtime, mClock.uptime, false);
-
- when(mStepDetailsCalculator.getHistoryStepDetails())
- .thenReturn(new BatteryStats.HistoryStepDetails());
-
mHistoryPrinter = new BatteryStats.HistoryPrinter(TimeZone.getTimeZone("GMT"));
}
@@ -288,7 +283,7 @@ public class BatteryStatsHistoryTest {
// create a new BatteryStatsHistory object, it will pick up existing history files.
BatteryStatsHistory history2 = new BatteryStatsHistory(mHistoryBuffer, 1024, mDirectory,
- null, mClock, mMonotonicClock, mTracer, mEventLogger);
+ mClock, mMonotonicClock, mTracer, mEventLogger);
// verify constructor can pick up all files from file system.
verifyFileNames(history2, fileList);
verifyActiveFile(history2, "33000.bh");
@@ -595,7 +590,7 @@ public class BatteryStatsHistoryTest {
// Keep the preserved part of history short - we only need to capture the very tail of
// history.
mHistory = new BatteryStatsHistory(mHistoryBuffer, 6000, mDirectory,
- mStepDetailsCalculator, mClock, mMonotonicClock, mTracer, mEventLogger);
+ mClock, mMonotonicClock, mTracer, mEventLogger);
mHistory.forceRecordAllHistory();
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
index 8a1d37b55255..90b3e132f9d3 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
@@ -575,7 +575,7 @@ public class BatteryUsageStatsProviderTest {
accumulateBatteryUsageStats(batteryStats, 10000000, 0);
// Accumulate every 200 bytes of battery history
accumulateBatteryUsageStats(batteryStats, 200, 1);
- accumulateBatteryUsageStats(batteryStats, 50, 5);
+ accumulateBatteryUsageStats(batteryStats, 50, 4);
// Accumulate on every invocation of accumulateBatteryUsageStats
accumulateBatteryUsageStats(batteryStats, 0, 7);
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
index c7a19ce7b233..8c3bd17c5acd 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
@@ -329,10 +329,6 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
}
@Override
- public void scheduleSyncDueToBatteryLevelChange(long delayMillis) {
- }
-
- @Override
public void scheduleSyncDueToProcessStateChange(int flags, long delayMillis) {
}
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockPowerStatsInternal.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockPowerStatsInternal.java
new file mode 100644
index 000000000000..dc5da8c2841f
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockPowerStatsInternal.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.power.stats;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.hardware.power.stats.Channel;
+import android.hardware.power.stats.EnergyConsumer;
+import android.hardware.power.stats.EnergyConsumerResult;
+import android.hardware.power.stats.EnergyConsumerType;
+import android.hardware.power.stats.EnergyMeasurement;
+import android.hardware.power.stats.PowerEntity;
+import android.hardware.power.stats.State;
+import android.hardware.power.stats.StateResidency;
+import android.hardware.power.stats.StateResidencyResult;
+import android.power.PowerStatsInternal;
+import android.util.SparseArray;
+
+import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+
+class MockPowerStatsInternal extends PowerStatsInternal {
+ private final SparseArray<PowerEntity> mPowerEntities = new SparseArray<>();
+ private final SparseArray<StateResidencyResult> mStateResidencyResults = new SparseArray<>();
+ private final SparseArray<EnergyConsumer> mEnergyConsumers = new SparseArray<>();
+ private final SparseArray<EnergyConsumerResult> mEnergyConsumerResults = new SparseArray<>();
+ private final int mTimeSinceBoot = 0;
+
+ @Override
+ public EnergyConsumer[] getEnergyConsumerInfo() {
+ final int size = mEnergyConsumers.size();
+ final EnergyConsumer[] consumers = new EnergyConsumer[size];
+ for (int i = 0; i < size; i++) {
+ consumers[i] = mEnergyConsumers.valueAt(i);
+ }
+ return consumers;
+ }
+
+ @Override
+ public CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync(
+ int[] energyConsumerIds) {
+ final CompletableFuture<EnergyConsumerResult[]> future = new CompletableFuture();
+ final EnergyConsumerResult[] results;
+ final int length = energyConsumerIds.length;
+ if (length == 0) {
+ final int size = mEnergyConsumerResults.size();
+ results = new EnergyConsumerResult[size];
+ for (int i = 0; i < size; i++) {
+ results[i] = mEnergyConsumerResults.valueAt(i);
+ }
+ } else {
+ results = new EnergyConsumerResult[length];
+ for (int i = 0; i < length; i++) {
+ results[i] = mEnergyConsumerResults.get(energyConsumerIds[i]);
+ }
+ }
+ future.complete(results);
+ return future;
+ }
+
+ @Override
+ public PowerEntity[] getPowerEntityInfo() {
+ final int size = mPowerEntities.size();
+ final PowerEntity[] entities = new PowerEntity[size];
+ for (int i = 0; i < size; i++) {
+ entities[i] = mPowerEntities.valueAt(i);
+ }
+ return entities;
+ }
+
+ @Override
+ public CompletableFuture<StateResidencyResult[]> getStateResidencyAsync(
+ int[] powerEntityIds) {
+ final CompletableFuture<StateResidencyResult[]> future = new CompletableFuture<>();
+ final StateResidencyResult[] results;
+ final int length = powerEntityIds.length;
+ if (length == 0) {
+ final int size = mStateResidencyResults.size();
+ results = new StateResidencyResult[size];
+ for (int i = 0; i < size; i++) {
+ results[i] = mStateResidencyResults.valueAt(i);
+ }
+ } else {
+ results = new StateResidencyResult[length];
+ for (int i = 0; i < length; i++) {
+ results[i] = mStateResidencyResults.get(powerEntityIds[i]);
+ }
+ }
+ future.complete(results);
+ return future;
+ }
+
+ @Override
+ public Channel[] getEnergyMeterInfo() {
+ return new Channel[0];
+ }
+
+ @Override
+ public CompletableFuture<EnergyMeasurement[]> readEnergyMeterAsync(
+ int[] channelIds) {
+ return new CompletableFuture<>();
+ }
+
+ public void reset() {
+ mStateResidencyResults.clear();
+ mEnergyConsumerResults.clear();
+ }
+
+ public void addPowerEntity(int id, String name) {
+ PowerEntity powerEntity = new PowerEntity();
+ powerEntity.id = id;
+ powerEntity.name = name;
+ powerEntity.states = new State[0];
+ mPowerEntities.put(id, powerEntity);
+ }
+
+ public void addPowerEntityState(int powerEntityId, int stateId, String name) {
+ State state = new State();
+ state.id = stateId;
+ state.name = name;
+
+ PowerEntity powerEntity = mPowerEntities.get(powerEntityId);
+ powerEntity.states = Arrays.copyOf(powerEntity.states, powerEntity.states.length + 1);
+ powerEntity.states[powerEntity.states.length - 1] = state;
+ }
+
+ public void addStateResidencyResult(int entityId, int stateId, long totalTimeInStateMs,
+ long totalStateEntryCount, long lastEntryTimestampMs) {
+ StateResidencyResult result = mStateResidencyResults.get(entityId);
+ if (result == null) {
+ result = new StateResidencyResult();
+ result.id = entityId;
+ result.stateResidencyData = new StateResidency[0];
+ mStateResidencyResults.put(entityId, result);
+ }
+
+ StateResidency residency = new StateResidency();
+ residency.id = stateId;
+ residency.totalTimeInStateMs = totalTimeInStateMs;
+ residency.totalStateEntryCount = totalStateEntryCount;
+ residency.lastEntryTimestampMs = lastEntryTimestampMs;
+
+ result.stateResidencyData = Arrays.copyOf(result.stateResidencyData,
+ result.stateResidencyData.length + 1);
+ result.stateResidencyData[result.stateResidencyData.length - 1] = residency;
+ }
+
+ /**
+ * Util method to add a new EnergyConsumer for testing
+ *
+ * @return the EnergyConsumer id of the new EnergyConsumer
+ */
+ public int addEnergyConsumer(@EnergyConsumerType byte type, int ordinal, String name) {
+ final EnergyConsumer consumer = new EnergyConsumer();
+ final int id = getNextAvailableId();
+ consumer.id = id;
+ consumer.type = type;
+ consumer.ordinal = ordinal;
+ consumer.name = name;
+ mEnergyConsumers.put(id, consumer);
+
+ final EnergyConsumerResult result = new EnergyConsumerResult();
+ result.id = id;
+ result.timestampMs = mTimeSinceBoot;
+ result.energyUWs = 0;
+ mEnergyConsumerResults.put(id, result);
+ return id;
+ }
+
+ public void incrementEnergyConsumption(int id, long energyUWs) {
+ EnergyConsumerResult result = mEnergyConsumerResults.get(id, null);
+ assertNotNull(result);
+ result.energyUWs += energyUWs;
+ }
+
+ private int getNextAvailableId() {
+ final int size = mEnergyConsumers.size();
+ // Just return the first index that does not match the key (aka the EnergyConsumer id)
+ for (int i = size - 1; i >= 0; i--) {
+ if (mEnergyConsumers.keyAt(i) == i) return i + 1;
+ }
+ // Otherwise return the lowest id
+ return 0;
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java
index 73d491c93bb5..7aa59bd03898 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java
@@ -59,9 +59,8 @@ public class PowerStatsAggregatorTest {
@Before
public void setup() throws ParseException {
- mHistory = new BatteryStatsHistory(null, 1024, null,
- mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock,
- mMonotonicClock, mock(BatteryStatsHistory.TraceDelegate.class), null);
+ mHistory = new BatteryStatsHistory(null, 1024, null, mClock, mMonotonicClock,
+ mock(BatteryStatsHistory.TraceDelegate.class), null);
AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
config.trackPowerComponent(TEST_POWER_COMPONENT)
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java
index a5a29f5883b1..b33cb7e6739f 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java
@@ -114,8 +114,7 @@ public class PowerStatsExporterTest {
mPowerStatsStore = new PowerStatsStore(storeDirectory, new TestHandler());
mDirectory = new BatteryHistoryDirectory(storeDirectory, 0);
- mHistory = new BatteryStatsHistory(Parcel.obtain(), 10000, mDirectory,
- mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock,
+ mHistory = new BatteryStatsHistory(Parcel.obtain(), 10000, mDirectory, mClock,
mMonotonicClock, null, null);
mPowerStatsAggregator = new PowerStatsAggregator(config);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/WakelockPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/WakelockPowerStatsProcessorTest.java
index 5ac7216194a4..b90019f9537a 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/WakelockPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/WakelockPowerStatsProcessorTest.java
@@ -29,8 +29,6 @@ import static com.android.server.power.stats.processor.AggregatedPowerStatsConfi
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
-
import android.annotation.SuppressLint;
import android.os.BatteryConsumer;
import android.os.PersistableBundle;
@@ -89,7 +87,6 @@ public class WakelockPowerStatsProcessorTest {
long[] uidStats = new long[descriptor.uidStatsArrayLength];
BatteryStatsHistory history = new BatteryStatsHistory(null, 10000, null,
- mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class),
mStatsRule.getMockClock(),
new MonotonicClock(START_TIME, mStatsRule.getMockClock()), null, null);
history.forceRecordAllHistory();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java
index 33529c3f4375..44870eb5dd49 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java
@@ -37,7 +37,6 @@ import android.content.Context;
import android.media.AudioDeviceInfo;
import android.media.AudioDevicePort;
import android.media.AudioManager;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
@@ -164,7 +163,6 @@ public class HearingDevicePhoneCallNotificationControllerTest {
}
@Test
- @EnableFlags(Flags.FLAG_HEARING_INPUT_CHANGE_WHEN_COMM_DEVICE)
public void onCallStateChanged_nonHearingDevice_offHookThenIdle_callAddAndRemoveListener() {
final ArgumentCaptor<AudioManager.OnCommunicationDeviceChangedListener> listenerCaptor =
ArgumentCaptor.forClass(AudioManager.OnCommunicationDeviceChangedListener.class);
@@ -185,7 +183,6 @@ public class HearingDevicePhoneCallNotificationControllerTest {
@Test
- @EnableFlags(Flags.FLAG_HEARING_INPUT_CHANGE_WHEN_COMM_DEVICE)
public void onCallStateChanged_hearingDeviceFromCommunicationDeviceChanged_showNotification() {
final ArgumentCaptor<AudioManager.OnCommunicationDeviceChangedListener> listenerCaptor =
ArgumentCaptor.forClass(AudioManager.OnCommunicationDeviceChangedListener.class);
@@ -209,7 +206,6 @@ public class HearingDevicePhoneCallNotificationControllerTest {
}
@Test
- @EnableFlags(Flags.FLAG_HEARING_INPUT_CHANGE_WHEN_COMM_DEVICE)
public void onCallStateChanged_offHookMultiple_addListenerOnlyOneTime() {
AudioDeviceInfo a2dpDeviceInfo = createAudioDeviceInfo(TEST_ADDRESS,
AudioManager.DEVICE_OUT_BLUETOOTH_A2DP);
diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
index 952d8fa47a34..09acfddacf03 100644
--- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
@@ -51,6 +51,7 @@ import android.os.IThermalStatusListener;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Temperature;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -78,6 +79,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server
@@ -117,7 +119,8 @@ public class ThermalManagerServiceTest {
*/
private class ThermalHalFake extends ThermalHalWrapper {
private static final int INIT_STATUS = Temperature.THROTTLING_NONE;
- private List<Temperature> mTemperatureList = new ArrayList<>();
+ private final List<Temperature> mTemperatureList = new ArrayList<>();
+ private AtomicInteger mGetCurrentTemperaturesCalled = new AtomicInteger();
private List<CoolingDevice> mCoolingDeviceList = new ArrayList<>();
private List<TemperatureThreshold> mTemperatureThresholdList = initializeThresholds();
@@ -173,6 +176,7 @@ public class ThermalManagerServiceTest {
mTemperatureList.add(mUsbPort);
mCoolingDeviceList.add(mCpu);
mCoolingDeviceList.add(mGpu);
+ mGetCurrentTemperaturesCalled.set(0);
}
void enableForecastSkinTemperature() {
@@ -188,14 +192,24 @@ public class ThermalManagerServiceTest {
mForecastSkinTemperaturesError = true;
}
+ void updateTemperatureList(Temperature... temperatures) {
+ synchronized (mTemperatureList) {
+ mTemperatureList.clear();
+ mTemperatureList.addAll(Arrays.asList(temperatures));
+ }
+ }
+
@Override
protected List<Temperature> getCurrentTemperatures(boolean shouldFilter, int type) {
List<Temperature> ret = new ArrayList<>();
- for (Temperature temperature : mTemperatureList) {
- if (shouldFilter && type != temperature.getType()) {
- continue;
+ synchronized (mTemperatureList) {
+ mGetCurrentTemperaturesCalled.incrementAndGet();
+ for (Temperature temperature : mTemperatureList) {
+ if (shouldFilter && type != temperature.getType()) {
+ continue;
+ }
+ ret.add(temperature);
}
- ret.add(temperature);
}
return ret;
}
@@ -407,7 +421,7 @@ public class ThermalManagerServiceTest {
Thread.sleep(CALLBACK_TIMEOUT_MILLI_SEC);
resetListenerMock();
int status = Temperature.THROTTLING_SEVERE;
- mFakeHal.mTemperatureList = new ArrayList<>();
+ mFakeHal.updateTemperatureList();
// Should not notify on non-skin type
Temperature newBattery = new Temperature(37, Temperature.TYPE_BATTERY, "batt", status);
@@ -537,6 +551,42 @@ public class ThermalManagerServiceTest {
}
@Test
+ @DisableFlags({Flags.FLAG_ALLOW_THERMAL_HAL_SKIN_FORECAST})
+ public void testGetThermalHeadroom_handlerUpdateTemperatures()
+ throws RemoteException, InterruptedException {
+ // test that handler will at least enqueue one message to periodically read temperatures
+ // even if there is sample seeded from HAL temperature callback
+ String temperatureName = "skin1";
+ Temperature temperature = new Temperature(100, Temperature.TYPE_SKIN, temperatureName,
+ Temperature.THROTTLING_NONE);
+ mFakeHal.mCallback.onTemperatureChanged(temperature);
+ float headroom = mService.mService.getThermalHeadroom(0);
+ // the callback temperature 100C (headroom > 1.0f) sample should have been appended by the
+ // immediately scheduled fake HAL current temperatures read (mSkin1, mSkin2), and because
+ // there are less samples for prediction, the latest temperature mSkin1 is used to calculate
+ // headroom (mSkin2 has no threshold), which is 0.6f (28C vs threshold 40C).
+ assertEquals(0.6f, headroom, 0.01f);
+ // one called by service onActivityManagerReady, one called by handler on headroom call
+ assertEquals(2, mFakeHal.mGetCurrentTemperaturesCalled.get());
+ // periodic read should update the samples history, so the headroom should increase 0.1f
+ // as current temperature goes up by 3C every 1100ms.
+ for (int i = 1; i < 5; i++) {
+ Temperature newTemperature = new Temperature(mFakeHal.mSkin1.getValue() + 3 * i,
+ Temperature.TYPE_SKIN,
+ temperatureName,
+ Temperature.THROTTLING_NONE);
+ mFakeHal.updateTemperatureList(newTemperature);
+ // wait for handler to update temperature
+ Thread.sleep(1100);
+ // assert that only one callback was scheduled to query HAL when making multiple
+ // headroom calls
+ assertEquals(2 + i, mFakeHal.mGetCurrentTemperaturesCalled.get());
+ headroom = mService.mService.getThermalHeadroom(0);
+ assertEquals(0.6f + 0.1f * i, headroom, 0.01f);
+ }
+ }
+
+ @Test
@EnableFlags({Flags.FLAG_ALLOW_THERMAL_HAL_SKIN_FORECAST})
public void testGetThermalHeadroom_halForecast() throws RemoteException {
mFakeHal.mForecastSkinTemperaturesCalled = 0;
diff --git a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
index 339bac4f768b..d6b3fecb487c 100644
--- a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
@@ -45,6 +45,8 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
@SuppressLint("VisibleForTests")
@@ -66,17 +68,28 @@ public class AdvancedProtectionServiceTest {
mPermissionEnforcer.grant(Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE);
mStore = new AdvancedProtectionService.AdvancedProtectionStore(mContext) {
+ private Map<String, Integer> mStoredValues = new HashMap<>();
private boolean mEnabled = false;
@Override
- boolean retrieve() {
+ boolean retrieveAdvancedProtectionModeEnabled() {
return mEnabled;
}
@Override
- void store(boolean enabled) {
+ void storeAdvancedProtectionModeEnabled(boolean enabled) {
this.mEnabled = enabled;
}
+
+ @Override
+ void storeInt(String key, int value) {
+ mStoredValues.put(key, value);
+ }
+
+ @Override
+ int retrieveInt(String key, int defaultValue) {
+ return mStoredValues.getOrDefault(key, defaultValue);
+ }
};
mLooper = new TestLooper();
@@ -316,6 +329,18 @@ public class AdvancedProtectionServiceTest {
}
@Test
+ public void testUsbDataProtection_withoutPermission() {
+ mPermissionEnforcer.revoke(Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE);
+ assertThrows(SecurityException.class, () -> mService.isUsbDataProtectionEnabled());
+ }
+
+ @Test
+ public void testSetUsbDataProtection_withoutPermission() {
+ mPermissionEnforcer.revoke(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE);
+ assertThrows(SecurityException.class, () -> mService.setUsbDataProtectionEnabled(true));
+ }
+
+ @Test
public void testRegisterCallback_withoutPermission() {
mPermissionEnforcer.revoke(Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE);
assertThrows(SecurityException.class, () -> mService.registerAdvancedProtectionCallback(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 902171d614d9..8c9b9bd03b9f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -18657,4 +18657,37 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mGroupHelper).onNotificationRemoved(eq(n), any(), eq(false));
}
+
+ @Test
+ public void onDisplayRemoveSystemDecorations_cancelToasts() throws RemoteException {
+ final String testPackage = "testPackageName";
+ final INotificationManager service = ((INotificationManager) mService.mService);
+ final IBinder firstExternal = new Binder();
+ final IBinder secondExternal = new Binder();
+ final IBinder firstBuiltin = new Binder();
+ service.enqueueTextToast(testPackage,
+ firstExternal, "First external", TOAST_DURATION,
+ /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null);
+ service.enqueueTextToast(testPackage,
+ secondExternal, "Second external", TOAST_DURATION,
+ /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null);
+ service.enqueueTextToast(testPackage,
+ firstBuiltin, "First built-in", TOAST_DURATION, /* isUiContext= */ true,
+ /* displayId= */ DEFAULT_DISPLAY, /* callback= */ null);
+
+ mInternalService.onDisplayRemoveSystemDecorations(10);
+
+ verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstExternal),
+ any(String.class), any(IBinder.class), anyInt(), any(), eq(10));
+ verify(mStatusBar).hideToast(eq(testPackage), eq(firstExternal));
+ // The second toast has not been shown but invokes hide() anyway as
+ // NotificationManagerService does not remembered if it invoked show().
+ verify(mStatusBar, never()).showToast(anyInt(), eq(testPackage), eq(secondExternal),
+ any(String.class), any(IBinder.class), anyInt(), any(), eq(10));
+ verify(mStatusBar).hideToast(eq(testPackage), eq(secondExternal));
+ // The toast on the default display is shown as other notifications are cancelled.
+ verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstBuiltin), any(String.class),
+ any(IBinder.class), anyInt(), any(), eq(DEFAULT_DISPLAY));
+ verify(mStatusBar, never()).hideToast(eq(testPackage), eq(firstBuiltin));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
index 0495e967c0e3..5ab00361d3c0 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -491,6 +491,11 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
@Test
public void testKeyGestureBack() {
+ mPhoneWindowManager.overrideDelegateBackGestureRemote(true);
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BACK);
+ mPhoneWindowManager.assertBackEventInjected();
+
+ mPhoneWindowManager.overrideDelegateBackGestureRemote(false);
sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BACK);
mPhoneWindowManager.assertBackEventInjected();
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 7b6d361c55d4..7059c41898f3 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -202,6 +202,7 @@ class TestPhoneWindowManager {
private boolean mIsTalkBackEnabled;
private boolean mIsTalkBackShortcutGestureEnabled;
+ private boolean mDelegateBackGestureRemote;
private boolean mIsVoiceAccessEnabled;
private Intent mBrowserIntent;
@@ -580,6 +581,12 @@ class TestPhoneWindowManager {
setPhoneCallIsInProgress();
}
+ void overrideDelegateBackGestureRemote(boolean isDelegating) {
+ mDelegateBackGestureRemote = isDelegating;
+ doReturn(mDelegateBackGestureRemote).when(mActivityTaskManagerInternal)
+ .requestBackGesture();
+ }
+
void prepareBrightnessDecrease(float currentBrightness) {
doReturn(0.0f).when(mPowerManager).getBrightnessConstraint(
DEFAULT_DISPLAY, PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
@@ -661,13 +668,21 @@ class TestPhoneWindowManager {
}
void assertBackEventInjected() {
- ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
- verify(mInputManager, times(2)).injectInputEvent(intentCaptor.capture(), anyInt());
- List<InputEvent> inputEvents = intentCaptor.getAllValues();
- Assert.assertEquals(KeyEvent.KEYCODE_BACK, ((KeyEvent) inputEvents.get(0)).getKeyCode());
- Assert.assertEquals(KeyEvent.KEYCODE_BACK, ((KeyEvent) inputEvents.get(1)).getKeyCode());
- // Reset verifier for next call.
- Mockito.clearInvocations(mContext);
+ if (mDelegateBackGestureRemote) {
+ Mockito.verify(mActivityTaskManagerInternal).requestBackGesture();
+ ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
+ verify(mInputManager, never()).injectInputEvent(intentCaptor.capture(), anyInt());
+ } else {
+ ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
+ verify(mInputManager, times(2)).injectInputEvent(intentCaptor.capture(), anyInt());
+ List<InputEvent> inputEvents = intentCaptor.getAllValues();
+ Assert.assertEquals(KeyEvent.KEYCODE_BACK,
+ ((KeyEvent) inputEvents.get(0)).getKeyCode());
+ Assert.assertEquals(KeyEvent.KEYCODE_BACK,
+ ((KeyEvent) inputEvents.get(1)).getKeyCode());
+ // Reset verifier for next call.
+ Mockito.clearInvocations(mContext);
+ }
}
void overrideSearchKeyBehavior(int behavior) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 521d8364a31f..449ca867b987 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -52,6 +52,8 @@ import android.view.Surface;
import androidx.test.filters.SmallTest;
import com.android.server.LocalServices;
+import com.android.server.UiThread;
+import com.android.server.notification.NotificationManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
import com.android.window.flags.Flags;
@@ -59,6 +61,7 @@ import com.android.window.flags.Flags;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
import java.util.HashMap;
import java.util.Map;
@@ -387,6 +390,30 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
}
@Test
+ @EnableFlags(com.android.server.display.feature.flags.Flags
+ .FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT)
+ public void testSetShouldShowSystemDecorsNotifyNotificationManager() {
+ final NotificationManagerInternal notificationManager = Mockito.mock(
+ NotificationManagerInternal.class);
+ LocalServices.addService(NotificationManagerInternal.class, notificationManager);
+ try {
+ // First show the decoration because setting false is noop if the decoration has already
+ // been hidden.
+ mDisplayWindowSettings.setShouldShowSystemDecorsLocked(
+ mSecondaryDisplay, /* shouldShow= */ true);
+
+ mDisplayWindowSettings.setShouldShowSystemDecorsLocked(
+ mSecondaryDisplay, /* shouldShow= */ false);
+
+ waitHandlerIdle(UiThread.getHandler());
+ Mockito.verify(notificationManager).onDisplayRemoveSystemDecorations(
+ mSecondaryDisplay.mDisplayId);
+ } finally {
+ LocalServices.removeServiceForTest(NotificationManagerInternal.class);
+ }
+ }
+
+ @Test
public void testPrimaryDisplayImePolicy() {
assertEquals(DISPLAY_IME_POLICY_LOCAL,
mDisplayWindowSettings.getImePolicyLocked(mPrimaryDisplay));
diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp
index 8fbc3e8a78db..a103d03af3c3 100644
--- a/tools/protologtool/Android.bp
+++ b/tools/protologtool/Android.bp
@@ -11,13 +11,13 @@ java_library_host {
name: "protologtool-lib",
srcs: [
"src/com/android/protolog/tool/**/*.kt",
- ":protolog-common-src",
],
static_libs: [
"javaparser",
- "platformprotos",
"jsonlib",
"perfetto_trace-full",
+ "platformprotos",
+ "protolog-common-lib",
],
}
@@ -39,10 +39,10 @@ java_test_host {
unit_test: true,
},
static_libs: [
- "protologtool-lib",
"junit",
"mockito",
"objenesis",
+ "protologtool-lib",
"truth",
],
}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
index 47724b7a9e1d..03c3a15562a9 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
@@ -24,5 +24,5 @@ interface ProtoLogCallProcessor {
logCallVisitor: ProtoLogCallVisitor?,
otherCallVisitor: MethodCallVisitor?,
fileName: String
- ): CompilationUnit
+ ): Collection<CodeProcessingException>
}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
index 1f6db5fe2d37..44db2ba45845 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
@@ -74,7 +74,7 @@ class ProtoLogCallProcessorImpl(
}
fun process(code: CompilationUnit, logCallVisitor: ProtoLogCallVisitor?, fileName: String):
- CompilationUnit {
+ Collection<CodeProcessingException> {
return process(code, logCallVisitor, null, fileName)
}
@@ -83,7 +83,7 @@ class ProtoLogCallProcessorImpl(
logCallVisitor: ProtoLogCallVisitor?,
otherCallVisitor: MethodCallVisitor?,
fileName: String
- ): CompilationUnit {
+ ): Collection<CodeProcessingException> {
CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName)
CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName)
@@ -93,50 +93,63 @@ class ProtoLogCallProcessorImpl(
protoLogGroupClassName)
val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName)
+ val errors = mutableListOf<CodeProcessingException>()
code.findAll(MethodCallExpr::class.java)
.filter { call ->
isProtoCall(call, isLogClassImported, staticLogImports)
}.forEach { call ->
val context = ParsingContext(fileName, call)
- val logMethods = LogLevel.entries.map { it.shortCode }
- if (logMethods.contains(call.name.id)) {
- // Process a log call
- if (call.arguments.size < 2) {
- throw InvalidProtoLogCallException("Method signature does not match " +
- "any ProtoLog method: $call", context)
- }
+ try {
+ val logMethods = LogLevel.entries.map { it.shortCode }
+ if (logMethods.contains(call.name.id)) {
+ // Process a log call
+ if (call.arguments.size < 2) {
+ errors.add(InvalidProtoLogCallException(
+ "Method signature does not match " +
+ "any ProtoLog method: $call", context
+ ))
+ return@forEach
+ }
- val messageString = CodeUtils.concatMultilineString(call.getArgument(1),
- context)
- val groupNameArg = call.getArgument(0)
- val groupName =
- getLogGroupName(groupNameArg, isGroupClassImported,
- staticGroupImports, fileName)
- if (groupName !in groupMap) {
- throw InvalidProtoLogCallException("Unknown group argument " +
- "- not a ProtoLogGroup enum member: $call", context)
- }
+ val messageString = CodeUtils.concatMultilineString(
+ call.getArgument(1),
+ context
+ )
+ val groupNameArg = call.getArgument(0)
+ val groupName =
+ getLogGroupName(
+ groupNameArg, isGroupClassImported,
+ staticGroupImports, fileName
+ )
+ if (groupName !in groupMap) {
+ errors.add(InvalidProtoLogCallException(
+ "Unknown group argument " +
+ "- not a ProtoLogGroup enum member: $call", context
+ ))
+ return@forEach
+ }
- try {
logCallVisitor?.processCall(
call, messageString, getLevelForMethodName(
call.name.toString(), call, context
), groupMap.getValue(groupName),
context.lineNumber
)
- } catch (e: Throwable) {
- throw InvalidProtoLogCallException("Error processing log call: $call",
- context, e)
+ } else if (call.name.id == "init") {
+ // No processing
+ } else {
+ // Process non-log message calls
+ otherCallVisitor?.processCall(call)
}
- } else if (call.name.id == "init") {
- // No processing
- } else {
- // Process non-log message calls
- otherCallVisitor?.processCall(call)
+ } catch (e: Throwable) {
+ errors.add(InvalidProtoLogCallException(
+ "Error processing log call: $call",
+ context, e
+ ))
}
}
- return code
+ return errors
}
private fun getLevelForMethodName(
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index d8a2954545bb..e9f2e81b69db 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -130,14 +130,16 @@ object ProtoLogTool {
val outSrc = try {
val code = tryParse(text, path)
if (containsProtoLogText(text, PROTOLOG_CLASS_NAME)) {
- transformer.processClass(text, path, packagePath(file, code), code)
+ val (processedText, errors) = transformer.processClass(text, path, packagePath(file, code), code)
+ errors.forEach { injector.reportProcessingError(it) }
+ processedText
} else {
text
}
} catch (ex: ParsingException) {
// If we cannot parse this file, skip it (and log why). Compilation will
// fail in a subsequent build step.
- injector.reportParseError(ex)
+ injector.reportProcessingError(ex)
text
}
path to outSrc
@@ -405,7 +407,7 @@ object ProtoLogTool {
} catch (ex: ParsingException) {
// If we cannot parse this file, skip it (and log why). Compilation will
// fail in a subsequent build step.
- injector.reportParseError(ex)
+ injector.reportProcessingError(ex)
null
}
} else {
@@ -466,6 +468,14 @@ object ProtoLogTool {
try {
val command = CommandOptions(args)
invoke(command)
+
+ if (injector.processingErrors.isNotEmpty()) {
+ injector.processingErrors.forEachIndexed { index, it ->
+ println("CodeProcessingException " +
+ "(${index + 1}/${injector.processingErrors.size}): \n${it.message}\n")
+ }
+ exitProcess(1)
+ }
} catch (ex: InvalidCommandException) {
println("InvalidCommandException: \n${ex.message}\n")
showHelpAndExit()
@@ -489,12 +499,14 @@ object ProtoLogTool {
}
var injector = object : Injector {
+ override val processingErrors: MutableList<CodeProcessingException>
+ get() = mutableListOf()
override fun fileOutputStream(file: String) = FileOutputStream(file)
override fun readText(file: File) = file.readText()
override fun readLogGroups(jarPath: String, className: String) =
ProtoLogGroupReader().loadFromJar(jarPath, className)
- override fun reportParseError(ex: ParsingException) {
- println("\n${ex.message}\n")
+ override fun reportProcessingError(ex: CodeProcessingException) {
+ processingErrors.add(ex)
}
}
@@ -502,7 +514,8 @@ object ProtoLogTool {
fun fileOutputStream(file: String): OutputStream
fun readText(file: File): String
fun readLogGroups(jarPath: String, className: String): Map<String, LogGroup>
- fun reportParseError(ex: ParsingException)
+ fun reportProcessingError(ex: CodeProcessingException)
+ val processingErrors: Collection<CodeProcessingException>
}
}
diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
index 76df0674df65..e97b0dd9a04b 100644
--- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
@@ -66,13 +66,13 @@ class SourceTransformer(
packagePath: String,
compilationUnit: CompilationUnit =
StaticJavaParser.parse(code)
- ): String {
+ ): Pair<String, Collection<CodeProcessingException>> {
this.path = path
this.packagePath = packagePath
processedCode = code.split('\n').toMutableList()
offsets = IntArray(processedCode.size)
- protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path)
- return processedCode.joinToString("\n")
+ val processingErrors = protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path)
+ return Pair(processedCode.joinToString("\n"), processingErrors)
}
private val protoLogImplClassNode =
diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
index 0cbbd483fe59..71bab3ebf2db 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
@@ -17,6 +17,7 @@
package com.android.protolog.tool
import com.android.protolog.tool.ProtoLogTool.PROTOLOG_IMPL_SRC_PATH
+import com.android.protolog.tool.ProtoLogTool.injector
import com.google.common.truth.Truth
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
@@ -102,6 +103,42 @@ class EndToEndTest {
""".trimIndent())
}
+ @Test
+ fun e2e_transform_withErrors() {
+ val srcs = mapOf(
+ "frameworks/base/org/example/Example.java" to """
+ package org.example;
+ import com.android.internal.protolog.ProtoLog;
+ import static com.android.internal.protolog.ProtoLogGroup.GROUP;
+
+ class Example {
+ void method() {
+ String argString = "hello";
+ int argInt = 123;
+ ProtoLog.d(GROUP, "Invalid format: %s %d %9 %", argString, argInt);
+ }
+ }
+ """.trimIndent())
+ val output = run(
+ srcs = srcs,
+ logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
+ commandOptions = CommandOptions(arrayOf("transform-protolog-calls",
+ "--protolog-class", "com.android.internal.protolog.ProtoLog",
+ "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
+ "--loggroups-jar", "not_required.jar",
+ "--viewer-config-file-path", "not_required.pb",
+ "--output-srcjar", "out.srcjar",
+ "frameworks/base/org/example/Example.java"))
+ )
+ val outSrcJar = assertLoadSrcJar(output, "out.srcjar")
+ // No change to source code on failure to process
+ Truth.assertThat(outSrcJar["frameworks/base/org/example/Example.java"])
+ .contains(srcs["frameworks/base/org/example/Example.java"])
+
+ Truth.assertThat(injector.processingErrors).hasSize(1)
+ Truth.assertThat(injector.processingErrors.first().message).contains("Invalid format")
+ }
+
private fun assertLoadSrcJar(
outputs: Map<String, ByteArray>,
path: String
@@ -172,7 +209,11 @@ class EndToEndTest {
override fun readLogGroups(jarPath: String, className: String) = mapOf(
logGroup.name to logGroup)
- override fun reportParseError(ex: ParsingException) = throw AssertionError(ex)
+ override fun reportProcessingError(ex: CodeProcessingException) {
+ processingErrors.add(ex)
+ }
+
+ override val processingErrors: MutableList<CodeProcessingException> = mutableListOf()
}
ProtoLogTool.invoke(commandOptions)
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
index 732824ae841c..8f765aecb431 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
@@ -21,7 +21,6 @@ import com.android.internal.protolog.common.LogLevel
import com.github.javaparser.StaticJavaParser
import com.github.javaparser.ast.expr.MethodCallExpr
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertThrows
import org.junit.Test
import com.google.common.truth.Truth
@@ -124,7 +123,7 @@ class ProtoLogCallProcessorImplTest {
checkCalls()
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_groupNotImported() {
val code = """
package org.example2;
@@ -138,7 +137,10 @@ class ProtoLogCallProcessorImplTest {
}
"""
groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager")
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
@Test
@@ -159,7 +161,7 @@ class ProtoLogCallProcessorImplTest {
assertEquals(0, calls.size)
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_unknownGroup() {
val code = """
package org.example;
@@ -170,10 +172,13 @@ class ProtoLogCallProcessorImplTest {
}
}
"""
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_staticGroup() {
val code = """
package org.example;
@@ -184,10 +189,13 @@ class ProtoLogCallProcessorImplTest {
}
}
"""
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_badGroup() {
val code = """
package org.example;
@@ -198,10 +206,13 @@ class ProtoLogCallProcessorImplTest {
}
}
"""
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_invalidSignature() {
val code = """
package org.example;
@@ -212,7 +223,10 @@ class ProtoLogCallProcessorImplTest {
}
}
"""
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
@Test
@@ -257,9 +271,10 @@ class ProtoLogCallProcessorImplTest {
}
}
- val exception = assertThrows(InvalidProtoLogCallException::class.java) {
- visitor.process(StaticJavaParser.parse(code), processor, "MyTestFile.java")
- }
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "MyTestFile.java")
+ Truth.assertThat(errors).hasSize(1)
+
+ val exception = errors.first()
Truth.assertThat(exception).hasMessageThat()
.contains("Code processing error in MyTestFile.java:6")
Truth.assertThat(exception.cause).hasMessageThat()
diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
index 674a907d68d9..271fc6064678 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
@@ -160,10 +160,10 @@ class SourceTransformerTest {
visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST"), 123)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -201,10 +201,10 @@ class SourceTransformerTest {
visitor.processCall(calls[2], "test %d %f",
LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST"), 123)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -238,10 +238,10 @@ class SourceTransformerTest {
"test %d %f abc %s\n test", LogLevel.WARN, LogGroup("TEST_GROUP",
true, true, "WM_TEST"), 123)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -275,10 +275,10 @@ class SourceTransformerTest {
visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test",
LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST"), 456)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -309,10 +309,10 @@ class SourceTransformerTest {
visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
LogLevel.WARN, LogGroup("TEST_GROUP", true, false, "WM_TEST"), 789)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -346,10 +346,10 @@ class SourceTransformerTest {
"test %d %f abc %s\n test", LogLevel.WARN, LogGroup("TEST_GROUP",
true, false, "WM_TEST"), 123)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {