summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/PerfettoTrackEventExtra.java5
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/view/ViewRootImpl.java50
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java3
-rw-r--r--core/java/android/window/DesktopModeFlags.java2
-rw-r--r--core/java/android/window/TransitionInfo.java4
-rw-r--r--core/java/android/window/flags/lse_desktop_experience.aconfig12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/Operations.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/Platform.java13
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java129
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java11
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java8
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java36
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/BitmapFontData.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java13
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapFontText.java13
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java17
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java43
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java13
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/FloatFunctionCall.java11
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ImageAttribute.java23
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesLoop.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java30
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java46
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java188
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java19
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleColumnLayout.java70
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleRowLayout.java43
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java29
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/FitBoxLayout.java371
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java17
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java39
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java47
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DrawContentOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightInModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthInModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java41
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java17
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java8
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java39
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java10
-rw-r--r--core/proto/android/providers/settings/secure.proto1
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--core/res/res/layout/accessibility_autoclick_type_panel.xml4
-rw-r--r--core/tests/coretests/src/android/os/PerfettoTraceTest.java2
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt171
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt176
-rw-r--r--libs/hwui/CanvasTransform.cpp44
-rw-r--r--libs/hwui/RenderNode.cpp33
-rw-r--r--libs/hwui/hwui/Bitmap.cpp13
-rw-r--r--libs/hwui/hwui/Bitmap.h1
-rw-r--r--libs/hwui/jni/GIFMovie.cpp10
-rw-r--r--location/java/android/location/LocationRequest.java9
-rw-r--r--location/java/android/location/flags/location.aconfig11
-rw-r--r--packages/EasterEgg/src/com/android/egg/landroid/Autopilot.kt2
-rw-r--r--packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt4
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt1
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt8
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt10
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt2
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt1
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt17
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt33
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java18
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java76
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt21
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt80
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt115
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt44
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt97
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java19
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt2
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt8
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/ClockEventController.kt33
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java19
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt94
-rw-r--r--packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/BouncerScrimController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/ScrimController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt98
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt31
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt20
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java29
-rw-r--r--services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickLinearLayout.java80
-rw-r--r--services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java18
-rw-r--r--services/core/java/com/android/server/appop/DiscreteOpsRegistry.java2
-rw-r--r--services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java113
-rw-r--r--services/core/java/com/android/server/appop/HistoricalRegistry.java1
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java93
-rw-r--r--services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java10
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java16
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java29
-rw-r--r--services/core/java/com/android/server/wm/Transition.java5
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java13
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java25
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceMockedTest.java (renamed from services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java)7
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java89
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickLinearLayoutTest.java102
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java43
-rw-r--r--services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java18
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java17
230 files changed, 3366 insertions, 752 deletions
diff --git a/core/java/android/os/PerfettoTrackEventExtra.java b/core/java/android/os/PerfettoTrackEventExtra.java
index 2848bcb8ad34..8a3a5be9c934 100644
--- a/core/java/android/os/PerfettoTrackEventExtra.java
+++ b/core/java/android/os/PerfettoTrackEventExtra.java
@@ -214,9 +214,6 @@ public final class PerfettoTrackEventExtra {
* Initialize the builder for a new trace event.
*/
public Builder init(int traceType, PerfettoTrace.Category category) {
- if (!category.isEnabled()) {
- return this;
- }
mTraceType = traceType;
mCategory = category;
mEventName = "";
@@ -228,7 +225,7 @@ public final class PerfettoTrackEventExtra {
mExtra.reset();
// Reset after on init in case the thread created builders without calling emit
- return initInternal(this, null, true);
+ return initInternal(this, null, category.isEnabled());
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 89f66c010976..1210790668de 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9357,6 +9357,16 @@ public final class Settings {
"accessibility_autoclick_panel_position";
/**
+ * Setting that specifies whether autoclick type reverts to left click after performing
+ * an action when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set.
+ *
+ * @see #ACCESSIBILITY_AUTOCLICK_ENABLED
+ * @hide
+ */
+ public static final String ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK =
+ "accessibility_autoclick_revert_to_left_click";
+
+ /**
* Whether or not larger size icons are used for the pointer of mouse/trackpad for
* accessibility.
* (0 = false, 1 = true)
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e157da72196a..9d0773f0a606 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2071,26 +2071,40 @@ public final class ViewRootImpl implements ViewParent,
*/
@VisibleForTesting
public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() {
- if (forceInvertColor()) {
- // Force invert ignores all developer opt-outs.
- // We also ignore dark theme, since the app developer can override the user's preference
- // for dark mode in configuration.uiMode. Instead, we assume that both force invert and
- // the system's dark theme are enabled.
- if (getUiModeManager().getForceInvertState() == UiModeManager.FORCE_INVERT_TYPE_DARK) {
- return ForceDarkType.FORCE_INVERT_COLOR_DARK;
- }
- }
-
- boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
- if (useAutoDark) {
- boolean forceDarkAllowedDefault =
- SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
- TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
- useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
- && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);
+ TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
+ try {
+ if (forceInvertColor()) {
+ // Force invert ignores all developer opt-outs.
+ // We also ignore dark theme, since the app developer can override the user's
+ // preference for dark mode in configuration.uiMode. Instead, we assume that both
+ // force invert and the system's dark theme are enabled.
+ if (getUiModeManager().getForceInvertState() ==
+ UiModeManager.FORCE_INVERT_TYPE_DARK) {
+ final boolean isLightTheme =
+ a.getBoolean(R.styleable.Theme_isLightTheme, false);
+ // TODO: b/372558459 - Also check the background ColorDrawable color lightness
+ // TODO: b/368725782 - Use hwui color area detection instead of / in
+ // addition to these heuristics.
+ if (isLightTheme) {
+ return ForceDarkType.FORCE_INVERT_COLOR_DARK;
+ } else {
+ return ForceDarkType.NONE;
+ }
+ }
+ }
+
+ boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
+ if (useAutoDark) {
+ boolean forceDarkAllowedDefault =
+ SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
+ useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
+ && a.getBoolean(R.styleable.Theme_forceDarkAllowed,
+ forceDarkAllowedDefault);
+ }
+ return useAutoDark ? ForceDarkType.FORCE_DARK : ForceDarkType.NONE;
+ } finally {
a.recycle();
}
- return useAutoDark ? ForceDarkType.FORCE_DARK : ForceDarkType.NONE;
}
private void updateForceDarkMode() {
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index d267c9451d1a..e43fb48527a1 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -163,6 +163,9 @@ public final class AccessibilityManager {
/** @hide */
public static final boolean AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT_DEFAULT = false;
+ /** @hide */
+ public static final boolean AUTOCLICK_REVERT_TO_LEFT_CLICK_DEFAULT = true;
+
/**
* Activity action: Launch UI to manage which accessibility service or feature is assigned
* to the navigation bar Accessibility button.
diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java
index 696b7b8bb965..1b8f73a7edb8 100644
--- a/core/java/android/window/DesktopModeFlags.java
+++ b/core/java/android/window/DesktopModeFlags.java
@@ -126,6 +126,8 @@ public enum DesktopModeFlags {
ENABLE_TILE_RESIZING(Flags::enableTileResizing, true),
ENABLE_TOP_VISIBLE_ROOT_TASK_PER_USER_TRACKING(Flags::enableTopVisibleRootTaskPerUserTracking,
true),
+ ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX(
+ Flags::enableVisualIndicatorInTransitionBugfix, false),
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/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 63c55ad6a889..be4edc3b6ec5 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -29,6 +29,7 @@ import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_NONE;
@@ -375,7 +376,8 @@ public final class TransitionInfo implements Parcelable {
*/
public boolean hasChangesOrSideEffects() {
return !mChanges.isEmpty() || isKeyguardGoingAway()
- || (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0;
+ || (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0
+ || (mFlags & TRANSIT_FLAG_AOD_APPEARING) != 0;
}
/**
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 09f458be9bfa..2f2a09a9fac3 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -864,4 +864,14 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
-} \ No newline at end of file
+}
+
+flag {
+ name: "enable_visual_indicator_in_transition_bugfix"
+ namespace: "lse_desktop_experience"
+ description: "Enables bugfix to move visual drop-zone indicator to transition root, so it can't be shown after the transition."
+ bug: "392826275"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
index b8503da2c09b..796ea8d1538f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -65,7 +65,7 @@ public class CoreDocument implements Serializable {
// We also keep a more fine-grained BUILD number, exposed as
// ID_API_LEVEL = DOCUMENT_API_LEVEL + BUILD
- static final float BUILD = 0.2f;
+ static final float BUILD = 0.3f;
@NonNull ArrayList<Operation> mOperations = new ArrayList<>();
@@ -411,7 +411,7 @@ public class CoreDocument implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", "CoreDocument")
+ .addType("CoreDocument")
.add("width", mWidth)
.add("height", mHeight)
.add("operations", mOperations);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
index 09ec40271f4d..9cbafab07a43 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
@@ -100,6 +100,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.managers
import com.android.internal.widget.remotecompose.core.operations.layout.managers.CollapsibleColumnLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.CollapsibleRowLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.ColumnLayout;
+import com.android.internal.widget.remotecompose.core.operations.layout.managers.FitBoxLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.RowLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.StateLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.TextLayout;
@@ -231,6 +232,7 @@ public class Operations {
public static final int LAYOUT_ROOT = 200;
public static final int LAYOUT_CONTENT = 201;
public static final int LAYOUT_BOX = 202;
+ public static final int LAYOUT_FIT_BOX = 176;
public static final int LAYOUT_ROW = 203;
public static final int LAYOUT_COLLAPSIBLE_ROW = 230;
public static final int LAYOUT_COLUMN = 204;
@@ -391,6 +393,7 @@ public class Operations {
map.put(LAYOUT_ROOT, RootLayoutComponent::read);
map.put(LAYOUT_CONTENT, LayoutComponentContent::read);
map.put(LAYOUT_BOX, BoxLayout::read);
+ map.put(LAYOUT_FIT_BOX, FitBoxLayout::read);
map.put(LAYOUT_COLUMN, ColumnLayout::read);
map.put(LAYOUT_COLLAPSIBLE_COLUMN, CollapsibleColumnLayout::read);
map.put(LAYOUT_ROW, RowLayout::read);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java
index f355676be63e..c27ee3284b9c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java
@@ -17,11 +17,13 @@ package com.android.internal.widget.remotecompose.core;
import android.annotation.NonNull;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
+
/**
* PaintOperation interface, used for operations aimed at painting (while any operation _can_ paint,
* this make it a little more explicit)
*/
-public abstract class PaintOperation extends Operation {
+public abstract class PaintOperation extends Operation implements Serializable {
@Override
public void apply(@NonNull RemoteContext context) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Platform.java b/core/java/com/android/internal/widget/remotecompose/core/Platform.java
index 6073de662cdb..3fff86c38b2e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Platform.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Platform.java
@@ -47,6 +47,14 @@ public interface Platform {
int getImageHeight(@NonNull Object image);
/**
+ * Returns true if the platform-specific image object has format ALPHA_8
+ *
+ * @param image platform-specific image object
+ * @return whether or not the platform-specific image object has format ALPHA_8
+ */
+ boolean isAlpha8Image(@NonNull Object image);
+
+ /**
* Converts a platform-specific path object into a platform-independent float buffer
*
* @param path
@@ -110,6 +118,11 @@ public interface Platform {
}
@Override
+ public boolean isAlpha8Image(@NonNull Object image) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public float[] pathToFloatArray(@NonNull Object path) {
throw new UnsupportedOperationException();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
index e75bd30b381d..c249adf5bd58 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
@@ -98,6 +98,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.managers
import com.android.internal.widget.remotecompose.core.operations.layout.managers.CollapsibleColumnLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.CollapsibleRowLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.ColumnLayout;
+import com.android.internal.widget.remotecompose.core.operations.layout.managers.FitBoxLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.RowLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.StateLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.TextLayout;
@@ -281,13 +282,7 @@ public class RemoteComposeBuffer {
int dstRight,
int dstBottom,
@Nullable String contentDescription) {
- int imageId = mRemoteComposeState.dataGetId(image);
- if (imageId == -1) {
- imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe
- BitmapData.apply(
- mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential npe
- }
+ int imageId = storeBitmap(image);
int contentDescriptionId = 0;
if (contentDescription != null) {
contentDescriptionId = addText(contentDescription);
@@ -443,16 +438,7 @@ public class RemoteComposeBuffer {
float right,
float bottom,
@Nullable String contentDescription) {
- int imageId = mRemoteComposeState.dataGetId(image);
- if (imageId == -1) {
- imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe
- int imageWidth = mPlatform.getImageWidth(image);
- int imageHeight = mPlatform.getImageHeight(image);
-
- BitmapData.apply(
- mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential npe
- }
+ int imageId = storeBitmap(image);
addDrawBitmap(imageId, left, top, right, bottom, contentDescription);
}
@@ -523,15 +509,7 @@ public class RemoteComposeBuffer {
int scaleType,
float scaleFactor,
@Nullable String contentDescription) {
- int imageId = mRemoteComposeState.dataGetId(image);
- if (imageId == -1) {
- imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe
- int imageWidth = mPlatform.getImageWidth(image);
- int imageHeight = mPlatform.getImageHeight(image);
-
- BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential pe
- }
+ int imageId = storeBitmap(image);
int contentDescriptionId = 0;
if (contentDescription != null) {
contentDescriptionId = addText(contentDescription);
@@ -559,16 +537,7 @@ public class RemoteComposeBuffer {
* @return id of the image useful with
*/
public int addBitmap(@NonNull Object image) {
- int imageId = mRemoteComposeState.dataGetId(image);
- if (imageId == -1) {
- imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image); // tODO: potential npe
- int imageWidth = mPlatform.getImageWidth(image);
- int imageHeight = mPlatform.getImageHeight(image);
-
- BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data);
- }
- return imageId;
+ return storeBitmap(image);
}
/**
@@ -578,18 +547,7 @@ public class RemoteComposeBuffer {
* @return id of the image useful with
*/
public int addBitmap(@NonNull Object image, @NonNull String name) {
- int imageId = mRemoteComposeState.dataGetId(image);
- if (imageId == -1) {
- imageId = mRemoteComposeState.cacheData(image);
- byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe
- int imageWidth = mPlatform.getImageWidth(image);
- int imageHeight = mPlatform.getImageHeight(image);
-
- BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data);
- setBitmapName(imageId, name);
- }
-
- return imageId;
+ return storeBitmap(image);
}
/**
@@ -1393,7 +1351,7 @@ public class RemoteComposeBuffer {
* @return the id of the command representing long
*/
public int addLong(long value) {
- int id = mRemoteComposeState.cacheData(value);
+ int id = mRemoteComposeState.nextId();
LongConstant.apply(mBuffer, id, value);
return id;
}
@@ -1405,7 +1363,7 @@ public class RemoteComposeBuffer {
* @return the id
*/
public int addBoolean(boolean value) {
- int id = mRemoteComposeState.cacheData(value);
+ int id = mRemoteComposeState.nextId();
BooleanConstant.apply(mBuffer, id, value);
return id;
}
@@ -1821,33 +1779,14 @@ public class RemoteComposeBuffer {
}
/**
- * This defines the name of the color given the id.
- *
- * @param id of the color
- * @param name Name of the color
- */
- public void setColorName(int id, @NonNull String name) {
- NamedVariable.apply(mBuffer, id, NamedVariable.COLOR_TYPE, name);
- }
-
- /**
- * This defines the name of the string given the id
- *
- * @param id of the string
- * @param name name of the string
- */
- public void setStringName(int id, @NonNull String name) {
- NamedVariable.apply(mBuffer, id, NamedVariable.STRING_TYPE, name);
- }
-
- /**
- * This defines the name of the float given the id
+ * This defines the name of a type of given object
*
* @param id of the float
* @param name name of the float
+ * @param type the type of variable NamedVariable.COLOR_TYPE, STRING_TYPE, etc
*/
- public void setFloatName(int id, String name) {
- NamedVariable.apply(mBuffer, id, NamedVariable.FLOAT_TYPE, name);
+ public void setNamedVariable(int id, @NonNull String name, int type) {
+ NamedVariable.apply(mBuffer, id, type, name);
}
/**
@@ -2139,6 +2078,19 @@ public class RemoteComposeBuffer {
}
/**
+ * Add a fitbox start tag
+ *
+ * @param componentId component id
+ * @param animationId animation id
+ * @param horizontal horizontal alignment
+ * @param vertical vertical alignment
+ */
+ public void addFitBoxStart(int componentId, int animationId, int horizontal, int vertical) {
+ mLastComponentId = getComponentId(componentId);
+ FitBoxLayout.apply(mBuffer, mLastComponentId, animationId, horizontal, vertical);
+ }
+
+ /**
* Add a row start tag
*
* @param componentId component id
@@ -2439,4 +2391,35 @@ public class RemoteComposeBuffer {
public void drawComponentContent() {
DrawContent.apply(mBuffer);
}
+
+ /**
+ * Ensures the bitmap is stored.
+ *
+ * @param image the bitbap to store
+ * @return the id of the bitmap
+ */
+ private int storeBitmap(Object image) {
+ int imageId = mRemoteComposeState.dataGetId(image);
+ if (imageId == -1) {
+ imageId = mRemoteComposeState.cacheData(image);
+ byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe
+ short imageWidth = (short) mPlatform.getImageWidth(image);
+ short imageHeight = (short) mPlatform.getImageHeight(image);
+ if (mPlatform.isAlpha8Image(image)) {
+ BitmapData.apply(
+ mBuffer,
+ imageId,
+ BitmapData.TYPE_PNG_ALPHA_8,
+ imageWidth,
+ BitmapData.ENCODING_INLINE,
+ imageHeight,
+ data); // todo: potential npe
+ } else {
+ BitmapData.apply(
+ mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential npe
+ }
+ }
+
+ return imageId;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
index 363b82bdf70c..83c06197db9c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
@@ -27,6 +27,7 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.IntMa
import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
/**
@@ -36,7 +37,7 @@ import java.util.HashMap;
public class RemoteComposeState implements CollectionsAccess {
public static final int START_ID = 42;
// private static final int MAX_FLOATS = 500;
- private static final int MAX_COLORS = 200;
+ private static int sMaxColors = 200;
private static final int MAX_DATA = 1000;
private final IntMap<Object> mIntDataMap = new IntMap<>();
@@ -52,7 +53,7 @@ public class RemoteComposeState implements CollectionsAccess {
private final IntMap<Object> mPathMap = new IntMap<>();
private final IntMap<float[]> mPathData = new IntMap<>();
- private final boolean[] mColorOverride = new boolean[MAX_COLORS];
+ private boolean[] mColorOverride = new boolean[sMaxColors];
@NonNull private final IntMap<ArrayAccess> mCollectionMap = new IntMap<>();
private final boolean[] mDataOverride = new boolean[MAX_DATA];
@@ -318,7 +319,7 @@ public class RemoteComposeState implements CollectionsAccess {
* @param color
*/
public void updateColor(int id, int color) {
- if (mColorOverride[id]) {
+ if (id < sMaxColors && mColorOverride[id]) {
return;
}
mColorMap.put(id, color);
@@ -342,6 +343,10 @@ public class RemoteComposeState implements CollectionsAccess {
* @param color
*/
public void overrideColor(int id, int color) {
+ if (id >= sMaxColors) {
+ sMaxColors *= 2;
+ mColorOverride = Arrays.copyOf(mColorOverride, sMaxColors);
+ }
mColorOverride[id] = true;
mColorMap.put(id, color);
updateListeners(id);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index 622f0c8d12b7..c6b17e4116d6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -211,6 +211,14 @@ public abstract class RemoteContext {
public abstract void clearNamedFloatOverride(String floatName);
/**
+ * Set the value of a named long. This modifies the content of a LongConstant
+ *
+ * @param name the name of the float to override
+ * @param value Override the default float
+ */
+ public abstract void setNamedLong(String name, long value);
+
+ /**
* Set the value of a named Object. This overrides the Object in the document
*
* @param dataName the name of the Object to override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
index 13e6f3859933..255d7a46e49e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
@@ -72,6 +72,9 @@ public class BitmapData extends Operation implements SerializableToString, Seria
/** The data is encoded as RAW 8888 bit */
public static final short TYPE_RAW8888 = 3;
+ /** The data is encoded as PNG_8888 but decoded as ALPHA_8 */
+ public static final short TYPE_PNG_ALPHA_8 = 4;
+
/**
* create a bitmap structure
*
@@ -136,6 +139,15 @@ public class BitmapData extends Operation implements SerializableToString, Seria
}
/**
+ * The type of the image
+ *
+ * @return the type of the image
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
* Add the image to the document
*
* @param buffer document to write to
@@ -195,6 +207,21 @@ public class BitmapData extends Operation implements SerializableToString, Seria
int imageId = buffer.readInt();
int width = buffer.readInt();
int height = buffer.readInt();
+ int type;
+ if (width > 0xffff) {
+ type = width >> 16;
+ width = width & 0xffff;
+ } else {
+ type = TYPE_PNG_8888;
+ }
+
+ int encoding;
+ if (height > 0xffff) {
+ encoding = height >> 16;
+ height = height & 0xffff;
+ } else {
+ encoding = ENCODING_INLINE;
+ }
if (width < 1
|| height < 1
|| height > MAX_IMAGE_DIMENSION
@@ -202,7 +229,10 @@ public class BitmapData extends Operation implements SerializableToString, Seria
throw new RuntimeException("Dimension of image is invalid " + width + "x" + height);
}
byte[] bitmap = buffer.readBuffer();
- operations.add(new BitmapData(imageId, width, height, bitmap));
+ BitmapData bitmapData = new BitmapData(imageId, width, height, bitmap);
+ bitmapData.mType = (short) type;
+ bitmapData.mEncoding = (short) encoding;
+ operations.add(bitmapData);
}
/**
@@ -244,7 +274,7 @@ public class BitmapData extends Operation implements SerializableToString, Seria
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("imageId", mImageId)
.add("imageWidth", mImageWidth)
.add("imageHeight", mImageHeight)
@@ -275,6 +305,8 @@ public class BitmapData extends Operation implements SerializableToString, Seria
return "TYPE_RAW8";
case TYPE_RAW8888:
return "TYPE_RAW8888";
+ case TYPE_PNG_ALPHA_8:
+ return "TYPE_PNG_ALPHA_8";
default:
return "TYPE_INVALID";
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapFontData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapFontData.java
index 078ce981d243..70bda6d1c0fa 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapFontData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapFontData.java
@@ -221,6 +221,6 @@ public class BitmapFontData extends Operation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId);
+ serializer.addType(CLASS_NAME).add("id", mId);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
index 00ac9c28f362..7a8373bf7c7d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
@@ -237,7 +237,7 @@ public class ClickArea extends Operation
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("id", mId)
.add("contentDescriptionId", mContentDescription)
.add("left", mLeft, mOutLeft)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
index e7dc405b542e..03bdb70a9289 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
@@ -133,7 +133,7 @@ public class ClipPath extends PaintOperation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId).add("regionOp", regionOpToString());
+ serializer.addType(CLASS_NAME).add("id", mId).add("regionOp", regionOpToString());
}
String regionOpToString() {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
index 1646146bd21d..8b1e96a691a6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
@@ -118,6 +118,6 @@ public class ClipRect extends DrawBase4 {
@Override
public void serialize(MapSerializer serializer) {
- serialize(serializer, "left", "top", "right", "bottom").add("type", CLASS_NAME);
+ serialize(serializer, "left", "top", "right", "bottom").addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
index 333ffaae8289..7b12f4a9cf15 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
@@ -133,7 +133,7 @@ public class ColorConstant extends Operation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("color", Utils.colorInt(mColor))
.add("colorId", mColorId);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
index d5af7914607a..25323a8a818d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
@@ -507,7 +507,7 @@ public class ColorExpression extends Operation implements VariableSupport, Seria
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId);
+ serializer.addType(CLASS_NAME).add("id", mId);
switch (mMode) {
case COLOR_COLOR_INTERPOLATE:
case ID_COLOR_INTERPOLATE:
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
index cd13d2534266..5335e4fa76ca 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
@@ -171,7 +171,7 @@ public class ComponentValue extends Operation implements SerializableToString, S
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("valueId", mValueId)
.add("componentValueType", typeToString(mType))
.add("componentId", mComponentID);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
index fb3abdbb0626..20bebaa1ddb2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
@@ -148,8 +148,9 @@ public class DataListFloat extends Operation implements VariableSupport, ArrayAc
return mValues.length;
}
+ @SuppressWarnings("JdkImmutableCollections")
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId).add("values", List.of(mValues));
+ serializer.addType(CLASS_NAME).add("id", mId).add("values", List.of(mValues));
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
index 58fd74fdcf3e..af660f3d42c9 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
@@ -150,8 +150,9 @@ public class DataListIds extends Operation implements VariableSupport, ArrayAcce
return 0;
}
+ @SuppressWarnings("JdkImmutableCollections")
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId).add("ids", List.of(mIds));
+ serializer.addType(CLASS_NAME).add("id", mId).add("ids", List.of(mIds));
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
index a427836b6c5f..5024164651f5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
@@ -141,6 +141,6 @@ public class DrawArc extends DrawBase6 {
@Override
public void serialize(MapSerializer serializer) {
serialize(serializer, "left", "top", "right", "bottom", "startAngle", "sweepAngle")
- .add("type", CLASS_NAME);
+ .addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
index 40d3bede0912..e3b53a125a63 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
@@ -28,6 +28,7 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.List;
@@ -185,4 +186,16 @@ public class DrawBitmap extends PaintOperation implements VariableSupport {
public void paint(@NonNull PaintContext context) {
context.drawBitmap(mId, mOutputLeft, mOutputTop, mOutputRight, mOutputBottom);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("imageId", mId)
+ .add("contentDescriptionId", mDescriptionId)
+ .add("left", mLeft, mOutputLeft)
+ .add("top", mTop, mOutputTop)
+ .add("right", mRight, mOutputRight)
+ .add("bottom", mBottom, mOutputBottom);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapFontText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapFontText.java
index 258988e8b00a..bff87fda2fd9 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapFontText.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapFontText.java
@@ -28,6 +28,7 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.List;
@@ -229,4 +230,16 @@ public class DrawBitmapFontText extends PaintOperation implements VariableSuppor
xPos = xPos2 + glyph.mMarginRight;
}
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("textId", mTextID)
+ .add("bitmapFontId", mBitmapFontID)
+ .add("start", mStart)
+ .add("end", mEnd)
+ .add("x", mX, mOutX)
+ .add("y", mY, mOutY);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java
index 013dd1ae9db8..39d85af900ee 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java
@@ -25,6 +25,7 @@ import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.List;
@@ -230,4 +231,20 @@ public class DrawBitmapInt extends PaintOperation implements AccessibleComponent
mDstBottom,
mContentDescId);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("imageId", mImageId)
+ .add("contentDescriptionId", mContentDescId)
+ .add("srcLeft", mSrcLeft)
+ .add("srcTop", mSrcTop)
+ .add("srcRight", mSrcRight)
+ .add("srcBottom", mSrcBottom)
+ .add("dstLeft", mDstLeft)
+ .add("dstTop", mDstTop)
+ .add("dstRight", mDstRight)
+ .add("dstBottom", mDstBottom);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
index e1070f97d5aa..827e5692e132 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
@@ -28,6 +28,7 @@ import com.android.internal.widget.remotecompose.core.documentation.Documentatio
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.ImageScaling;
import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.List;
@@ -374,4 +375,46 @@ public class DrawBitmapScaled extends PaintOperation
mContentDescId);
context.restore();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("imageId", mImageId)
+ .add("contentDescriptionId", mContentDescId)
+ .add("scaleType", getScaleTypeString())
+ .add("mode", mMode)
+ .add("scaleFactor", mScaleFactor, mOutScaleFactor)
+ .add("srcLeft", mSrcLeft, mOutSrcLeft)
+ .add("srcTop", mSrcTop, mOutSrcTop)
+ .add("srcRight", mSrcRight, mOutSrcRight)
+ .add("srcBottom", mSrcBottom, mOutSrcBottom)
+ .add("dstLeft", mDstLeft, mOutDstLeft)
+ .add("dstTop", mDstTop, mOutDstTop)
+ .add("dstRight", mDstRight, mOutDstRight)
+ .add("dstBottom", mDstBottom, mOutDstBottom);
+ }
+
+ private String getScaleTypeString() {
+ switch (mScaleType) {
+ case SCALE_NONE:
+ return "SCALE_NONE";
+ case SCALE_INSIDE:
+ return "SCALE_INSIDE";
+ case SCALE_FILL_WIDTH:
+ return "SCALE_FILL_WIDTH";
+ case SCALE_FILL_HEIGHT:
+ return "SCALE_FILL_HEIGHT";
+ case SCALE_FIT:
+ return "SCALE_FIT";
+ case SCALE_CROP:
+ return "SCALE_CROP";
+ case SCALE_FILL_BOUNDS:
+ return "SCALE_FILL_BOUNDS";
+ case SCALE_FIXED_SCALE:
+ return "SCALE_FIXED_SCALE";
+ default:
+ return "INVALID_SCALE_TYPE";
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
index dfc89b12de1e..538cbaf97a06 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
@@ -112,6 +112,6 @@ public class DrawCircle extends DrawBase3 {
@Override
public void serialize(MapSerializer serializer) {
- serialize(serializer, "cx", "cy", "radius").add("type", CLASS_NAME);
+ serialize(serializer, "cx", "cy", "radius").addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java
index e2e22acbeb8f..4d2a939eb948 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java
@@ -114,6 +114,6 @@ public class DrawContent extends PaintOperation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME);
+ serializer.addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
index 461dece02625..97e5057fb950 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
@@ -140,6 +140,6 @@ public class DrawLine extends DrawBase4 implements SerializableToString {
@Override
public void serialize(MapSerializer serializer) {
- serialize(serializer, "startX", "startY", "endX", "endY").add("type", CLASS_NAME);
+ serialize(serializer, "startX", "startY", "endX", "endY").addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
index d0a5adc0e737..5d619baa1328 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
@@ -110,6 +110,6 @@ public class DrawOval extends DrawBase4 {
@Override
public void serialize(MapSerializer serializer) {
- serialize(serializer, "left", "top", "right", "bottom").add("type", CLASS_NAME);
+ serialize(serializer, "left", "top", "right", "bottom").addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
index 3fd8bb440d82..6e299275fb24 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
@@ -112,6 +112,6 @@ public class DrawPath extends PaintOperation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId).add("start", mStart).add("end", mEnd);
+ serializer.addType(CLASS_NAME).add("id", mId).add("start", mStart).add("end", mEnd);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
index f6aa30f5b5dd..15f3ced74652 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
@@ -106,6 +106,6 @@ public class DrawRect extends DrawBase4 {
@Override
public void serialize(MapSerializer serializer) {
- serialize(serializer, "left", "top", "right", "bottom").add("type", CLASS_NAME);
+ serialize(serializer, "left", "top", "right", "bottom").addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
index 67338c14a101..31d9b6ac124d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
@@ -127,6 +127,6 @@ public class DrawRoundRect extends DrawBase6 {
@Override
public void serialize(MapSerializer serializer) {
serialize(serializer, "left", "top", "right", "bottom", "rx", "sweepAngle")
- .add("type", CLASS_NAME);
+ .addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java
index 78f64a5bcd44..19f16239b9f2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java
@@ -128,6 +128,6 @@ public class DrawSector extends DrawBase6 {
@Override
public void serialize(MapSerializer serializer) {
serialize(serializer, "left", "top", "right", "bottom", "startAngle", "sweepAngle")
- .add("type", CLASS_NAME);
+ .addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
index 8adba1d2616a..ee1689c21fe3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
@@ -28,6 +28,7 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.List;
@@ -205,4 +206,17 @@ public class DrawText extends PaintOperation implements VariableSupport {
public void paint(@NonNull PaintContext context) {
context.drawTextRun(mTextID, mStart, mEnd, mContextStart, mContextEnd, mOutX, mOutY, mRtl);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("start", mStart)
+ .add("end", mEnd)
+ .add("contextStart", mContextStart)
+ .add("contextEnd", mContextEnd)
+ .add("x", mX, mOutX)
+ .add("y", mY, mOutY)
+ .add("rtl", mRtl);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
index 92469d1834ba..1d917d565331 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
@@ -244,7 +244,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport,
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("textId", mTextID)
.add("x", mX, mOutX)
.add("y", mY, mOutY)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
index 1f7910ede4b5..f382440360ed 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
@@ -159,7 +159,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport, S
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("pathId", mPathId)
.add("textId", mTextId)
.add("vOffset", mVOffset, mOutVOffset)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
index e2883949022c..4ca995b59f1f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
@@ -28,6 +28,7 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.List;
@@ -171,4 +172,15 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport {
public void paint(@NonNull PaintContext context) {
context.drawTweenPath(mPath1Id, mPath2Id, mOutTween, mOutStart, mOutStop);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("path1Id", mPath1Id)
+ .add("path2Id", mPath2Id)
+ .add("tween", mTween, mOutTween)
+ .add("start", mStart, mOutStart)
+ .add("stop", mStop, mOutStop);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
index 7f3c3ed6bcff..233e246d3868 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
@@ -123,6 +123,6 @@ public class FloatConstant extends Operation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId).add("value", mValue);
+ serializer.addType(CLASS_NAME).add("id", mId).add("value", mValue);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
index c1fa898ec619..eba201bfb216 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
@@ -160,6 +160,9 @@ public class FloatExpression extends Operation implements VariableSupport, Seria
mLastAnimatedValue = lastComputedValue;
context.loadFloat(mId, lastComputedValue);
context.needsRepaint();
+ if (mFloatAnimation.isPropagate()) {
+ markDirty();
+ }
}
} else if (mSpring != null) {
float lastComputedValue = mSpring.get(t - mLastChange);
@@ -169,8 +172,12 @@ public class FloatExpression extends Operation implements VariableSupport, Seria
context.needsRepaint();
}
} else {
- float v =
- mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length);
+ float v = 0;
+ try {
+ v = mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length);
+ } catch (Exception e) {
+ throw new RuntimeException(this.toString() + " len = " + mPreCalcValue.length, e);
+ }
if (mFloatAnimation != null) {
mFloatAnimation.setTargetValue(v);
}
@@ -344,7 +351,7 @@ public class FloatExpression extends Operation implements VariableSupport, Seria
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.EXPRESSION)
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("id", mId)
.addFloatExpressionSrc("srcValues", mSrcValue)
.add("animation", mFloatAnimation);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatFunctionCall.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatFunctionCall.java
index eccc00a18308..85592948438f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatFunctionCall.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatFunctionCall.java
@@ -32,8 +32,10 @@ import com.android.internal.widget.remotecompose.core.documentation.Documentatio
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression;
import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/** This provides the command to call a floatfunction defined in floatfunction */
@@ -182,4 +184,13 @@ public class FloatFunctionCall extends PaintOperation implements VariableSupport
}
mFunction.execute(remoteContext);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("id", mId)
+ .add("args", Collections.singletonList(mArgs))
+ .add("outArgs", Collections.singletonList(mOutArgs));
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ImageAttribute.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ImageAttribute.java
index fb4a5e4848c2..9ef1b3b1ad6a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ImageAttribute.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ImageAttribute.java
@@ -26,7 +26,9 @@ import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import java.util.Collections;
import java.util.List;
/** Operation to extract meta Attributes from image data objects */
@@ -162,4 +164,25 @@ public class ImageAttribute extends PaintOperation {
break;
}
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("id", mId)
+ .add("imageId", mImageId)
+ .add("args", Collections.singletonList(mArgs))
+ .addType(typeToString());
+ }
+
+ private String typeToString() {
+ switch (mType) {
+ case IMAGE_WIDTH:
+ return "IMAGE_WIDTH";
+ case IMAGE_HEIGHT:
+ return "IMAGE_HEIGHT";
+ default:
+ return "INVALID_TYPE";
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
index 2a5260c0c9b1..53b3c89f3aa8 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
@@ -233,7 +233,7 @@ public class IntegerExpression extends Operation implements VariableSupport, Ser
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.EXPRESSION)
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("id", mId)
.add("mask", mId)
.addIntExpressionSrc("srcValues", mSrcValue, mMask);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
index 64df19d8a04f..d2b38f42e966 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
@@ -102,6 +102,6 @@ public class MatrixRestore extends PaintOperation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME);
+ serializer.addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
index 9c4df0b54d60..5990b4bdfad7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
@@ -114,6 +114,6 @@ public class MatrixRotate extends DrawBase3 {
@Override
public void serialize(MapSerializer serializer) {
- serialize(serializer, "rotate", "pivotX", "pivotY").add("type", CLASS_NAME);
+ serialize(serializer, "rotate", "pivotX", "pivotY").addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
index 0e6de0db3b28..06da1565bf3a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
@@ -100,6 +100,6 @@ public class MatrixSave extends PaintOperation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME);
+ serializer.addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
index b6e5cbcf388a..20d406569223 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
@@ -106,6 +106,6 @@ public class MatrixScale extends DrawBase4 {
@Override
public void serialize(MapSerializer serializer) {
- serialize(serializer, "scaleX", "scaleY", "pivotX", "pivotY").add("type", CLASS_NAME);
+ serialize(serializer, "scaleX", "scaleY", "pivotX", "pivotY").addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java
index f9a589c598aa..6d1c503c3284 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java
@@ -103,6 +103,6 @@ public class MatrixSkew extends DrawBase2 {
@Override
public void serialize(MapSerializer serializer) {
- serialize(serializer, "skewX", "skewY").add("type", CLASS_NAME);
+ serialize(serializer, "skewX", "skewY").addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
index de783bfc7ae8..e21f13355679 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
@@ -102,6 +102,6 @@ public class MatrixTranslate extends DrawBase2 {
@Override
public void serialize(MapSerializer serializer) {
- serialize(serializer, "dx", "dy").add("type", CLASS_NAME);
+ serialize(serializer, "dx", "dy").addType(CLASS_NAME);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
index 96628fd51225..9a880858b5a5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
@@ -25,7 +25,6 @@ import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
-import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import com.android.internal.widget.remotecompose.core.serialize.Serializable;
@@ -43,6 +42,8 @@ public class NamedVariable extends Operation implements Serializable {
public static final int FLOAT_TYPE = 1;
public static final int STRING_TYPE = 0;
public static final int IMAGE_TYPE = 3;
+ public static final int INT_TYPE = 4;
+ public static final int LONG_TYPE = 5;
public NamedVariable(int varId, int varType, @NonNull String name) {
this.mVarId = varId;
@@ -122,7 +123,7 @@ public class NamedVariable extends Operation implements Serializable {
public static void documentation(@NonNull DocumentationBuilder doc) {
doc.operation("Data Operations", OP_CODE, CLASS_NAME)
.description("Add a string name for an ID")
- .field(DocumentedOperation.INT, "varId", "id to label")
+ .field(INT, "varId", "id to label")
.field(INT, "varType", "The type of variable")
.field(UTF8, "name", "String");
}
@@ -141,7 +142,7 @@ public class NamedVariable extends Operation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("varId", mVarId)
.add("varName", mVarName)
.add("varType", typeToString());
@@ -157,6 +158,8 @@ public class NamedVariable extends Operation implements Serializable {
return "STRING_TYPE";
case IMAGE_TYPE:
return "IMAGE_TYPE";
+ case INT_TYPE:
+ return "INT_TYPE";
default:
return "INVALID_TYPE";
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
index 8389aa707ee6..70197c6d085d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
@@ -131,6 +131,6 @@ public class PaintData extends PaintOperation implements VariableSupport, Serial
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("paintBundle", mPaintData);
+ serializer.addType(CLASS_NAME).add("paintBundle", mPaintData);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesLoop.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesLoop.java
index 8d19c94df604..f9fdfdf09e35 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesLoop.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesLoop.java
@@ -33,6 +33,7 @@ import com.android.internal.widget.remotecompose.core.documentation.DocumentedOp
import com.android.internal.widget.remotecompose.core.operations.layout.Container;
import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression;
import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.ArrayList;
import java.util.List;
@@ -292,4 +293,9 @@ public class ParticlesLoop extends PaintOperation implements VariableSupport, Co
}
}
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.addType(CLASS_NAME).add("id", mId);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
index 8f353ce4a26b..8a747e134897 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
@@ -258,9 +258,6 @@ public class PathAppend extends PaintOperation implements VariableSupport, Seria
@Override
public void serialize(MapSerializer serializer) {
- serializer
- .add("type", CLASS_NAME)
- .add("id", mInstanceId)
- .add("path", pathString(mFloatPath));
+ serializer.addType(CLASS_NAME).add("id", mInstanceId).add("path", pathString(mFloatPath));
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
index 7aa3390b53ee..78e3b9eac110 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
@@ -242,9 +242,6 @@ public class PathCreate extends PaintOperation implements VariableSupport, Seria
@Override
public void serialize(MapSerializer serializer) {
- serializer
- .add("type", CLASS_NAME)
- .add("id", mInstanceId)
- .add("path", pathString(mFloatPath));
+ serializer.addType(CLASS_NAME).add("id", mInstanceId).add("path", pathString(mFloatPath));
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
index 9564f15209c7..cedc4f3b0e45 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
@@ -243,9 +243,6 @@ public class PathData extends Operation implements VariableSupport, Serializable
@Override
public void serialize(MapSerializer serializer) {
- serializer
- .add("type", CLASS_NAME)
- .add("id", mInstanceId)
- .add("path", pathString(mFloatPath));
+ serializer.addType(CLASS_NAME).add("id", mInstanceId).add("path", pathString(mFloatPath));
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
index c5add57d4dd0..09b29e8c5e5c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
@@ -161,7 +161,7 @@ public class PathTween extends PaintOperation implements VariableSupport, Serial
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("outId", mOutId)
.add("pathId1", mPathId1)
.add("pathId2", mPathId2)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
index a6a8a810d2ad..214d240a39fd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
@@ -133,6 +133,6 @@ public class RootContentDescription extends Operation
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("contentDescriptionId", mContentDescription);
+ serializer.addType(CLASS_NAME).add("contentDescriptionId", mContentDescription);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
index 5f6162b68e9e..013b6f64b91a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
@@ -390,7 +390,7 @@ public class ShaderData extends Operation implements VariableSupport, Serializab
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("shaderTextId", mShaderTextId)
.add("shaderID", mShaderID)
.add("uniformRawFloatMap", mUniformRawFloatMap)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java
index 3e72995de9db..36f25c6ce944 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java
@@ -173,7 +173,7 @@ public class TextAttribute extends PaintOperation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("id", mId)
.add("textId", mTextId)
.add("measureType", typeToString());
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
index 419e6d074479..67773d1d6187 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
@@ -136,6 +136,6 @@ public class TextData extends Operation implements SerializableToString, Seriali
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("textId", mTextId).add("text", mText);
+ serializer.addType(CLASS_NAME).add("textId", mTextId).add("text", mText);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
index 6b2f49be76f0..f22369f51ce9 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
@@ -215,7 +215,7 @@ public class TextFromFloat extends Operation implements VariableSupport, Seriali
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("textId", mTextId)
.add("value", mValue, mOutValue)
.add("digitsBefore", mDigitsBefore)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
index e8865c26db12..fa44bf165cd7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
@@ -156,7 +156,7 @@ public class TextLookup extends Operation implements VariableSupport, Serializab
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("textId", mTextId)
.add("dataSetId", mDataSetId)
.add("indexId", mIndex, mOutIndex);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
index de2025569d46..5ec3290c445d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
@@ -149,7 +149,7 @@ public class TextLookupInt extends Operation implements VariableSupport, Seriali
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("textId", mTextId)
.add("dataSetId", mDataSetId)
.add("indexId", mIndex, mOutIndex);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java
index 58cd68e2a5db..3559d1dbe53b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java
@@ -27,6 +27,7 @@ import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.List;
@@ -161,4 +162,33 @@ public class TextMeasure extends PaintOperation {
break;
}
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("id", mId)
+ .add("textId", mTextId)
+ .add("measureType", typeToString());
+ }
+
+ private String typeToString() {
+ int val = mType & 255;
+ switch (val) {
+ case MEASURE_WIDTH:
+ return "MEASURE_WIDTH";
+ case MEASURE_HEIGHT:
+ return "MEASURE_HEIGHT";
+ case MEASURE_LEFT:
+ return "MEASURE_LEFT";
+ case MEASURE_TOP:
+ return "MEASURE_TOP";
+ case MEASURE_RIGHT:
+ return "MEASURE_RIGHT";
+ case MEASURE_BOTTOM:
+ return "MEASURE_BOTTOM";
+ default:
+ return "INVALID_TYPE";
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
index 262916dd9d0c..1239b5648446 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
@@ -132,7 +132,7 @@ public class TextMerge extends Operation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("id", mTextId)
.add("leftId", mSrcId1)
.add("rightId", mSrcId2);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java
index afb84b56d7b0..fd9a2bf5e435 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java
@@ -27,12 +27,14 @@ import com.android.internal.widget.remotecompose.core.PaintOperation;
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import com.android.internal.widget.remotecompose.core.types.LongConstant;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
/** Operation to perform time related calculation */
@@ -292,4 +294,48 @@ public class TimeAttribute extends PaintOperation {
break;
}
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("id", mId)
+ .add("timeId", mTimeId)
+ .addType(getTypeString())
+ .add("args", Collections.singletonList(mArgs));
+ }
+
+ private String getTypeString() {
+ int val = mType & 255;
+ switch (val) {
+ case TIME_FROM_NOW_SEC:
+ return "TIME_FROM_NOW_SEC";
+ case TIME_FROM_NOW_MIN:
+ return "TIME_FROM_NOW_MIN";
+ case TIME_FROM_NOW_HR:
+ return "TIME_FROM_NOW_HR";
+ case TIME_FROM_ARG_SEC:
+ return "TIME_FROM_ARG_SEC";
+ case TIME_FROM_ARG_MIN:
+ return "TIME_FROM_ARG_MIN";
+ case TIME_FROM_ARG_HR:
+ return "TIME_FROM_ARG_HR";
+ case TIME_IN_SEC:
+ return "TIME_IN_SEC";
+ case TIME_IN_MIN:
+ return "TIME_IN_MIN";
+ case TIME_IN_HR:
+ return "TIME_IN_HR";
+ case TIME_DAY_OF_MONTH:
+ return "TIME_DAY_OF_MONTH";
+ case TIME_MONTH_VALUE:
+ return "TIME_MONTH_VALUE";
+ case TIME_DAY_OF_WEEK:
+ return "TIME_DAY_OF_WEEK";
+ case TIME_YEAR:
+ return "TIME_YEAR";
+ default:
+ return "INVALID_TIME_TYPE";
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
index 2591a4c39778..f24672922367 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
@@ -716,9 +716,9 @@ public class TouchExpression extends Operation
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("id", mId)
- .add("mDefValue", mDefValue, mOutDefValue)
+ .add("defValue", mDefValue, mOutDefValue)
.add("min", mMin, mOutMin)
.add("max", mMax, mOutMax)
.add("mode", mMode)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java
index 9dc2a49d26ef..b98a017addb3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java
@@ -129,6 +129,6 @@ public class AnimatableValue implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", "AnimatableValue").add("id", mId);
+ serializer.addType("AnimatableValue").add("id", mId);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java
index 3e7f1d304315..25a10ab7dbeb 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java
@@ -156,7 +156,7 @@ public class CanvasOperations extends PaintOperation
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("list", mList);
+ serializer.addType(CLASS_NAME).add("list", mList);
}
/**
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
index 8b13c13a3333..7ee14903ced5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
@@ -253,6 +253,6 @@ public class ClickModifierOperation extends PaintOperation
@Override
public void serialize(MapSerializer serializer) {
- serializer.addTags(SerializeTags.MODIFIER).add("type", "ClickModifierOperation");
+ serializer.addTags(SerializeTags.MODIFIER).addType("ClickModifierOperation");
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
index c73643682b55..b30dade828a7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
@@ -57,8 +57,8 @@ public class Component extends PaintOperation
protected float mHeight;
@Nullable protected Component mParent;
protected int mAnimationId = -1;
- @NonNull public Visibility mVisibility = Visibility.VISIBLE;
- @NonNull public Visibility mScheduledVisibility = Visibility.VISIBLE;
+ public int mVisibility = Visibility.VISIBLE;
+ public int mScheduledVisibility = Visibility.VISIBLE;
@NonNull public ArrayList<Operation> mList = new ArrayList<>();
public PaintOperation mPreTranslate; // todo, can we initialize this here and make it NonNull?
public boolean mNeedsMeasure = true;
@@ -288,22 +288,42 @@ public class Component extends PaintOperation
}
/**
- * Returns the intrinsic width of the layout
+ * Returns the min intrinsic width of the layout
*
* @param context
* @return the width in pixels
*/
- public float intrinsicWidth(@Nullable RemoteContext context) {
+ public float minIntrinsicWidth(@Nullable RemoteContext context) {
return getWidth();
}
/**
- * Returns the intrinsic height of the layout
+ * Returns the max intrinsic width of the layout
+ *
+ * @param context
+ * @return the width in pixels
+ */
+ public float maxIntrinsicWidth(@Nullable RemoteContext context) {
+ return getWidth();
+ }
+
+ /**
+ * Returns the min intrinsic height of the layout
+ *
+ * @param context
+ * @return the height in pixels
+ */
+ public float minIntrinsicHeight(@Nullable RemoteContext context) {
+ return getHeight();
+ }
+
+ /**
+ * Returns the max intrinsic height of the layout
*
* @param context
* @return the height in pixels
*/
- public float intrinsicHeight(@Nullable RemoteContext context) {
+ public float maxIntrinsicHeight(@Nullable RemoteContext context) {
return getHeight();
}
@@ -338,10 +358,119 @@ public class Component extends PaintOperation
// Nothing here
}
- public enum Visibility {
- GONE,
- VISIBLE,
- INVISIBLE
+ public static class Visibility {
+
+ public static final int GONE = 0;
+ public static final int VISIBLE = 1;
+ public static final int INVISIBLE = 2;
+ public static final int OVERRIDE_GONE = 16;
+ public static final int OVERRIDE_VISIBLE = 32;
+ public static final int OVERRIDE_INVISIBLE = 64;
+ public static final int CLEAR_OVERRIDE = 128;
+
+ /**
+ * Returns a string representation of the field
+ *
+ * @param value
+ * @return
+ */
+ public static String toString(int value) {
+ switch (value) {
+ case GONE:
+ return "GONE";
+ case VISIBLE:
+ return "VISIBLE";
+ case INVISIBLE:
+ return "INVISIBLE";
+ }
+ if ((value >> 4) > 0) {
+ if ((value & OVERRIDE_GONE) == OVERRIDE_GONE) {
+ return "OVERRIDE_GONE";
+ }
+ if ((value & OVERRIDE_VISIBLE) == OVERRIDE_VISIBLE) {
+ return "OVERRIDE_VISIBLE";
+ }
+ if ((value & OVERRIDE_INVISIBLE) == OVERRIDE_INVISIBLE) {
+ return "OVERRIDE_INVISIBLE";
+ }
+ }
+ return "" + value;
+ }
+
+ /**
+ * Returns true if gone
+ *
+ * @param value
+ * @return
+ */
+ public static boolean isGone(int value) {
+ if ((value >> 4) > 0) {
+ return (value & OVERRIDE_GONE) == OVERRIDE_GONE;
+ }
+ return value == GONE;
+ }
+
+ /**
+ * Returns true if visible
+ *
+ * @param value
+ * @return
+ */
+ public static boolean isVisible(int value) {
+ if ((value >> 4) > 0) {
+ return (value & OVERRIDE_VISIBLE) == OVERRIDE_VISIBLE;
+ }
+ return value == VISIBLE;
+ }
+
+ /**
+ * Returns true if invisible
+ *
+ * @param value
+ * @return
+ */
+ public static boolean isInvisible(int value) {
+ if ((value >> 4) > 0) {
+ return (value & OVERRIDE_INVISIBLE) == OVERRIDE_INVISIBLE;
+ }
+ return value == INVISIBLE;
+ }
+
+ /**
+ * Returns true if the field has an override
+ *
+ * @param value
+ * @return
+ */
+ public static boolean hasOverride(int value) {
+ return (value >> 4) > 0;
+ }
+
+ /**
+ * Clear the override values
+ *
+ * @param value
+ * @return
+ */
+ public static int clearOverride(int value) {
+ return value & 15;
+ }
+
+ /**
+ * Add an override value
+ *
+ * @param value
+ * @param visibility
+ * @return
+ */
+ public static int add(int value, int visibility) {
+ int v = value & 15;
+ v += visibility;
+ if ((v & CLEAR_OVERRIDE) == CLEAR_OVERRIDE) {
+ v = v & 15;
+ }
+ return v;
+ }
}
/**
@@ -350,13 +479,28 @@ public class Component extends PaintOperation
* @return
*/
public boolean isVisible() {
- if (mVisibility != Visibility.VISIBLE || mParent == null) {
- return mVisibility == Visibility.VISIBLE;
- }
- if (mParent != null) { // TODO: this is always true -- bbade@
- return mParent.isVisible();
+ if (mParent == null || !Visibility.isVisible(mVisibility)) {
+ return Visibility.isVisible(mVisibility);
}
- return true;
+ return mParent.isVisible();
+ }
+
+ /**
+ * Returns true if the component is gone
+ *
+ * @return
+ */
+ public boolean isGone() {
+ return Visibility.isGone(mVisibility);
+ }
+
+ /**
+ * Returns true if the component is invisible
+ *
+ * @return
+ */
+ public boolean isInvisible() {
+ return Visibility.isInvisible(mVisibility);
}
/**
@@ -364,7 +508,7 @@ public class Component extends PaintOperation
*
* @param visibility can be VISIBLE, INVISIBLE or GONE
*/
- public void setVisibility(@NonNull Visibility visibility) {
+ public void setVisibility(int visibility) {
if (visibility != mVisibility || visibility != mScheduledVisibility) {
mScheduledVisibility = visibility;
invalidateMeasure();
@@ -705,7 +849,7 @@ public class Component extends PaintOperation
+ "] "
+ textContent()
+ " Visibility ("
- + mVisibility
+ + Visibility.toString(mVisibility)
+ ") ";
}
@@ -732,7 +876,7 @@ public class Component extends PaintOperation
+ ", "
+ mHeight
+ "] "
- + mVisibility;
+ + Visibility.toString(mVisibility);
// + " [" + mNeedsMeasure + ", " + mNeedsRepaint + "]"
serializer.append(indent, content);
}
@@ -966,7 +1110,7 @@ public class Component extends PaintOperation
if (applyAnimationAsNeeded(context)) {
return;
}
- if (mVisibility == Visibility.GONE || mVisibility == Visibility.INVISIBLE) {
+ if (isGone() || isInvisible()) {
return;
}
paintingComponent(context);
@@ -1071,13 +1215,13 @@ public class Component extends PaintOperation
@Override
public void serialize(MapSerializer serializer) {
serializer.addTags(SerializeTags.COMPONENT);
- serializer.add("type", getSerializedName());
+ serializer.addType(getSerializedName());
serializer.add("id", mComponentId);
serializer.add("x", mX);
serializer.add("y", mY);
serializer.add("width", mWidth);
serializer.add("height", mHeight);
- serializer.add("visibility", mVisibility);
+ serializer.add("visibility", Visibility.toString(mVisibility));
serializer.add("list", mList);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java
index e277d49325be..0e629c5d2448 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java
@@ -27,6 +27,7 @@ import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.Utils;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import java.util.ArrayList;
import java.util.List;
@@ -228,4 +229,12 @@ public class ImpulseOperation extends PaintOperation implements VariableSupport,
public void setProcess(ImpulseProcess impulseProcess) {
mProcess = impulseProcess;
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("duration", mDuration, mOutDuration)
+ .add("startAt", mStartAt, mOutStartAt);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java
index 8c9dd76c9ed5..83d4d38be66e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java
@@ -157,6 +157,6 @@ public class ImpulseProcess extends PaintOperation
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("list", mList);
+ serializer.addType(CLASS_NAME).add("list", mList);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
index 2b63cf246555..dda328f57a3b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
@@ -206,12 +206,12 @@ public class LoopOperation extends PaintOperation
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("indexVariableId", mIndexVariableId)
.add("until", mUntil, mUntilOut)
.add("from", mFrom, mFromOut)
.add("step", mStep, mStepOut)
- .add("mUntilOut", mUntilOut)
+ .add("untilOut", mUntilOut)
.add("list", mList);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
index f2503b26513e..77d3dae74558 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
@@ -77,7 +77,7 @@ public class RootLayoutComponent extends Component {
+ " x "
+ mHeight
+ ") "
- + mVisibility;
+ + Visibility.toString(mVisibility);
}
@Override
@@ -97,7 +97,7 @@ public class RootLayoutComponent extends Component {
+ ", "
+ mHeight
+ "] "
- + mVisibility);
+ + Visibility.toString(mVisibility));
}
/**
@@ -282,6 +282,6 @@ public class RootLayoutComponent extends Component {
public void serialize(MapSerializer serializer) {
super.serialize(serializer);
serializer.addTags(SerializeTags.COMPONENT);
- serializer.add("type", "RootLayoutComponent");
+ serializer.addType("RootLayoutComponent");
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
index 62b1b6cf9615..283bc7a45f85 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
@@ -129,6 +129,6 @@ public class TouchCancelModifierOperation extends ListActionsOperation implement
@Override
public void serialize(MapSerializer serializer) {
super.serialize(serializer);
- serializer.add("type", "TouchCancelModifierOperation");
+ serializer.addType("TouchCancelModifierOperation");
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java
index 5289fda2c74b..b010c148d122 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java
@@ -131,6 +131,6 @@ public class TouchDownModifierOperation extends ListActionsOperation implements
@Override
public void serialize(MapSerializer serializer) {
super.serialize(serializer);
- serializer.add("type", "TouchDownModifierOperation");
+ serializer.addType("TouchDownModifierOperation");
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java
index 576c5e9281a4..bc5c10b86c96 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java
@@ -129,6 +129,6 @@ public class TouchUpModifierOperation extends ListActionsOperation implements To
@Override
public void serialize(MapSerializer serializer) {
super.serialize(serializer);
- serializer.add("type", "TouchUpModifierOperation");
+ serializer.addType("TouchUpModifierOperation");
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java
index e5cd485967e8..1a60451ddd3b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java
@@ -143,7 +143,7 @@ public class AnimateMeasure {
*/
public void paint(@NonNull PaintContext context) {
if (mOriginal.getVisibility() != mTarget.getVisibility()) {
- if (mTarget.getVisibility() == Component.Visibility.GONE) {
+ if (mTarget.isGone()) {
switch (mExitAnimation) {
case PARTICLE:
// particleAnimation(context, component, original, target, vp)
@@ -229,8 +229,7 @@ public class AnimateMeasure {
mParticleAnimation.animate(context, mComponent, mOriginal, mTarget, mVp);
break;
}
- } else if (mOriginal.getVisibility() == Component.Visibility.GONE
- && mTarget.getVisibility() == Component.Visibility.VISIBLE) {
+ } else if (mOriginal.isGone() && mTarget.isVisible()) {
switch (mEnterAnimation) {
case ROTATE:
float px = mTarget.getX() + mTarget.getW() / 2f;
@@ -323,7 +322,7 @@ public class AnimateMeasure {
} else {
mComponent.paintingComponent(context);
}
- } else if (mTarget.getVisibility() == Component.Visibility.VISIBLE) {
+ } else if (mTarget.isVisible()) {
mComponent.paintingComponent(context);
}
@@ -360,7 +359,7 @@ public class AnimateMeasure {
public float getVisibility() {
if (mOriginal.getVisibility() == mTarget.getVisibility()) {
return 1f;
- } else if (mTarget.getVisibility() == Component.Visibility.VISIBLE) {
+ } else if (mTarget.isVisible()) {
return mVp;
} else {
return 1 - mVp;
@@ -382,7 +381,7 @@ public class AnimateMeasure {
float targetY = mTarget.getY();
float targetW = mTarget.getW();
float targetH = mTarget.getH();
- Component.Visibility targetVisibility = mTarget.getVisibility();
+ int targetVisibility = mTarget.getVisibility();
if (targetX != measure.getX()
|| targetY != measure.getY()
|| targetW != measure.getW()
@@ -393,7 +392,13 @@ public class AnimateMeasure {
mTarget.setW(measure.getW());
mTarget.setH(measure.getH());
mTarget.setVisibility(measure.getVisibility());
- mStartTime = currentTime;
+ // We shouldn't reset the leftover animation time here
+ // 1/ if we are eg fading out a component, and an updateTarget comes on, we don't want
+ // to restart the full animation time
+ // 2/ if no visibility change but quick updates come in (eg live resize) it seems
+ // better as well to not restart the animation time and only allows the original
+ // time to wrap up
+ // mStartTime = currentTime;
}
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
index 91348f5810a1..c87bbdc9809d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
@@ -129,7 +129,7 @@ public class AnimationSpec extends Operation implements ModifierOperation {
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", "AnimationSpec")
+ .addType("AnimationSpec")
.add("motionDuration", getMotionDuration())
.add("motionEasingType", Easing.getString(getMotionEasingType()))
.add("visibilityDuration", getVisibilityDuration())
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
index 35d639e65385..6ee18bbbd7e0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
@@ -115,8 +115,10 @@ public class BoxLayout extends LayoutManager {
for (Component c : mChildrenComponents) {
c.measure(context, 0f, maxWidth, 0f, maxHeight, measure);
ComponentMeasure m = measure.get(c);
- size.setWidth(Math.max(size.getWidth(), m.getW()));
- size.setHeight(Math.max(size.getHeight(), m.getH()));
+ if (!m.isGone()) {
+ size.setWidth(Math.max(size.getWidth(), m.getW()));
+ size.setHeight(Math.max(size.getHeight(), m.getH()));
+ }
}
// add padding
size.setWidth(Math.max(size.getWidth(), computeModifierDefinedWidth(context.getContext())));
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
index 508b685b5407..f9111dffe2c4 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
@@ -154,7 +154,7 @@ public class CanvasLayout extends BoxLayout {
@Override
public void serialize(MapSerializer serializer) {
super.serialize(serializer);
- serializer.add("type", getSerializedName());
+ serializer.addType(getSerializedName());
serializer.add("horizontalPositioning", mHorizontalPositioning);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleColumnLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleColumnLayout.java
index afc41b1873ef..b0089525af5a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleColumnLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleColumnLayout.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure;
@@ -134,6 +135,24 @@ public class CollapsibleColumnLayout extends ColumnLayout {
}
@Override
+ public float minIntrinsicHeight(@NonNull RemoteContext context) {
+ float height = computeModifierDefinedHeight(context);
+ if (!mChildrenComponents.isEmpty()) {
+ height += mChildrenComponents.get(0).minIntrinsicHeight(context);
+ }
+ return height;
+ }
+
+ @Override
+ public float minIntrinsicWidth(@NonNull RemoteContext context) {
+ float width = computeModifierDefinedWidth(context);
+ if (!mChildrenComponents.isEmpty()) {
+ width += mChildrenComponents.get(0).minIntrinsicWidth(context);
+ }
+ return width;
+ }
+
+ @Override
protected boolean hasVerticalIntrinsicDimension() {
return true;
}
@@ -147,29 +166,54 @@ public class CollapsibleColumnLayout extends ColumnLayout {
boolean verticalWrap,
@NonNull MeasurePass measure,
@NonNull Size size) {
- super.computeWrapSize(
- context, maxWidth, Float.MAX_VALUE, horizontalWrap, verticalWrap, measure, size);
- }
+ int visibleChildren = 0;
+ ComponentMeasure self = measure.get(this);
+ self.addVisibilityOverride(Visibility.OVERRIDE_VISIBLE);
+ float currentMaxHeight = maxHeight;
+ for (Component c : mChildrenComponents) {
+ if (c instanceof CollapsibleColumnLayout) {
+ c.measure(context, 0f, maxWidth, 0f, currentMaxHeight, measure);
+ } else {
+ c.measure(context, 0f, maxWidth, 0f, Float.MAX_VALUE, measure);
+ }
+ ComponentMeasure m = measure.get(c);
+ if (!m.isGone()) {
+ size.setWidth(Math.max(size.getWidth(), m.getW()));
+ size.setHeight(size.getHeight() + m.getH());
+ visibleChildren++;
+ currentMaxHeight -= m.getH();
+ }
+ }
+ if (!mChildrenComponents.isEmpty()) {
+ size.setHeight(size.getHeight() + (mSpacedBy * (visibleChildren - 1)));
+ }
- @Override
- public boolean applyVisibility(
- float selfWidth, float selfHeight, @NonNull MeasurePass measure) {
float childrenWidth = 0f;
float childrenHeight = 0f;
- boolean changedVisibility = false;
+
+ boolean overflow = false;
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (overflow || childMeasure.isGone()) {
+ childMeasure.addVisibilityOverride(Visibility.OVERRIDE_GONE);
continue;
}
- if (childrenHeight + childMeasure.getH() > selfHeight) {
- childMeasure.setVisibility(Visibility.GONE);
- changedVisibility = true;
+ float childHeight = childMeasure.getH();
+ boolean childDoesNotFits = childrenHeight + childHeight > maxHeight;
+ if (childDoesNotFits) {
+ childMeasure.addVisibilityOverride(Visibility.OVERRIDE_GONE);
+ overflow = true;
} else {
- childrenHeight += childMeasure.getH();
+ childrenHeight += childHeight;
childrenWidth = Math.max(childrenWidth, childMeasure.getW());
+ visibleChildren++;
}
}
- return changedVisibility;
+ if (verticalWrap) {
+ size.setHeight(Math.min(maxHeight, childrenHeight));
+ }
+ if (visibleChildren == 0 || size.getHeight() <= 0f) {
+ self.addVisibilityOverride(Visibility.OVERRIDE_GONE);
+ }
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleRowLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleRowLayout.java
index 0e7eb8676f46..05f332960c16 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleRowLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CollapsibleRowLayout.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure;
@@ -139,6 +140,24 @@ public class CollapsibleRowLayout extends RowLayout {
}
@Override
+ public float minIntrinsicWidth(@NonNull RemoteContext context) {
+ float width = computeModifierDefinedWidth(context);
+ if (!mChildrenComponents.isEmpty()) {
+ width += mChildrenComponents.get(0).minIntrinsicWidth(context);
+ }
+ return width;
+ }
+
+ @Override
+ public float minIntrinsicHeight(@NonNull RemoteContext context) {
+ float height = computeModifierDefinedHeight(context);
+ if (!mChildrenComponents.isEmpty()) {
+ height += mChildrenComponents.get(0).minIntrinsicHeight(context);
+ }
+ return height;
+ }
+
+ @Override
public void computeWrapSize(
@NonNull PaintContext context,
float maxWidth,
@@ -157,19 +176,35 @@ public class CollapsibleRowLayout extends RowLayout {
float childrenWidth = 0f;
float childrenHeight = 0f;
boolean changedVisibility = false;
+ int visibleChildren = 0;
+ ComponentMeasure self = measure.get(this);
+ self.clearVisibilityOverride();
+ if (selfWidth <= 0 || selfHeight <= 0) {
+ self.addVisibilityOverride(Visibility.OVERRIDE_GONE);
+ return true;
+ }
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ int visibility = childMeasure.getVisibility();
+ childMeasure.clearVisibilityOverride();
+ if (!childMeasure.isVisible()) {
continue;
}
- if (childrenWidth + childMeasure.getW() > selfWidth) {
- childMeasure.setVisibility(Visibility.GONE);
- changedVisibility = true;
+ if (childrenWidth + childMeasure.getW() > selfWidth
+ && childrenHeight + childMeasure.getH() > selfHeight) {
+ childMeasure.addVisibilityOverride(Visibility.OVERRIDE_GONE);
+ if (visibility != childMeasure.getVisibility()) {
+ changedVisibility = true;
+ }
} else {
childrenWidth += childMeasure.getW();
childrenHeight = Math.max(childrenHeight, childMeasure.getH());
+ visibleChildren++;
}
}
+ if (visibleChildren == 0) {
+ self.addVisibilityOverride(Visibility.OVERRIDE_GONE);
+ }
return changedVisibility;
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
index 47a55b6ed82a..cda90c2d3b0b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
@@ -138,7 +138,7 @@ public class ColumnLayout extends LayoutManager {
for (Component c : mChildrenComponents) {
c.measure(context, 0f, maxWidth, 0f, currentMaxHeight, measure);
ComponentMeasure m = measure.get(c);
- if (m.getVisibility() != Visibility.GONE) {
+ if (!m.isGone()) {
size.setWidth(Math.max(size.getWidth(), m.getW()));
size.setHeight(size.getHeight() + m.getH());
visibleChildrens++;
@@ -164,7 +164,7 @@ public class ColumnLayout extends LayoutManager {
for (Component child : mChildrenComponents) {
child.measure(context, minWidth, maxWidth, minHeight, mh, measure);
ComponentMeasure m = measure.get(child);
- if (m.getVisibility() != Visibility.GONE) {
+ if (!m.isGone()) {
mh -= m.getH();
}
}
@@ -172,11 +172,11 @@ public class ColumnLayout extends LayoutManager {
}
@Override
- public float intrinsicHeight(@NonNull RemoteContext context) {
+ public float minIntrinsicHeight(@NonNull RemoteContext context) {
float height = computeModifierDefinedHeight(context);
float componentHeights = 0f;
for (Component c : mChildrenComponents) {
- componentHeights += c.intrinsicHeight(context);
+ componentHeights += c.minIntrinsicHeight(context);
}
return Math.max(height, componentHeights);
}
@@ -225,7 +225,7 @@ public class ColumnLayout extends LayoutManager {
float totalWeights = 0f;
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
if (child instanceof LayoutComponent
@@ -242,7 +242,7 @@ public class ColumnLayout extends LayoutManager {
if (child instanceof LayoutComponent
&& ((LayoutComponent) child).getHeightModifier().hasWeight()) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
float weight = ((LayoutComponent) child).getHeightModifier().getValue();
@@ -280,7 +280,7 @@ public class ColumnLayout extends LayoutManager {
int visibleChildrens = 0;
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
childrenWidth = Math.max(childrenWidth, childMeasure.getW());
@@ -307,17 +307,22 @@ public class ColumnLayout extends LayoutManager {
case SPACE_BETWEEN:
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
total += childMeasure.getH();
}
- verticalGap = (selfHeight - total) / (visibleChildrens - 1);
+ if (visibleChildrens > 1) {
+ verticalGap = (selfHeight - total) / (visibleChildrens - 1);
+ } else {
+ // we center the element
+ ty = (selfHeight - childrenHeight) / 2f;
+ }
break;
case SPACE_EVENLY:
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
total += childMeasure.getH();
@@ -328,7 +333,7 @@ public class ColumnLayout extends LayoutManager {
case SPACE_AROUND:
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
total += childMeasure.getH();
@@ -353,7 +358,7 @@ public class ColumnLayout extends LayoutManager {
}
childMeasure.setX(tx);
childMeasure.setY(ty);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
ty += childMeasure.getH();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/FitBoxLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/FitBoxLayout.java
new file mode 100644
index 000000000000..ff7a3af11f20
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/FitBoxLayout.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.layout.managers;
+
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent;
+import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure;
+import com.android.internal.widget.remotecompose.core.operations.layout.measure.MeasurePass;
+import com.android.internal.widget.remotecompose.core.operations.layout.measure.Size;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightInModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthInModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthModifierOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+
+import java.util.List;
+
+/** FitBox layout implementation -- only display the child that fits in the available space */
+public class FitBoxLayout extends LayoutManager {
+
+ public static final int START = 1;
+ public static final int CENTER = 2;
+ public static final int END = 3;
+ public static final int TOP = 4;
+ public static final int BOTTOM = 5;
+
+ int mHorizontalPositioning;
+ int mVerticalPositioning;
+
+ public FitBoxLayout(
+ @Nullable Component parent,
+ int componentId,
+ int animationId,
+ float x,
+ float y,
+ float width,
+ float height,
+ int horizontalPositioning,
+ int verticalPositioning) {
+ super(parent, componentId, animationId, x, y, width, height);
+ mHorizontalPositioning = horizontalPositioning;
+ mVerticalPositioning = verticalPositioning;
+ }
+
+ public FitBoxLayout(
+ @Nullable Component parent,
+ int componentId,
+ int animationId,
+ int horizontalPositioning,
+ int verticalPositioning) {
+ this(
+ parent,
+ componentId,
+ animationId,
+ 0,
+ 0,
+ 0,
+ 0,
+ horizontalPositioning,
+ verticalPositioning);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "BOX ["
+ + mComponentId
+ + ":"
+ + mAnimationId
+ + "] ("
+ + mX
+ + ", "
+ + mY
+ + " - "
+ + mWidth
+ + " x "
+ + mHeight
+ + ") "
+ + mVisibility;
+ }
+
+ @NonNull
+ @Override
+ protected String getSerializedName() {
+ return "FITBOX";
+ }
+
+ @Override
+ public void computeWrapSize(
+ @NonNull PaintContext context,
+ float maxWidth,
+ float maxHeight,
+ boolean horizontalWrap,
+ boolean verticalWrap,
+ @NonNull MeasurePass measure,
+ @NonNull Size size) {
+
+ boolean found = false;
+ ComponentMeasure self = measure.get(this);
+ for (Component c : mChildrenComponents) {
+ float cw = 0f; // c.intrinsicWidth(context.getContext());
+ float ch = 0f; // c.intrinsicHeight(context.getContext());
+ if (c instanceof LayoutComponent) {
+ LayoutComponent lc = (LayoutComponent) c;
+ WidthModifierOperation widthModifier = lc.getWidthModifier();
+ if (widthModifier != null) {
+ WidthInModifierOperation widthIn = lc.getWidthModifier().getWidthIn();
+ if (widthIn != null) {
+ cw = widthIn.getMin();
+ }
+ }
+ HeightModifierOperation heightModifier = lc.getHeightModifier();
+ if (heightModifier != null) {
+ HeightInModifierOperation heightIn = lc.getHeightModifier().getHeightIn();
+ if (heightIn != null) {
+ ch = heightIn.getMin();
+ }
+ }
+ }
+ c.measure(context, 0f, maxWidth, 0f, maxHeight, measure);
+ ComponentMeasure m = measure.get(c);
+ if (!found && cw <= maxWidth && ch <= maxHeight) {
+ found = true;
+ m.addVisibilityOverride(Visibility.OVERRIDE_VISIBLE);
+ size.setWidth(m.getW());
+ size.setHeight(m.getH());
+ } else {
+ m.addVisibilityOverride(Visibility.OVERRIDE_GONE);
+ }
+ }
+ if (!found) {
+ self.setVisibility(Visibility.GONE);
+ } else {
+ self.setVisibility(Visibility.VISIBLE);
+ }
+
+ // add padding
+ size.setWidth(Math.max(size.getWidth(), computeModifierDefinedWidth(context.getContext())));
+ size.setHeight(
+ Math.max(size.getHeight(), computeModifierDefinedHeight(context.getContext())));
+ }
+
+ @Override
+ public void computeSize(
+ @NonNull PaintContext context,
+ float minWidth,
+ float maxWidth,
+ float minHeight,
+ float maxHeight,
+ @NonNull MeasurePass measure) {
+
+ ComponentMeasure self = measure.get(this);
+ boolean found = false;
+ for (Component c : mChildrenComponents) {
+ float cw = 0f;
+ float ch = 0f;
+ if (c instanceof LayoutComponent) {
+ LayoutComponent lc = (LayoutComponent) c;
+ WidthModifierOperation widthModifier = lc.getWidthModifier();
+ if (widthModifier != null) {
+ WidthInModifierOperation widthIn = lc.getWidthModifier().getWidthIn();
+ if (widthIn != null) {
+ cw = widthIn.getMin();
+ }
+ }
+ HeightModifierOperation heightModifier = lc.getHeightModifier();
+ if (heightModifier != null) {
+ HeightInModifierOperation heightIn = lc.getHeightModifier().getHeightIn();
+ if (heightIn != null) {
+ ch = heightIn.getMin();
+ }
+ }
+ }
+ c.measure(context, minWidth, maxWidth, minHeight, maxHeight, measure);
+ // child.measure(context, minWidth, Float.MAX_VALUE, minHeight,
+ // Float.MAX_VALUE, measure);
+ // m.getVisibility().clearOverride();
+ ComponentMeasure m = measure.get(c);
+ // m.setVisibility(Visibility.GONE);
+ // m.getVisibility().add(Visibility.OVERRIDE_GONE);
+ // m.getVisibility().add(Visibility.OVERRIDE_GONE);
+ m.clearVisibilityOverride();
+ if (!found && cw <= maxWidth && ch <= maxHeight) {
+ found = true;
+ m.addVisibilityOverride(Visibility.OVERRIDE_VISIBLE);
+ } else {
+ m.addVisibilityOverride(Visibility.OVERRIDE_GONE);
+ }
+ }
+ }
+
+ @Override
+ public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) {
+ ComponentMeasure selfMeasure = measure.get(this);
+ float selfWidth = selfMeasure.getW() - mPaddingLeft - mPaddingRight;
+ float selfHeight = selfMeasure.getH() - mPaddingTop - mPaddingBottom;
+ applyVisibility(selfWidth, selfHeight, measure);
+ for (Component child : mChildrenComponents) {
+ ComponentMeasure m = measure.get(child);
+ float tx = 0f;
+ float ty = 0f;
+ switch (mVerticalPositioning) {
+ case TOP:
+ ty = 0f;
+ break;
+ case CENTER:
+ ty = (selfHeight - m.getH()) / 2f;
+ break;
+ case BOTTOM:
+ ty = selfHeight - m.getH();
+ break;
+ }
+ switch (mHorizontalPositioning) {
+ case START:
+ tx = 0f;
+ break;
+ case CENTER:
+ tx = (selfWidth - m.getW()) / 2f;
+ break;
+ case END:
+ tx = selfWidth - m.getW();
+ break;
+ }
+ m.setX(tx);
+ m.setY(ty);
+ }
+ }
+
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
+ public static String name() {
+ return "BoxLayout";
+ }
+
+ /**
+ * The OP_CODE for this command
+ *
+ * @return the opcode
+ */
+ public static int id() {
+ return Operations.LAYOUT_FIT_BOX;
+ }
+
+ /**
+ * Write the operation to the buffer
+ *
+ * @param buffer a WireBuffer
+ * @param componentId the component id
+ * @param animationId the component animation id
+ * @param horizontalPositioning the horizontal positioning rules
+ * @param verticalPositioning the vertical positioning rules
+ */
+ public static void apply(
+ @NonNull WireBuffer buffer,
+ int componentId,
+ int animationId,
+ int horizontalPositioning,
+ int verticalPositioning) {
+ buffer.start(id());
+ buffer.writeInt(componentId);
+ buffer.writeInt(animationId);
+ buffer.writeInt(horizontalPositioning);
+ buffer.writeInt(verticalPositioning);
+ }
+
+ /**
+ * Read this operation and add it to the list of operations
+ *
+ * @param buffer the buffer to read
+ * @param operations the list of operations that will be added to
+ */
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+ int componentId = buffer.readInt();
+ int animationId = buffer.readInt();
+ int horizontalPositioning = buffer.readInt();
+ int verticalPositioning = buffer.readInt();
+ operations.add(
+ new FitBoxLayout(
+ null,
+ componentId,
+ animationId,
+ horizontalPositioning,
+ verticalPositioning));
+ }
+
+ /**
+ * Populate the documentation with a description of this operation
+ *
+ * @param doc to append the description to.
+ */
+ public static void documentation(@NonNull DocumentationBuilder doc) {
+ doc.operation("Layout Operations", id(), name())
+ .description(
+ "FitBox layout implementation.\n\n"
+ + "Only display the first child component that fits in the available"
+ + " space")
+ .examplesDimension(150, 100)
+ .exampleImage("Top", "layout-BoxLayout-start-top.png")
+ .exampleImage("Center", "layout-BoxLayout-center-center.png")
+ .exampleImage("Bottom", "layout-BoxLayout-end-bottom.png")
+ .field(INT, "COMPONENT_ID", "unique id for this component")
+ .field(
+ INT,
+ "ANIMATION_ID",
+ "id used to match components," + " for animation purposes")
+ .field(INT, "HORIZONTAL_POSITIONING", "horizontal positioning value")
+ .possibleValues("START", FitBoxLayout.START)
+ .possibleValues("CENTER", FitBoxLayout.CENTER)
+ .possibleValues("END", FitBoxLayout.END)
+ .field(INT, "VERTICAL_POSITIONING", "vertical positioning value")
+ .possibleValues("TOP", FitBoxLayout.TOP)
+ .possibleValues("CENTER", FitBoxLayout.CENTER)
+ .possibleValues("BOTTOM", FitBoxLayout.BOTTOM);
+ }
+
+ @Override
+ public void write(@NonNull WireBuffer buffer) {
+ apply(buffer, mComponentId, mAnimationId, mHorizontalPositioning, mVerticalPositioning);
+ }
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ super.serialize(serializer);
+ serializer.add("verticalPositioning", getPositioningString(mVerticalPositioning));
+ serializer.add("horizontalPositioning", getPositioningString(mHorizontalPositioning));
+ }
+
+ private String getPositioningString(int pos) {
+ switch (pos) {
+ case START:
+ return "START";
+ case CENTER:
+ return "CENTER";
+ case END:
+ return "END";
+ case TOP:
+ return "TOP";
+ case BOTTOM:
+ return "BOTTOM";
+ default:
+ return "NONE";
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
index 8b52bbe5cdf8..5b66b95cf1dd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
@@ -73,19 +73,19 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
}
@Override
- public float intrinsicHeight(@Nullable RemoteContext context) {
+ public float minIntrinsicHeight(@Nullable RemoteContext context) {
float height = computeModifierDefinedHeight(context);
for (Component c : mChildrenComponents) {
- height = Math.max(c.intrinsicHeight(context), height);
+ height = Math.max(c.minIntrinsicHeight(context), height);
}
return height;
}
@Override
- public float intrinsicWidth(@Nullable RemoteContext context) {
+ public float minIntrinsicWidth(@Nullable RemoteContext context) {
float width = computeModifierDefinedWidth(context);
for (Component c : mChildrenComponents) {
- width = Math.max(c.intrinsicWidth(context), width);
+ width = Math.max(c.minIntrinsicWidth(context), width);
}
return width;
}
@@ -149,10 +149,10 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
Math.min(maxHeight, computeModifierDefinedHeight(context.getContext()));
if (mWidthModifier.isIntrinsicMin()) {
- maxWidth = intrinsicWidth(context.getContext()) + mPaddingLeft + mPaddingRight;
+ maxWidth = minIntrinsicWidth(context.getContext()) + mPaddingLeft + mPaddingRight;
}
if (mHeightModifier.isIntrinsicMin()) {
- maxHeight = intrinsicHeight(context.getContext()) + mPaddingTop + mPaddingBottom;
+ maxHeight = minIntrinsicHeight(context.getContext()) + mPaddingTop + mPaddingBottom;
}
float insetMaxWidth = maxWidth - mPaddingLeft - mPaddingRight;
@@ -171,6 +171,11 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
mHeightModifier.isWrap(),
measure,
mCachedWrapSize);
+ int selfVisibilityAfterMeasure = measure.get(this).getVisibility();
+ if (Visibility.hasOverride(selfVisibilityAfterMeasure)
+ && mScheduledVisibility != selfVisibilityAfterMeasure) {
+ mScheduledVisibility = selfVisibilityAfterMeasure;
+ }
measuredWidth = mCachedWrapSize.getWidth();
if (hasHorizontalWrap) {
measuredWidth += mPaddingLeft + mPaddingRight;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
index e93cbd74b0b5..d5d2e03c3f2a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
@@ -136,7 +136,7 @@ public class RowLayout extends LayoutManager {
for (Component c : mChildrenComponents) {
c.measure(context, 0f, currentMaxWidth, 0f, maxHeight, measure);
ComponentMeasure m = measure.get(c);
- if (m.getVisibility() != Visibility.GONE) {
+ if (!m.isGone()) {
size.setWidth(size.getWidth() + m.getW());
size.setHeight(Math.max(size.getHeight(), m.getH()));
visibleChildrens++;
@@ -162,7 +162,7 @@ public class RowLayout extends LayoutManager {
for (Component child : mChildrenComponents) {
child.measure(context, minWidth, mw, minHeight, maxHeight, measure);
ComponentMeasure m = measure.get(child);
- if (m.getVisibility() != Visibility.GONE) {
+ if (!m.isGone()) {
mw -= m.getW();
}
}
@@ -170,16 +170,26 @@ public class RowLayout extends LayoutManager {
}
@Override
- public float intrinsicWidth(@Nullable RemoteContext context) {
+ public float minIntrinsicWidth(@Nullable RemoteContext context) {
float width = computeModifierDefinedWidth(context);
float componentWidths = 0f;
for (Component c : mChildrenComponents) {
- componentWidths += c.intrinsicWidth(context);
+ componentWidths += c.minIntrinsicWidth(context);
}
return Math.max(width, componentWidths);
}
@Override
+ public float minIntrinsicHeight(@Nullable RemoteContext context) {
+ float height = computeModifierDefinedHeight(context);
+ float componentHeights = 0f;
+ for (Component c : mChildrenComponents) {
+ componentHeights = Math.max(componentHeights, c.minIntrinsicHeight(context));
+ }
+ return Math.max(height, componentHeights);
+ }
+
+ @Override
public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) {
ComponentMeasure selfMeasure = measure.get(this);
DebugLog.s(
@@ -225,7 +235,7 @@ public class RowLayout extends LayoutManager {
float totalWeights = 0f;
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
if (child instanceof LayoutComponent
@@ -245,7 +255,7 @@ public class RowLayout extends LayoutManager {
if (child instanceof LayoutComponent
&& ((LayoutComponent) child).getWidthModifier().hasWeight()) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
float weight = ((LayoutComponent) child).getWidthModifier().getValue();
@@ -283,7 +293,7 @@ public class RowLayout extends LayoutManager {
int visibleChildrens = 0;
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
childrenWidth += childMeasure.getW();
@@ -311,17 +321,22 @@ public class RowLayout extends LayoutManager {
case SPACE_BETWEEN:
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
total += childMeasure.getW();
}
- horizontalGap = (selfWidth - total) / (visibleChildrens - 1);
+ if (visibleChildrens > 1) {
+ horizontalGap = (selfWidth - total) / (visibleChildrens - 1);
+ } else {
+ // we center the element
+ tx = (selfWidth - childrenWidth) / 2f;
+ }
break;
case SPACE_EVENLY:
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
total += childMeasure.getW();
@@ -332,7 +347,7 @@ public class RowLayout extends LayoutManager {
case SPACE_AROUND:
for (Component child : mChildrenComponents) {
ComponentMeasure childMeasure = measure.get(child);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
total += childMeasure.getW();
@@ -357,7 +372,7 @@ public class RowLayout extends LayoutManager {
}
childMeasure.setX(tx);
childMeasure.setY(ty);
- if (childMeasure.getVisibility() == Visibility.GONE) {
+ if (childMeasure.isGone()) {
continue;
}
tx += childMeasure.getW();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java
index ee16bc2f4459..0192d8438a75 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java
@@ -413,7 +413,7 @@ public class StateLayout extends LayoutManager {
if (index != currentLayoutIndex && index != previousLayoutIndex) {
pane.mVisibility = Visibility.GONE;
}
- if (index == currentLayoutIndex && pane.mVisibility != Visibility.VISIBLE) {
+ if (index == currentLayoutIndex && !pane.isVisible()) {
pane.mVisibility = Visibility.VISIBLE;
}
index++;
@@ -511,7 +511,7 @@ public class StateLayout extends LayoutManager {
&& previousLayout.mAnimateMeasure == null) {
inTransition = false;
LayoutManager previous = getLayout(previousLayoutIndex);
- if (previous != currentLayout && previous.mVisibility != Visibility.GONE) {
+ if (previous != currentLayout && !previous.isGone()) {
previous.mVisibility = Visibility.GONE;
previous.needsRepaint();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
index d5db74b5ca51..2595a71abaa5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
@@ -280,7 +280,7 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
+ " x "
+ mHeight
+ ") "
- + mVisibility;
+ + Visibility.toString(mVisibility);
}
@NonNull
@@ -308,7 +308,7 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
+ ", "
+ mHeight
+ "] "
- + mVisibility
+ + Visibility.toString(mVisibility)
+ " ("
+ mTextId
+ ":\""
@@ -343,7 +343,7 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
flags |= PaintContext.TEXT_COMPLEX;
}
context.getTextBounds(mTextId, 0, mCachedString.length(), flags, bounds);
- if (bounds[2] - bounds[1] > maxWidth && mMaxLines > 1) {
+ if (bounds[2] - bounds[1] > maxWidth && mMaxLines > 1 && maxWidth > 0f) {
mComputedTextLayout =
context.layoutComplexText(
mTextId,
@@ -375,12 +375,12 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
}
@Override
- public float intrinsicHeight(@Nullable RemoteContext context) {
+ public float minIntrinsicHeight(@Nullable RemoteContext context) {
return mTextH;
}
@Override
- public float intrinsicWidth(@Nullable RemoteContext context) {
+ public float minIntrinsicWidth(@Nullable RemoteContext context) {
return mTextW;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java
index 11ed9f435070..993441944c33 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java
@@ -26,7 +26,7 @@ public class ComponentMeasure {
float mY;
float mW;
float mH;
- @NonNull Component.Visibility mVisibility = Component.Visibility.VISIBLE;
+ int mVisibility = Component.Visibility.VISIBLE;
public void setX(float value) {
mX = value;
@@ -60,16 +60,15 @@ public class ComponentMeasure {
return mH;
}
- public @NonNull Component.Visibility getVisibility() {
+ public int getVisibility() {
return mVisibility;
}
- public void setVisibility(@NonNull Component.Visibility visibility) {
+ public void setVisibility(int visibility) {
mVisibility = visibility;
}
- public ComponentMeasure(
- int id, float x, float y, float w, float h, @NonNull Component.Visibility visibility) {
+ public ComponentMeasure(int id, float x, float y, float w, float h, int visibility) {
this.mId = id;
this.mX = x;
this.mY = y;
@@ -114,4 +113,42 @@ public class ComponentMeasure {
public boolean same(@NonNull ComponentMeasure m) {
return mX == m.mX && mY == m.mY && mW == m.mW && mH == m.mH && mVisibility == m.mVisibility;
}
+
+ /**
+ * Returns true if the component will be gone
+ *
+ * @return true if gone
+ */
+ public boolean isGone() {
+ return Component.Visibility.isGone(mVisibility);
+ }
+
+ /**
+ * Returns true if the component will be visible
+ *
+ * @return true if visible
+ */
+ public boolean isVisible() {
+ return Component.Visibility.isVisible(mVisibility);
+ }
+
+ /**
+ * Returns true if the component will be invisible
+ *
+ * @return true if invisible
+ */
+ public boolean isInvisible() {
+ return Component.Visibility.isInvisible(mVisibility);
+ }
+
+ /** Clear any override on the visibility */
+ public void clearVisibilityOverride() {
+ mVisibility = Component.Visibility.clearOverride(mVisibility);
+ }
+
+ /** Add a visibility override */
+ public void addVisibilityOverride(int value) {
+ mVisibility = Component.Visibility.clearOverride(mVisibility);
+ mVisibility = Component.Visibility.add(mVisibility, value);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
index fd5f8c9cdbe7..1ab0c3dc7fb8 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
@@ -228,7 +228,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "BackgroundModifierOperation")
+ .addType("BackgroundModifierOperation")
.add("x", mX)
.add("y", mY)
.add("width", mWidth)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
index e5f318307a75..656a3c0fca68 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
@@ -290,7 +290,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "BorderModifierOperation")
+ .addType("BorderModifierOperation")
.add("x", mX)
.add("y", mY)
.add("width", mWidth)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
index 00a53170fc48..e96dc838fc91 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
@@ -111,7 +111,7 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "ClipRectModifierOperation")
+ .addType("ClipRectModifierOperation")
.add("width", mWidth)
.add("height", mHeight);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java
index a9e342144cc5..14b2fad5825d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java
@@ -327,7 +327,7 @@ public class ComponentModifiers extends PaintOperation
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "ComponentModifiers")
+ .addType("ComponentModifiers")
.add("modifiers", mList);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
index fbf8a95248b9..88b28c39eec6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
@@ -41,7 +41,7 @@ public class ComponentVisibilityOperation extends Operation
private static final int OP_CODE = Operations.MODIFIER_VISIBILITY;
int mVisibilityId;
- @NonNull Component.Visibility mVisibility = Component.Visibility.VISIBLE;
+ int mVisibility = Component.Visibility.VISIBLE;
private LayoutComponent mParent;
public ComponentVisibilityOperation(int id) {
@@ -124,11 +124,11 @@ public class ComponentVisibilityOperation extends Operation
@Override
public void updateVariables(@NonNull RemoteContext context) {
int visibility = context.getInteger(mVisibilityId);
- if (visibility == Component.Visibility.VISIBLE.ordinal()) {
+ if (Component.Visibility.isVisible(visibility)) {
mVisibility = Component.Visibility.VISIBLE;
- } else if (visibility == Component.Visibility.GONE.ordinal()) {
+ } else if (Component.Visibility.isGone(visibility)) {
mVisibility = Component.Visibility.GONE;
- } else if (visibility == Component.Visibility.INVISIBLE.ordinal()) {
+ } else if (Component.Visibility.isInvisible(visibility)) {
mVisibility = Component.Visibility.INVISIBLE;
} else {
mVisibility = Component.Visibility.GONE;
@@ -150,8 +150,8 @@ public class ComponentVisibilityOperation extends Operation
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "ComponentVisibilityOperation")
+ .addType("ComponentVisibilityOperation")
.add("visibilityId", mVisibilityId)
- .add("visibility", mVisibility);
+ .add("visibility", Component.Visibility.toString(mVisibility));
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DrawContentOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DrawContentOperation.java
index d7abdbae4962..6beb13586163 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DrawContentOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DrawContentOperation.java
@@ -120,6 +120,6 @@ public class DrawContentOperation extends Operation
@Override
public void serialize(MapSerializer serializer) {
- serializer.addTags(SerializeTags.MODIFIER).add("type", "DrawContentOperation");
+ serializer.addTags(SerializeTags.MODIFIER).addType("DrawContentOperation");
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
index c1c1f9568ea8..361438b51a47 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
@@ -352,7 +352,7 @@ public class GraphicsLayerModifierOperation extends DecoratorModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "GraphicsLayerModifierOperation")
+ .addType("GraphicsLayerModifierOperation")
.add("scaleX", mScaleX)
.add("scaleX", mScaleX)
.add("rotationX", mRotationX)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightInModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightInModifierOperation.java
index 7f0dd8d8d8e5..9b63c034675a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightInModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightInModifierOperation.java
@@ -107,7 +107,7 @@ public class HeightInModifierOperation extends DimensionInModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "HeightInModifierOperation")
+ .addType("HeightInModifierOperation")
.add("min", mV1, mValue1)
.add("max", mV2, mValue2);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
index 1df84257f344..5fbaafca5759 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
@@ -143,7 +143,7 @@ public class HeightModifierOperation extends DimensionModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "HeightModifierOperation")
+ .addType("HeightModifierOperation")
.add("height", mValue, mOutValue)
.add("dimensionModifierType", mType);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
index 67714ef5abac..4d8acb4f04e2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
@@ -130,7 +130,7 @@ public class HostActionOperation extends Operation
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "HostActionOperation")
+ .addType("HostActionOperation")
.add("id", mActionId);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
index 40c13f143468..807ff68fa965 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
@@ -157,7 +157,7 @@ public class HostNamedActionOperation extends Operation implements ActionOperati
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "HostNamedActionOperation")
+ .addType("HostNamedActionOperation")
.add("textId", mTextId)
.add("actionType", getActionType(mType))
.add("valueId", mValueId);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java
index d2a1684a262a..c493e253d243 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java
@@ -247,8 +247,8 @@ public class MarqueeModifierOperation extends DecoratorModifierOperation impleme
mComponentHeight = height;
if (component instanceof LayoutComponent) {
LayoutComponent layoutComponent = (LayoutComponent) component;
- setContentWidth(layoutComponent.intrinsicWidth(context));
- setContentHeight(layoutComponent.intrinsicHeight(context));
+ setContentWidth(layoutComponent.minIntrinsicWidth(context));
+ setContentHeight(layoutComponent.minIntrinsicHeight(context));
}
}
@@ -256,7 +256,7 @@ public class MarqueeModifierOperation extends DecoratorModifierOperation impleme
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "MarqueeModifierOperation")
+ .addType("MarqueeModifierOperation")
.add("iterations", mIterations)
.add("animationMode", mAnimationMode)
.add("repeatDelayMillis", mRepeatDelayMillis)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
index b7fe97b0e936..37f56cbc02e1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
@@ -162,7 +162,7 @@ public class OffsetModifierOperation extends DecoratorModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "OffsetModifierOperation")
+ .addType("OffsetModifierOperation")
.add("x", mX)
.add("y", mY);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
index d5b3a0b09261..0156992650ed 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
@@ -184,7 +184,7 @@ public class PaddingModifierOperation extends Operation implements ModifierOpera
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "PaddingModifierOperation")
+ .addType("PaddingModifierOperation")
.add("left", mLeft)
.add("top", mTop)
.add("right", mRight)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java
index 69ace8478e08..eb5bfcff7d40 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java
@@ -217,7 +217,7 @@ public class RippleModifierOperation extends DecoratorModifierOperation implemen
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "RippleModifierOperation")
+ .addType("RippleModifierOperation")
.add("animateRippleStart", mAnimateRippleStart)
.add("animateRippleX", mAnimateRippleX)
.add("animateRippleY", mAnimateRippleY)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
index 8442e05e59df..f0ed905ac158 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
@@ -167,7 +167,7 @@ public class RoundedClipRectModifierOperation extends DrawBase4
public void serialize(MapSerializer serializer) {
serialize(serializer, "topStart", "topEnd", "bottomStart", "bottomEnd")
.addTags(SerializeTags.MODIFIER)
- .add("type", CLASS_NAME)
+ .addType(CLASS_NAME)
.add("width", mWidth)
.add("height", mHeight);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
index a57365ec9132..466e435e20cf 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
@@ -397,7 +397,7 @@ public class ScrollModifierOperation extends ListActionsOperation
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "ScrollModifierOperation")
+ .addType("ScrollModifierOperation")
.add("direction", mDirection)
.add("max", mMax)
.add("notchMax", mNotchMax)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
index bd91734602d9..171e2bed6b00 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
@@ -126,7 +126,7 @@ public class ValueFloatChangeActionOperation extends Operation implements Action
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER, SerializeTags.ACTION)
- .add("type", "ValueFloatChangeActionOperation")
+ .addType("ValueFloatChangeActionOperation")
.add("targetValueId", mTargetValueId)
.add("value", mValue);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
index 4b18d0aaf0df..d8133f6715a8 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
@@ -133,7 +133,7 @@ public class ValueFloatExpressionChangeActionOperation extends Operation
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER, SerializeTags.ACTION)
- .add("type", "ValueFloatExpressionChangeActionOperation")
+ .addType("ValueFloatExpressionChangeActionOperation")
.add("targetValueId", mTargetValueId)
.add("valueExpressionId", mValueExpressionId);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
index d86c4a6ad416..05a6fd0f10da 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
@@ -131,7 +131,7 @@ public class ValueIntegerChangeActionOperation extends Operation implements Acti
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER, SerializeTags.ACTION)
- .add("type", "ValueIntegerChangeActionOperation")
+ .addType("ValueIntegerChangeActionOperation")
.add("targetValueId", mTargetValueId)
.add("value", mValue);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
index e253460d2afb..8994febe7f7c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
@@ -133,7 +133,7 @@ public class ValueIntegerExpressionChangeActionOperation extends Operation
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER, SerializeTags.ACTION)
- .add("type", "ValueIntegerExpressionChangeActionOperation")
+ .addType("ValueIntegerExpressionChangeActionOperation")
.add("targetValueId", mTargetValueId)
.add("valueExpressionId", mValueExpressionId);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
index e84b29922523..08960d3576f4 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
@@ -139,7 +139,7 @@ public class ValueStringChangeActionOperation extends Operation implements Actio
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER, SerializeTags.ACTION)
- .add("type", "ValueIntegerExpressionChangeActionOperation")
+ .addType("ValueIntegerExpressionChangeActionOperation")
.add("targetValueId", mTargetValueId)
.add("valueId", mValueId);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthInModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthInModifierOperation.java
index 3282a9cb5426..93074c79319f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthInModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthInModifierOperation.java
@@ -107,7 +107,7 @@ public class WidthInModifierOperation extends DimensionInModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "WidthInModifierOperation")
+ .addType("WidthInModifierOperation")
.add("min", mV1, mValue1)
.add("max", mV2, mValue2);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
index 6fe5a70b7ad4..ebdafa2aaa89 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
@@ -143,7 +143,7 @@ public class WidthModifierOperation extends DimensionModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "WidthModifierOperation")
+ .addType("WidthModifierOperation")
.add("width", mValue, mOutValue)
.add("dimensionModifierType", mType);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
index f250951ab87e..ddb34b57e936 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
@@ -147,7 +147,7 @@ public class ZIndexModifierOperation extends DecoratorModifierOperation {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER)
- .add("type", "ZIndexModifierOperation")
+ .addType("ZIndexModifierOperation")
.add("value", mValue);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
index 0f17b114133d..55b64364e4e5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
@@ -1248,7 +1248,7 @@ public class PaintBundle implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", "PaintBundle");
+ serializer.addType("PaintBundle");
List<Map<String, Object>> list = new ArrayList<>();
int i = 0;
while (i < mPos) {
@@ -1336,6 +1336,7 @@ public class PaintBundle implements Serializable {
serializer.add("operations", list);
}
+ @SuppressWarnings("JdkImmutableCollections")
private static Map<String, Object> getVariable(int value) {
float fValue = Float.intBitsToFloat(value);
if (Float.isNaN(fValue)) {
@@ -1344,6 +1345,7 @@ public class PaintBundle implements Serializable {
return orderedOf("type", "Value", "value", fValue);
}
+ @SuppressWarnings("JdkImmutableCollections")
private static int serializeGradient(
int cmd, int[] array, int i, List<Map<String, Object>> list) {
int ret = i;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
index cad76059f7a4..349ab6117b2b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
@@ -34,8 +34,10 @@ public class FloatAnimation extends Easing implements Serializable {
private float mWrap = Float.NaN;
private float mInitialValue = Float.NaN;
private float mTargetValue = Float.NaN;
+ private int mDirectionalSnap = 0;
// private float mScale = 1;
float mOffset = 0;
+ private boolean mPropagate = false;
@NonNull
@Override
@@ -161,11 +163,15 @@ public class FloatAnimation extends Easing implements Serializable {
int type = 0;
float wrapValue = Float.NaN;
float initialValue = Float.NaN;
+ int directionalSnap = 0;
+ boolean propagate = false;
if (mSpec.length > 1) {
int num_type = Float.floatToRawIntBits(mSpec[1]);
type = num_type & 0xFF;
boolean wrap = ((num_type >> 8) & 0x1) > 0;
boolean init = ((num_type >> 8) & 0x2) > 0;
+ directionalSnap = (num_type >> 10) & 0x3;
+ propagate = ((num_type >> 12) & 0x1) > 0;
len = (num_type >> 16) & 0xFFFF;
int off = 2 + len;
if (init) {
@@ -229,6 +235,12 @@ public class FloatAnimation extends Easing implements Serializable {
if (!Float.isNaN(wrapValue)) {
str += " wrap =" + wrapValue;
}
+ if (directionalSnap != 0) {
+ str += " directionalSnap=" + directionalSnap;
+ }
+ if (propagate) {
+ str += " propagate";
+ }
return str;
}
@@ -246,6 +258,8 @@ public class FloatAnimation extends Easing implements Serializable {
mType = num_type & 0xFF;
boolean wrap = ((num_type >> 8) & 0x1) > 0;
boolean init = ((num_type >> 8) & 0x2) > 0;
+ int directional = (num_type >> 10) & 0x3;
+ boolean propagate = ((num_type >> 12) & 0x1) > 0;
len = (num_type >> 16) & 0xFFFF;
int off = 2 + len;
if (init) {
@@ -254,6 +268,8 @@ public class FloatAnimation extends Easing implements Serializable {
if (wrap) {
mWrap = mSpec[off];
}
+ mDirectionalSnap = directional;
+ mPropagate = propagate;
}
create(mType, description, 2, len);
}
@@ -347,7 +363,13 @@ public class FloatAnimation extends Easing implements Serializable {
float dist = wrapDistance(mWrap, mInitialValue, mTargetValue);
if ((dist > 0) && (mTargetValue < mInitialValue)) {
mTargetValue += mWrap;
- } else if ((dist < 0) && (mTargetValue > mInitialValue)) {
+ } else if ((dist < 0) && mDirectionalSnap != 0) {
+ if (mDirectionalSnap == 1 && mTargetValue > mInitialValue) {
+ mInitialValue = mTargetValue;
+ }
+ if (mDirectionalSnap == 2 && mTargetValue < mInitialValue) {
+ mInitialValue = mTargetValue;
+ }
mTargetValue -= mWrap;
}
}
@@ -377,6 +399,14 @@ public class FloatAnimation extends Easing implements Serializable {
/** get the value at time t in seconds since start */
@Override
public float get(float t) {
+ if (mDirectionalSnap == 1 && mTargetValue < mInitialValue) {
+ mInitialValue = mTargetValue;
+ return mTargetValue;
+ }
+ if (mDirectionalSnap == 2 && mTargetValue > mInitialValue) {
+ mInitialValue = mTargetValue;
+ return mTargetValue;
+ }
return mEasingCurve.get(t / mDuration) * (mTargetValue - mInitialValue) + mInitialValue;
}
@@ -387,6 +417,13 @@ public class FloatAnimation extends Easing implements Serializable {
}
/**
+ * @return if you should propagate the animation
+ */
+ public boolean isPropagate() {
+ return mPropagate;
+ }
+
+ /**
* Get the initial value
*
* @return the initial value
@@ -398,7 +435,7 @@ public class FloatAnimation extends Easing implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
serializer
- .add("type", "FloatAnimation")
+ .addType("FloatAnimation")
.add("initialValue", mInitialValue)
.add("targetValue", mInitialValue)
.add("duration", mInitialValue)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java
index 08559fc21acb..424894a3e665 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java
@@ -161,7 +161,7 @@ public class CoreSemantics extends Operation implements AccessibilityModifier {
public void serialize(MapSerializer serializer) {
serializer
.addTags(SerializeTags.MODIFIER, SerializeTags.A11Y)
- .add("type", "CoreSemantics")
+ .addType("CoreSemantics")
.add("contentDescriptionId", mContentDescriptionId)
.add("role", mRole)
.add("textId", mTextId)
diff --git a/core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java b/core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java
index f9ecf0f4f672..20e94ab5d898 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java
@@ -25,11 +25,17 @@ import java.util.Map;
public interface MapSerializer {
/**
+ * Adds a "type" field with this value
+ *
+ * @param type The name of the type
+ */
+ MapSerializer addType(String type);
+
+ /**
* Add a float expression
*
- * @param key
- * @param value
- * @return
+ * @param key The key
+ * @param value The float src
*/
MapSerializer addFloatExpressionSrc(String key, float[] value);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
index cb759a61249a..0da543f3336c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
@@ -131,6 +131,6 @@ public class BooleanConstant extends Operation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId).add("value", mValue);
+ serializer.addType(CLASS_NAME).add("id", mId).add("value", mValue);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
index c734f813ede3..bdc765968387 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
@@ -123,6 +123,6 @@ public class IntegerConstant extends Operation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId).add("value", mValue);
+ serializer.addType(CLASS_NAME).add("id", mId).add("value", mValue);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
index 50509f3636b3..d071e0a21d22 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
@@ -35,9 +35,13 @@ public class LongConstant extends Operation implements Serializable {
private static final String CLASS_NAME = "LongConstant";
private static final int OP_CODE = Operations.DATA_LONG;
- private final long mValue;
+ private long mValue;
private final int mId;
+ /**
+ * @param id the id of the constant
+ * @param value the value of the constant
+ */
public LongConstant(int id, long value) {
mId = id;
mValue = value;
@@ -52,6 +56,15 @@ public class LongConstant extends Operation implements Serializable {
return mValue;
}
+ /**
+ * Set the value of the long constant
+ *
+ * @param value the value to set it to
+ */
+ public void setValue(long value) {
+ mValue = value;
+ }
+
@Override
public void write(@NonNull WireBuffer buffer) {
apply(buffer, mId, mValue);
@@ -114,6 +127,6 @@ public class LongConstant extends Operation implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", CLASS_NAME).add("id", mId).add("value", mValue);
+ serializer.addType(CLASS_NAME).add("id", mId).add("value", mValue);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
index 1d1e579ebc2f..1f9a27429067 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
@@ -388,6 +388,16 @@ public class RemoteComposePlayer extends FrameLayout implements RemoteContextAwa
mInner.setColor(colorName, colorValue);
}
+ /**
+ * This sets long based on its name.
+ *
+ * @param name Name of the color
+ * @param value The new long value
+ */
+ public void setLong(String name, long value) {
+ mInner.setLong(name, value);
+ }
+
private void mapColors() {
String[] name = getNamedColors();
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index ac4a294b5e5e..b5aedd8d0231 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -290,8 +290,8 @@ public class AndroidPaintContext extends PaintContext {
}
if ((flags & PaintContext.TEXT_MEASURE_FONT_HEIGHT) != 0) {
- bounds[1] = Math.round(mCachedFontMetrics.top);
- bounds[3] = Math.round(mCachedFontMetrics.bottom);
+ bounds[1] = Math.round(mCachedFontMetrics.ascent);
+ bounds[3] = Math.round(mCachedFontMetrics.descent);
} else {
bounds[1] = mTmpRect.top;
bounds[3] = mTmpRect.bottom;
@@ -344,6 +344,7 @@ public class AndroidPaintContext extends PaintContext {
default:
}
staticLayoutBuilder.setMaxLines(maxLines);
+ staticLayoutBuilder.setIncludePad(false);
StaticLayout staticLayout = staticLayoutBuilder.build();
return new AndroidComputedTextLayout(
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java
index ba8d83bff51f..51c42fe111bd 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java
@@ -60,6 +60,14 @@ public class AndroidPlatformServices implements Platform {
}
@Override
+ public boolean isAlpha8Image(@NonNull Object image) {
+ if (image instanceof Bitmap) {
+ return ((Bitmap) image).getConfig().equals(Bitmap.Config.ALPHA_8);
+ }
+ return false;
+ }
+
+ @Override
@Nullable
public float[] pathToFloatArray(@NonNull Object path) {
// if (path is RemotePath) {
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
index 14349b028819..b31c76056e38 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.Paint;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.remotecompose.core.RemoteContext;
@@ -30,6 +31,7 @@ import com.android.internal.widget.remotecompose.core.operations.FloatExpression
import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.utilities.ArrayAccess;
import com.android.internal.widget.remotecompose.core.operations.utilities.DataMap;
+import com.android.internal.widget.remotecompose.core.types.LongConstant;
import java.io.IOException;
import java.net.MalformedURLException;
@@ -141,6 +143,16 @@ public class AndroidRemoteContext extends RemoteContext {
}
@Override
+ public void setNamedLong(String name, long value) {
+ VarName entry = mVarNameHashMap.get(name);
+ if (entry != null) {
+ int id = entry.mId;
+ LongConstant longConstant = (LongConstant) mRemoteComposeState.getObject(id);
+ longConstant.setValue(value);
+ }
+ }
+
+ @Override
public void setNamedDataOverride(String dataName, Object value) {
if (mVarNameHashMap.get(dataName) != null) {
int id = mVarNameHashMap.get(dataName).mId;
@@ -215,6 +227,27 @@ public class AndroidRemoteContext extends RemoteContext {
case BitmapData.TYPE_PNG_8888:
image = BitmapFactory.decodeByteArray(data, 0, data.length);
break;
+ case BitmapData.TYPE_PNG_ALPHA_8:
+ image = decodePreferringAlpha8(data);
+
+ // If needed convert to ALPHA_8.
+ if (!image.getConfig().equals(Bitmap.Config.ALPHA_8)) {
+ Bitmap alpha8Bitmap =
+ Bitmap.createBitmap(
+ image.getWidth(),
+ image.getHeight(),
+ Bitmap.Config.ALPHA_8);
+ Canvas canvas = new Canvas(alpha8Bitmap);
+ Paint paint = new Paint();
+ paint.setXfermode(
+ new android.graphics.PorterDuffXfermode(
+ android.graphics.PorterDuff.Mode.SRC));
+ canvas.drawBitmap(image, 0, 0, paint);
+ image.recycle(); // Release resources
+
+ image = alpha8Bitmap;
+ }
+ break;
case BitmapData.TYPE_RAW8888:
image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] idata = new int[data.length / 4];
@@ -255,6 +288,12 @@ public class AndroidRemoteContext extends RemoteContext {
}
}
+ private Bitmap decodePreferringAlpha8(@NonNull byte[] data) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inPreferredConfig = Bitmap.Config.ALPHA_8;
+ return BitmapFactory.decodeByteArray(data, 0, data.length, options);
+ }
+
@Override
public void loadText(int id, @NonNull String text) {
if (!mRemoteComposeState.containsId(id)) {
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
index 4d2dd05ca603..29cd40def562 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
@@ -200,6 +200,16 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta
mARContext.setNamedColorOverride(colorName, colorValue);
}
+ /**
+ * set the value of a long associated with this name.
+ *
+ * @param name Name of color typically "android.xxx"
+ * @param value the long value
+ */
+ public void setLong(String name, long value) {
+ mARContext.setNamedLong(name, value);
+ }
+
public RemoteComposeDocument getDocument() {
return mDocument;
}
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 34ec1481f697..8de77469d170 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -111,6 +111,7 @@ message SecureSettingsProto {
optional SettingProto autoclick_cursor_area_size = 62 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto autoclick_ignore_minor_cursor_movement = 63 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto autoclick_panel_position = 64 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto autoclick_revert_to_left_click = 65 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Accessibility accessibility = 2;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ee6899cf866b..e16ce9849ff2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -8995,13 +8995,13 @@
<!-- @SystemApi
@FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled")
- This permission is required to access the specific text classifier you need from the
+ This permission is required to access the specific text classifier from the
TextClassificationManager.
- <p>Protection level: signature|role
+ <p>Protection level: signature|role|privileged
@hide
-->
<permission android:name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE"
- android:protectionLevel="signature|role"
+ android:protectionLevel="signature|role|privileged"
android:featureFlag="android.permission.flags.text_classifier_choice_api_enabled"/>
<!-- Attribution for Geofencing service. -->
diff --git a/core/res/res/layout/accessibility_autoclick_type_panel.xml b/core/res/res/layout/accessibility_autoclick_type_panel.xml
index cedbdc175488..902ef7fc38e8 100644
--- a/core/res/res/layout/accessibility_autoclick_type_panel.xml
+++ b/core/res/res/layout/accessibility_autoclick_type_panel.xml
@@ -17,7 +17,7 @@
*/
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.server.accessibility.autoclick.AutoclickLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/accessibility_autoclick_type_panel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -130,4 +130,4 @@
</LinearLayout>
-</LinearLayout>
+</com.android.server.accessibility.autoclick.AutoclickLinearLayout>
diff --git a/core/tests/coretests/src/android/os/PerfettoTraceTest.java b/core/tests/coretests/src/android/os/PerfettoTraceTest.java
index 69150150d6f9..790ac4a55dc6 100644
--- a/core/tests/coretests/src/android/os/PerfettoTraceTest.java
+++ b/core/tests/coretests/src/android/os/PerfettoTraceTest.java
@@ -33,6 +33,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -611,6 +612,7 @@ public class PerfettoTraceTest {
@Test
@RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
+ @Ignore("b/303199244")
public void testMessageQueue() throws Exception {
TraceConfig traceConfig = getTraceConfig("mq");
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 15f70298198f..9234902335c1 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -619,6 +619,8 @@ applications that come with the platform
<permission name="android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE"/>
<permission name="android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE"/>
<permission name="android.permission.READ_COLOR_ZONES"/>
+ <!-- Permission required for CTS test - CtsTextClassifierTestCases -->
+ <permission name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
index b507ca2019a9..3f21e74a7d03 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.app.ActivityManager;
+import android.window.DesktopExperienceFlags;
import android.window.DisplayAreaInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -67,7 +68,7 @@ public class PipDesktopState {
/** Returns whether PiP in Connected Displays is enabled by checking the flag. */
public boolean isConnectedDisplaysPipEnabled() {
- return Flags.enableConnectedDisplaysPip();
+ return DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue();
}
/** Returns whether the display with the PiP task is in freeform windowing mode. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 5de3be4bbfc0..8f7e52ea2108 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -677,11 +677,7 @@ class DesktopTasksController(
// Bring other apps to front first.
bringDesktopAppsToFrontBeforeShowingNewTask(displayId, wct, task.taskId)
}
- if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
- prepareMoveTaskToDesk(wct, task, deskId)
- } else {
- addMoveToDesktopChanges(wct, task)
- }
+ addMoveToDeskTaskChanges(wct = wct, task = task, deskId = deskId)
return taskIdToMinimize
}
@@ -1260,6 +1256,8 @@ class DesktopTasksController(
* Move [task] to display with [displayId].
*
* No-op if task is already on that display per [RunningTaskInfo.displayId].
+ *
+ * TODO: b/399411604 - split this up into smaller functions.
*/
private fun moveToDisplay(task: RunningTaskInfo, displayId: Int) {
logV("moveToDisplay: taskId=%d displayId=%d", task.taskId, displayId)
@@ -1315,16 +1313,20 @@ class DesktopTasksController(
// TODO: b/393977830 and b/397437641 - do not assume that freeform==desktop.
if (!task.isFreeform) {
- addMoveToDesktopChanges(wct, task, displayId)
- } else if (Flags.enableMoveToNextDisplayShortcut()) {
- applyFreeformDisplayChange(wct, task, displayId)
+ addMoveToDeskTaskChanges(wct = wct, task = task, deskId = destinationDeskId)
+ } else {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
+ desksOrganizer.moveTaskToDesk(wct, destinationDeskId, task)
+ }
+ if (Flags.enableMoveToNextDisplayShortcut()) {
+ applyFreeformDisplayChange(wct, task, displayId)
+ }
}
- if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
- desksOrganizer.moveTaskToDesk(wct, destinationDeskId, task)
- } else {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
wct.reparent(task.token, displayAreaInfo.token, /* onTop= */ true)
}
+
addDeskActivationChanges(destinationDeskId, wct)
val activationRunnable: RunOnTransitStart = { transition ->
desksTransitionObserver.addPendingTransition(
@@ -2062,12 +2064,13 @@ class DesktopTasksController(
triggerTask?.let { task ->
when {
// Check if freeform task launch during recents should be handled
- shouldHandleMidRecentsFreeformLaunch -> handleMidRecentsFreeformTaskLaunch(task)
+ shouldHandleMidRecentsFreeformLaunch ->
+ handleMidRecentsFreeformTaskLaunch(task, transition)
// Check if the closing task needs to be handled
TransitionUtil.isClosingType(request.type) ->
handleTaskClosing(task, transition, request.type)
// Check if the top task shouldn't be allowed to enter desktop mode
- isIncompatibleTask(task) -> handleIncompatibleTaskLaunch(task)
+ isIncompatibleTask(task) -> handleIncompatibleTaskLaunch(task, transition)
// Check if fullscreen task should be updated
task.isFullscreen -> handleFullscreenTaskLaunch(task, transition)
// Check if freeform task should be updated
@@ -2306,20 +2309,23 @@ class DesktopTasksController(
* This is a special case where we want to launch the task in fullscreen instead of freeform.
*/
private fun handleMidRecentsFreeformTaskLaunch(
- task: RunningTaskInfo
+ task: RunningTaskInfo,
+ transition: IBinder,
): WindowContainerTransaction? {
logV("DesktopTasksController: handleMidRecentsFreeformTaskLaunch")
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(
- wct = wct,
- taskInfo = task,
- willExitDesktop =
- willExitDesktop(
- triggerTaskId = task.taskId,
- displayId = task.displayId,
- forceExitDesktop = true,
- ),
- )
+ val runOnTransitStart =
+ addMoveToFullscreenChanges(
+ wct = wct,
+ taskInfo = task,
+ willExitDesktop =
+ willExitDesktop(
+ triggerTaskId = task.taskId,
+ displayId = task.displayId,
+ forceExitDesktop = true,
+ ),
+ )
+ runOnTransitStart?.invoke(transition)
wct.reorder(task.token, true)
return wct
}
@@ -2343,16 +2349,18 @@ class DesktopTasksController(
// launched. We should make this task go to fullscreen instead of freeform. Note
// that this means any re-launch of a freeform window outside of desktop will be in
// fullscreen as long as default-desktop flag is disabled.
- addMoveToFullscreenChanges(
- wct = wct,
- taskInfo = task,
- willExitDesktop =
- willExitDesktop(
- triggerTaskId = task.taskId,
- displayId = task.displayId,
- forceExitDesktop = true,
- ),
- )
+ val runOnTransitStart =
+ addMoveToFullscreenChanges(
+ wct = wct,
+ taskInfo = task,
+ willExitDesktop =
+ willExitDesktop(
+ triggerTaskId = task.taskId,
+ displayId = task.displayId,
+ forceExitDesktop = true,
+ ),
+ )
+ runOnTransitStart?.invoke(transition)
return wct
}
bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
@@ -2416,7 +2424,8 @@ class DesktopTasksController(
if (shouldFullscreenTaskLaunchSwitchToDesktop(task)) {
logD("Switch fullscreen task to freeform on transition: taskId=%d", task.taskId)
return WindowContainerTransaction().also { wct ->
- addMoveToDesktopChanges(wct, task)
+ val deskId = getDefaultDeskId(task.displayId)
+ addMoveToDeskTaskChanges(wct = wct, task = task, deskId = deskId)
// In some launches home task is moved behind new task being launched. Make sure
// that's not the case for launches in desktop. Also, if this launch is the first
// one to trigger the desktop mode (e.g., when [forceEnterDesktop()]), activate the
@@ -2447,7 +2456,8 @@ class DesktopTasksController(
// If a freeform task receives a request for a fullscreen launch, apply the same
// changes we do for similar transitions. The task not having WINDOWING_MODE_UNDEFINED
// set when needed can interfere with future split / multi-instance transitions.
- return WindowContainerTransaction().also { wct ->
+ val wct = WindowContainerTransaction()
+ val runOnTransitStart =
addMoveToFullscreenChanges(
wct = wct,
taskInfo = task,
@@ -2458,7 +2468,8 @@ class DesktopTasksController(
forceExitDesktop = true,
),
)
- }
+ runOnTransitStart?.invoke(transition)
+ return wct
}
return null
}
@@ -2473,7 +2484,10 @@ class DesktopTasksController(
* If a task is not compatible with desktop mode freeform, it should always be launched in
* fullscreen.
*/
- private fun handleIncompatibleTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? {
+ private fun handleIncompatibleTaskLaunch(
+ task: RunningTaskInfo,
+ transition: IBinder,
+ ): WindowContainerTransaction? {
logV("handleIncompatibleTaskLaunch")
if (!isDesktopModeShowing(task.displayId) && !forceEnterDesktop(task.displayId)) return null
// Only update task repository for transparent task.
@@ -2485,7 +2499,8 @@ class DesktopTasksController(
}
// Already fullscreen, no-op.
if (task.isFullscreen) return null
- return WindowContainerTransaction().also { wct ->
+ val wct = WindowContainerTransaction()
+ val runOnTransitStart =
addMoveToFullscreenChanges(
wct = wct,
taskInfo = task,
@@ -2496,7 +2511,8 @@ class DesktopTasksController(
forceExitDesktop = true,
),
)
- }
+ runOnTransitStart?.invoke(transition)
+ return wct
}
/**
@@ -2543,55 +2559,44 @@ class DesktopTasksController(
}
/**
- * Apply all changes required when task is first added to desktop. Uses the task's current
- * display by default to apply initial bounds and placement relative to the display. Use a
- * different [displayId] if the task should be moved to a different display.
+ * Applies the [wct] changes needed when a task is first moving to a desk.
+ *
+ * Note that this recalculates the initial bounds of the task, so it should not be used when
+ * transferring a task between desks.
+ *
+ * TODO: b/362720497 - this should be improved to be reusable by desk-to-desk CUJs where
+ * [DesksOrganizer.moveTaskToDesk] needs to be called and even cross-display CUJs where
+ * [applyFreeformDisplayChange] needs to be called. Potentially by comparing source vs
+ * destination desk ids and display ids, or adding extra arguments to the function.
*/
- @VisibleForTesting
- @Deprecated("Deprecated with multiple desks", ReplaceWith("prepareMoveTaskToDesk()"))
- fun addMoveToDesktopChanges(
+ fun addMoveToDeskTaskChanges(
wct: WindowContainerTransaction,
- taskInfo: RunningTaskInfo,
- displayId: Int = taskInfo.displayId,
- ) {
- val displayLayout = displayController.getDisplayLayout(displayId) ?: return
- val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)!!
- val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode
- // TODO: b/397437641 - reconsider the windowing mode choice when multiple desks is enabled.
- val targetWindowingMode =
- if (tdaWindowingMode == WINDOWING_MODE_FREEFORM) {
- // Display windowing is freeform, set to undefined and inherit it
- WINDOWING_MODE_UNDEFINED
- } else {
- WINDOWING_MODE_FREEFORM
- }
- val initialBounds = getInitialBounds(displayLayout, taskInfo, displayId)
-
- if (canChangeTaskPosition(taskInfo)) {
- wct.setBounds(taskInfo.token, initialBounds)
- }
- wct.setWindowingMode(taskInfo.token, targetWindowingMode)
- wct.reorder(taskInfo.token, /* onTop= */ true)
- if (useDesktopOverrideDensity()) {
- wct.setDensityDpi(taskInfo.token, DESKTOP_DENSITY_OVERRIDE)
- }
- }
-
- private fun prepareMoveTaskToDesk(
- wct: WindowContainerTransaction,
- taskInfo: RunningTaskInfo,
+ task: RunningTaskInfo,
deskId: Int,
) {
- if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
- val displayId = taskRepository.getDisplayForDesk(deskId)
- val displayLayout = displayController.getDisplayLayout(displayId) ?: return
- val initialBounds = getInitialBounds(displayLayout, taskInfo, displayId)
- if (canChangeTaskPosition(taskInfo)) {
- wct.setBounds(taskInfo.token, initialBounds)
+ val targetDisplayId = taskRepository.getDisplayForDesk(deskId)
+ val displayLayout = displayController.getDisplayLayout(targetDisplayId) ?: return
+ val initialBounds = getInitialBounds(displayLayout, task, targetDisplayId)
+ if (canChangeTaskPosition(task)) {
+ wct.setBounds(task.token, initialBounds)
+ }
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
+ desksOrganizer.moveTaskToDesk(wct = wct, deskId = deskId, task = task)
+ } else {
+ val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(targetDisplayId)!!
+ val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode
+ val targetWindowingMode =
+ if (tdaWindowingMode == WINDOWING_MODE_FREEFORM) {
+ // Display windowing is freeform, set to undefined and inherit it
+ WINDOWING_MODE_UNDEFINED
+ } else {
+ WINDOWING_MODE_FREEFORM
+ }
+ wct.setWindowingMode(task.token, targetWindowingMode)
+ wct.reorder(task.token, /* onTop= */ true)
}
- desksOrganizer.moveTaskToDesk(wct, deskId = deskId, task = taskInfo)
if (useDesktopOverrideDensity()) {
- wct.setDensityDpi(taskInfo.token, DESKTOP_DENSITY_OVERRIDE)
+ wct.setDensityDpi(task.token, DESKTOP_DENSITY_OVERRIDE)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index d666126b91ba..c0a0f469add4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.service.dreams.Flags.dismissDreamOnKeyguardDismiss;
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
+import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
@@ -200,7 +201,8 @@ public class KeyguardTransitionHandler
transition, info, startTransaction, finishTransaction, finishCallback);
}
- if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0) {
+ if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0
+ || (info.getFlags() & TRANSIT_FLAG_AOD_APPEARING) != 0) {
return startAnimation(mAppearTransition, "appearing",
transition, info, startTransaction, finishTransaction, finishCallback);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index d16c5782177e..6012fe66188d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -32,6 +32,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.SurfaceControl;
+import android.window.DesktopExperienceFlags;
import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;
@@ -41,7 +42,6 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.Preconditions;
-import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayChangeController;
@@ -303,7 +303,8 @@ public class PipController implements ConfigurationChangeListener,
public void onDisplayRemoved(int displayId) {
// If PiP was active on an external display that is removed, clean up states and set
// {@link PipDisplayLayoutState} to DEFAULT_DISPLAY.
- if (Flags.enableConnectedDisplaysPip() && mPipTransitionState.isInPip()
+ if (DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue()
+ && mPipTransitionState.isInPip()
&& displayId == mPipDisplayLayoutState.getDisplayId()
&& displayId != DEFAULT_DISPLAY) {
mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
@@ -385,7 +386,7 @@ public class PipController implements ConfigurationChangeListener,
// If PiP is enabled on Connected Displays, update PipDisplayLayoutState to have the correct
// display info that PiP is entering in.
- if (Flags.enableConnectedDisplaysPip()) {
+ if (DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue()) {
final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId);
if (displayLayout != null) {
mPipDisplayLayoutState.setDisplayId(displayId);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index b0785df3542e..63bf6841dba4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -1114,44 +1114,44 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- fun addMoveToDesktopChanges_gravityLeft_noBoundsApplied() {
+ fun addMoveToDeskTaskChanges_gravityLeft_noBoundsApplied() {
setUpLandscapeDisplay()
val task = setUpFullscreenTask(gravity = Gravity.LEFT)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(finalBounds).isEqualTo(Rect())
}
@Test
- fun addMoveToDesktopChanges_gravityRight_noBoundsApplied() {
+ fun addMoveToDeskTaskChanges_gravityRight_noBoundsApplied() {
setUpLandscapeDisplay()
val task = setUpFullscreenTask(gravity = Gravity.RIGHT)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(finalBounds).isEqualTo(Rect())
}
@Test
- fun addMoveToDesktopChanges_gravityTop_noBoundsApplied() {
+ fun addMoveToDeskTaskChanges_gravityTop_noBoundsApplied() {
setUpLandscapeDisplay()
val task = setUpFullscreenTask(gravity = Gravity.TOP)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(finalBounds).isEqualTo(Rect())
}
@Test
- fun addMoveToDesktopChanges_gravityBottom_noBoundsApplied() {
+ fun addMoveToDeskTaskChanges_gravityBottom_noBoundsApplied() {
setUpLandscapeDisplay()
val task = setUpFullscreenTask(gravity = Gravity.BOTTOM)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(finalBounds).isEqualTo(Rect())
@@ -1192,7 +1192,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS)
- fun addMoveToDesktopChanges_positionBottomRight() {
+ fun addMoveToDeskTaskChanges_positionBottomRight() {
setUpLandscapeDisplay()
val stableBounds = Rect()
displayLayout.getStableBoundsForDesktopMode(stableBounds)
@@ -1201,7 +1201,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFullscreenTask()
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!))
@@ -1210,7 +1210,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS)
- fun addMoveToDesktopChanges_positionTopLeft() {
+ fun addMoveToDeskTaskChanges_positionTopLeft() {
setUpLandscapeDisplay()
val stableBounds = Rect()
displayLayout.getStableBoundsForDesktopMode(stableBounds)
@@ -1219,7 +1219,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFullscreenTask()
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!))
@@ -1228,7 +1228,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS)
- fun addMoveToDesktopChanges_positionBottomLeft() {
+ fun addMoveToDeskTaskChanges_positionBottomLeft() {
setUpLandscapeDisplay()
val stableBounds = Rect()
displayLayout.getStableBoundsForDesktopMode(stableBounds)
@@ -1237,7 +1237,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFullscreenTask()
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!))
@@ -1246,7 +1246,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS)
- fun addMoveToDesktopChanges_positionTopRight() {
+ fun addMoveToDeskTaskChanges_positionTopRight() {
setUpLandscapeDisplay()
val stableBounds = Rect()
displayLayout.getStableBoundsForDesktopMode(stableBounds)
@@ -1255,7 +1255,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFullscreenTask()
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!))
@@ -1264,7 +1264,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS)
- fun addMoveToDesktopChanges_positionResetsToCenter() {
+ fun addMoveToDeskTaskChanges_positionResetsToCenter() {
setUpLandscapeDisplay()
val stableBounds = Rect()
displayLayout.getStableBoundsForDesktopMode(stableBounds)
@@ -1273,7 +1273,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFullscreenTask()
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!))
@@ -1282,7 +1282,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS)
- fun addMoveToDesktopChanges_lastWindowSnapLeft_positionResetsToCenter() {
+ fun addMoveToDeskTaskChanges_lastWindowSnapLeft_positionResetsToCenter() {
setUpLandscapeDisplay()
val stableBounds = Rect()
displayLayout.getStableBoundsForDesktopMode(stableBounds)
@@ -1294,7 +1294,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFullscreenTask()
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!))
@@ -1303,7 +1303,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS)
- fun addMoveToDesktopChanges_lastWindowSnapRight_positionResetsToCenter() {
+ fun addMoveToDeskTaskChanges_lastWindowSnapRight_positionResetsToCenter() {
setUpLandscapeDisplay()
val stableBounds = Rect()
displayLayout.getStableBoundsForDesktopMode(stableBounds)
@@ -1321,7 +1321,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFullscreenTask()
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!))
@@ -1330,7 +1330,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS)
- fun addMoveToDesktopChanges_lastWindowMaximised_positionResetsToCenter() {
+ fun addMoveToDeskTaskChanges_lastWindowMaximised_positionResetsToCenter() {
setUpLandscapeDisplay()
val stableBounds = Rect()
displayLayout.getStableBoundsForDesktopMode(stableBounds)
@@ -1340,7 +1340,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFullscreenTask()
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!))
@@ -1349,7 +1349,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS)
- fun addMoveToDesktopChanges_defaultToCenterIfFree() {
+ fun addMoveToDeskTaskChanges_defaultToCenterIfFree() {
setUpLandscapeDisplay()
val stableBounds = Rect()
displayLayout.getStableBoundsForDesktopMode(stableBounds)
@@ -1367,7 +1367,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFullscreenTask()
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!))
@@ -1375,7 +1375,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- fun addMoveToDesktopChanges_excludeCaptionFromAppBounds_nonResizableLandscape() {
+ fun addMoveToDeskTaskChanges_excludeCaptionFromAppBounds_nonResizableLandscape() {
setUpLandscapeDisplay()
val task =
setUpFullscreenTask(
@@ -1385,7 +1385,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
whenever(desktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(task)).thenReturn(true)
val initialAspectRatio = calculateAspectRatio(task)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
val captionInsets = getAppHeaderHeight(context)
@@ -1397,7 +1397,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- fun addMoveToDesktopChanges_excludeCaptionFromAppBounds_nonResizablePortrait() {
+ fun addMoveToDeskTaskChanges_excludeCaptionFromAppBounds_nonResizablePortrait() {
setUpLandscapeDisplay()
val task =
setUpFullscreenTask(
@@ -1407,7 +1407,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
whenever(desktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(task)).thenReturn(true)
val initialAspectRatio = calculateAspectRatio(task)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
val finalBounds = findBoundsChange(wct, task)
val captionInsets = getAppHeaderHeight(context)
@@ -1445,29 +1445,29 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
- fun addMoveToDesktopChanges_landscapeDevice_userFullscreenOverride_defaultPortraitBounds() {
+ fun addMoveToDeskTaskChanges_landscapeDevice_userFullscreenOverride_defaultPortraitBounds() {
setUpLandscapeDisplay()
val task = setUpFullscreenTask(enableUserFullscreenOverride = true)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
- fun addMoveToDesktopChanges_landscapeDevice_systemFullscreenOverride_defaultPortraitBounds() {
+ fun addMoveToDeskTaskChanges_landscapeDevice_systemFullscreenOverride_defaultPortraitBounds() {
setUpLandscapeDisplay()
val task = setUpFullscreenTask(enableSystemFullscreenOverride = true)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
- fun addMoveToDesktopChanges_landscapeDevice_portraitResizableApp_aspectRatioOverridden() {
+ fun addMoveToDeskTaskChanges_landscapeDevice_portraitResizableApp_aspectRatioOverridden() {
setUpLandscapeDisplay()
val task =
setUpFullscreenTask(
@@ -1476,36 +1476,36 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
aspectRatioOverrideApplied = true,
)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_PORTRAIT_BOUNDS)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
- fun addMoveToDesktopChanges_portraitDevice_userFullscreenOverride_defaultPortraitBounds() {
+ fun addMoveToDeskTaskChanges_portraitDevice_userFullscreenOverride_defaultPortraitBounds() {
setUpPortraitDisplay()
val task = setUpFullscreenTask(enableUserFullscreenOverride = true)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
- fun addMoveToDesktopChanges_portraitDevice_systemFullscreenOverride_defaultPortraitBounds() {
+ fun addMoveToDeskTaskChanges_portraitDevice_systemFullscreenOverride_defaultPortraitBounds() {
setUpPortraitDisplay()
val task = setUpFullscreenTask(enableSystemFullscreenOverride = true)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
- fun addMoveToDesktopChanges_portraitDevice_landscapeResizableApp_aspectRatioOverridden() {
+ fun addMoveToDeskTaskChanges_portraitDevice_landscapeResizableApp_aspectRatioOverridden() {
setUpPortraitDisplay()
val task =
setUpFullscreenTask(
@@ -1515,7 +1515,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
aspectRatioOverrideApplied = true,
)
val wct = WindowContainerTransaction()
- controller.addMoveToDesktopChanges(wct, task)
+ controller.addMoveToDeskTaskChanges(wct, task, deskId = 0)
assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_LANDSCAPE_BOUNDS)
}
@@ -2824,7 +2824,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun moveToNextDisplay_toDesktopInOtherDisplay_bringsExistingTasksToFront() {
val transition = Binder()
val sourceDeskId = 0
@@ -2856,7 +2855,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY,
Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
)
- @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun moveToNextDisplay_toDesktopInOtherDisplay_movesHomeAndWallpaperToFront() {
val homeTask = setUpHomeTask(displayId = SECOND_DISPLAY)
whenever(desktopWallpaperActivityTokenProvider.getToken(SECOND_DISPLAY))
@@ -3506,6 +3504,39 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun handleRequest_fullscreenTask_switchToDesktop_movesTaskToDesk() {
+ taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = 5)
+ setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 5)
+ taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 5)
+
+ val fullscreenTask = createFullscreenTask()
+ val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
+
+ assertNotNull(wct, "should handle request")
+ verify(desksOrganizer).moveTaskToDesk(wct = wct, deskId = 5, task = fullscreenTask)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun handleRequest_fullscreenTaskThatWasInactiveInDesk_tracksDeskDeactivation() {
+ // Set up and existing desktop task in an active desk.
+ val inactiveInDeskTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
+ taskRepository.setDeskInactive(deskId = 0)
+
+ // Now the task is launching as fullscreen.
+ inactiveInDeskTask.configuration.windowConfiguration.windowingMode =
+ WINDOWING_MODE_FULLSCREEN
+ val transition = Binder()
+ val wct = controller.handleRequest(transition, createTransition(inactiveInDeskTask))
+
+ // Desk is deactivated.
+ assertNotNull(wct, "should handle request")
+ verify(desksTransitionsObserver)
+ .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId = 0))
+ }
+
+ @Test
fun handleRequest_fullscreenTask_freeformVisible_returnSwitchToFreeformWCT() {
val homeTask = setUpHomeTask()
val freeformTask = setUpFreeformTask()
@@ -3681,6 +3712,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun handleRequest_freeformTaskFromInactiveDesk_tracksDeskDeactivation() {
+ val deskId = 0
+ val freeformTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+ taskRepository.setDeskInactive(deskId = deskId)
+
+ val transition = Binder()
+ controller.handleRequest(transition, createTransition(freeformTask))
+
+ verify(desksTransitionsObserver)
+ .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId))
+ }
+
+ @Test
fun handleRequest_freeformTask_relaunchActiveTask_taskBecomesUndefined() {
val freeformTask = setUpFreeformTask()
markTaskHidden(freeformTask)
@@ -3928,6 +3973,24 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun handleRequest_recentsAnimationRunning_relaunchActiveTask_tracksDeskDeactivation() {
+ // Set up a visible freeform task
+ val freeformTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
+ markTaskVisible(freeformTask)
+
+ // Mark recents animation running
+ recentsTransitionStateListener.onTransitionStateChanged(TRANSITION_STATE_ANIMATING)
+
+ val transition = Binder()
+ controller.handleRequest(transition, createTransition(freeformTask))
+
+ desksTransitionsObserver.addPendingTransition(
+ DeskTransition.DeactivateDesk(transition, deskId = 0)
+ )
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
fun handleRequest_topActivityTransparentWithoutDisplay_returnSwitchToFreeformWCT() {
val freeformTask = setUpFreeformTask()
@@ -4045,6 +4108,31 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY,
+ )
+ fun handleRequest_systemUIActivityWithDisplayInFreeformTask_inDesktop_tracksDeskDeactivation() {
+ val deskId = 5
+ taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+ taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+ val systemUIPackageName =
+ context.resources.getString(com.android.internal.R.string.config_systemUi)
+ val baseComponent = ComponentName(systemUIPackageName, /* cls= */ "")
+ val task =
+ setUpFreeformTask(displayId = DEFAULT_DISPLAY).apply {
+ baseActivity = baseComponent
+ isTopActivityNoDisplay = false
+ }
+
+ val transition = Binder()
+ controller.handleRequest(transition, createTransition(task))
+
+ verify(desksTransitionsObserver)
+ .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId))
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
fun handleRequest_systemUIActivityWithoutDisplay_returnSwitchToFreeformWCT() {
val freeformTask = setUpFreeformTask()
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index 30e7a628f1f6..6f60d01e4395 100644
--- a/libs/hwui/CanvasTransform.cpp
+++ b/libs/hwui/CanvasTransform.cpp
@@ -55,12 +55,20 @@ SkColor makeDark(SkColor color) {
}
}
+SkColor invert(SkColor color) {
+ Lab lab = sRGBToLab(color);
+ lab.L = 100 - lab.L;
+ return LabToSRGB(lab, SkColorGetA(color));
+}
+
SkColor transformColor(ColorTransform transform, SkColor color) {
switch (transform) {
case ColorTransform::Light:
return makeLight(color);
case ColorTransform::Dark:
return makeDark(color);
+ case ColorTransform::Invert:
+ return invert(color);
default:
return color;
}
@@ -80,19 +88,6 @@ SkColor transformColorInverse(ColorTransform transform, SkColor color) {
static void applyColorTransform(ColorTransform transform, SkPaint& paint) {
if (transform == ColorTransform::None) return;
- if (transform == ColorTransform::Invert) {
- auto filter = SkHighContrastFilter::Make(
- {/* grayscale= */ false, SkHighContrastConfig::InvertStyle::kInvertLightness,
- /* contrast= */ 0.0f});
-
- if (paint.getColorFilter()) {
- paint.setColorFilter(SkColorFilters::Compose(filter, paint.refColorFilter()));
- } else {
- paint.setColorFilter(filter);
- }
- return;
- }
-
SkColor newColor = transformColor(transform, paint.getColor());
paint.setColor(newColor);
@@ -112,6 +107,22 @@ static void applyColorTransform(ColorTransform transform, SkPaint& paint) {
paint.setShader(SkGradientShader::MakeLinear(
info.fPoints, info.fColors, info.fColorOffsets, info.fColorCount,
info.fTileMode, info.fGradientFlags, nullptr));
+ } else {
+ if (transform == ColorTransform::Invert) {
+ // Since we're trying to invert every thing around this draw call, we invert
+ // the color of the draw call if we don't know what it is.
+ auto filter = SkHighContrastFilter::Make(
+ {/* grayscale= */ false,
+ SkHighContrastConfig::InvertStyle::kInvertLightness,
+ /* contrast= */ 0.0f});
+
+ if (paint.getColorFilter()) {
+ paint.setColorFilter(SkColorFilters::Compose(filter, paint.refColorFilter()));
+ } else {
+ paint.setColorFilter(filter);
+ }
+ return;
+ }
}
}
@@ -150,8 +161,13 @@ bool transformPaint(ColorTransform transform, SkPaint* paint) {
}
bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette) {
- palette = filterPalette(paint, palette);
bool shouldInvert = false;
+ if (transform == ColorTransform::Invert && palette != BitmapPalette::Colorful) {
+ // When the transform is Invert we invert any image that is not deemed "colorful",
+ // regardless of calculated image brightness.
+ shouldInvert = true;
+ }
+ palette = filterPalette(paint, palette);
if (palette == BitmapPalette::Light && transform == ColorTransform::Dark) {
shouldInvert = true;
}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 4801bd1038a3..8b4e59aa73e2 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -27,6 +27,7 @@
#include "DamageAccumulator.h"
#include "Debug.h"
+#include "FeatureFlags.h"
#include "Properties.h"
#include "TreeInfo.h"
#include "VectorDrawable.h"
@@ -398,26 +399,32 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
deleteDisplayList(observer, info);
mDisplayList = std::move(mStagingDisplayList);
if (mDisplayList) {
- WebViewSyncData syncData{.applyForceDark = shouldEnableForceDark(info)};
+ WebViewSyncData syncData{.applyForceDark = shouldEnableForceDark(info) ||
+ (info && isForceInvertDark(*info))};
mDisplayList.syncContents(syncData);
handleForceDark(info);
}
}
+// Return true if the tree should use the force invert feature that inverts
+// the entire tree to darken it.
inline bool RenderNode::isForceInvertDark(TreeInfo& info) {
- return CC_UNLIKELY(
- info.forceDarkType == android::uirenderer::ForceDarkType::FORCE_INVERT_COLOR_DARK);
+ return CC_UNLIKELY(info.forceDarkType ==
+ android::uirenderer::ForceDarkType::FORCE_INVERT_COLOR_DARK);
}
+// Return true if the tree should use the force dark feature that selectively
+// darkens light nodes on the tree.
inline bool RenderNode::shouldEnableForceDark(TreeInfo* info) {
- return CC_UNLIKELY(
- info &&
- (!info->disableForceDark || isForceInvertDark(*info)));
+ return CC_UNLIKELY(info && !info->disableForceDark);
}
-
-
-void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) {
+void RenderNode::handleForceDark(TreeInfo *info) {
+ if (CC_UNLIKELY(view_accessibility_flags::force_invert_color() && info &&
+ isForceInvertDark(*info))) {
+ mDisplayList.applyColorTransform(ColorTransform::Invert);
+ return;
+ }
if (!shouldEnableForceDark(info)) {
return;
}
@@ -427,13 +434,7 @@ void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) {
children.push_back(node);
});
if (mDisplayList.hasText()) {
- if (isForceInvertDark(*info) && mDisplayList.hasFill()) {
- // Handle a special case for custom views that draw both text and background in the
- // same RenderNode, which would otherwise be altered to white-on-white text.
- usage = UsageHint::Container;
- } else {
- usage = UsageHint::Foreground;
- }
+ usage = UsageHint::Foreground;
}
if (usage == UsageHint::Unknown) {
if (children.size() > 1) {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 63a024b8e780..3ef970830dc4 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -16,6 +16,8 @@
#include "Bitmap.h"
#include <android-base/file.h>
+
+#include "FeatureFlags.h"
#include "HardwareBitmapUploader.h"
#include "Properties.h"
#ifdef __ANDROID__ // Layoutlib does not support render thread
@@ -547,9 +549,16 @@ BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr,
}
ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
- "%f]",
+ "%f] %d x %d",
sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
- saturation.average());
+ saturation.average(), info.width(), info.height());
+
+ if (CC_UNLIKELY(view_accessibility_flags::force_invert_color())) {
+ if (saturation.delta() > 0.1f ||
+ (hue.delta() > 20 && saturation.average() > 0.2f && value.average() < 0.9f)) {
+ return BitmapPalette::Colorful;
+ }
+ }
if (hue.delta() <= 20 && saturation.delta() <= .1f) {
if (value.average() >= .5f) {
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 4e9bcf27c0ef..0fe5fe88f715 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -49,6 +49,7 @@ enum class BitmapPalette {
Unknown,
Light,
Dark,
+ Colorful,
};
namespace uirenderer {
diff --git a/libs/hwui/jni/GIFMovie.cpp b/libs/hwui/jni/GIFMovie.cpp
index 6c82aa1ca27d..476b6fda5007 100644
--- a/libs/hwui/jni/GIFMovie.cpp
+++ b/libs/hwui/jni/GIFMovie.cpp
@@ -63,7 +63,7 @@ GIFMovie::GIFMovie(SkStream* stream)
}
fCurrIndex = -1;
fLastDrawIndex = -1;
- fPaintingColor = SkPackARGB32(0, 0, 0, 0);
+ fPaintingColor = SK_AlphaTRANSPARENT;
}
GIFMovie::~GIFMovie()
@@ -127,7 +127,7 @@ static void copyLine(uint32_t* dst, const unsigned char* src, const ColorMapObje
for (; width > 0; width--, src++, dst++) {
if (*src != transparent && *src < cmap->ColorCount) {
const GifColorType& col = cmap->Colors[*src];
- *dst = SkPackARGB32(0xFF, col.Red, col.Green, col.Blue);
+ *dst = SkColorSetRGB(col.Red, col.Green, col.Blue);
}
}
}
@@ -395,10 +395,10 @@ bool GIFMovie::onGetBitmap(SkBitmap* bm)
lastIndex = fGIF->ImageCount - 1;
}
- SkColor bgColor = SkPackARGB32(0, 0, 0, 0);
+ SkColor bgColor = SK_ColorTRANSPARENT;
if (gif->SColorMap != nullptr && gif->SBackGroundColor < gif->SColorMap->ColorCount) {
const GifColorType& col = gif->SColorMap->Colors[gif->SBackGroundColor];
- bgColor = SkColorSetARGB(0xFF, col.Red, col.Green, col.Blue);
+ bgColor = SkColorSetRGB(col.Red, col.Green, col.Blue);
}
// draw each frames - not intelligent way
@@ -411,7 +411,7 @@ bool GIFMovie::onGetBitmap(SkBitmap* bm)
if (!trans && gif->SColorMap != nullptr) {
fPaintingColor = bgColor;
} else {
- fPaintingColor = SkColorSetARGB(0, 0, 0, 0);
+ fPaintingColor = SK_ColorTRANSPARENT;
}
bm->eraseColor(fPaintingColor);
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 80b55e2c1244..5a993bfcc9cf 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -33,6 +33,7 @@ import android.annotation.SystemApi;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.pm.PackageManager;
+import android.location.flags.Flags;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -181,7 +182,8 @@ public final class LocationRequest implements Parcelable {
public static final int POWER_HIGH = 203;
private static final long IMPLICIT_MIN_UPDATE_INTERVAL = -1;
- private static final double IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR = 1D / 6D;
+ private static final double LEGACY_IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR = 1D / 6D;
+ private static final double IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR = 1D / 2D;
private @Nullable String mProvider;
private @Quality int mQuality;
@@ -553,7 +555,10 @@ public final class LocationRequest implements Parcelable {
*/
public @IntRange(from = 0) long getMinUpdateIntervalMillis() {
if (mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
- return (long) (mIntervalMillis * IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR);
+ if (Flags.updateMinLocationRequestInterval()) {
+ return (long) (mIntervalMillis * IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR);
+ }
+ return (long) (mIntervalMillis * LEGACY_IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR);
} else {
// the min is only necessary in case someone use a deprecated function to mess with the
// interval or min update interval
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index 1b38982f48c1..83b1778fd611 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -168,3 +168,14 @@ flag {
description: "Flag for GNSS assistance interface"
bug: "209078566"
}
+
+flag {
+ name: "update_min_location_request_interval"
+ namespace: "location"
+ description: "Flag for updating the default logic for the minimal interval for location request"
+ bug: "397444378"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Autopilot.kt b/packages/EasterEgg/src/com/android/egg/landroid/Autopilot.kt
index 8214c540304e..a4803d248ea8 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/Autopilot.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Autopilot.kt
@@ -44,7 +44,7 @@ class Autopilot(val ship: Spacecraft, val universe: Universe) : Entity {
if (enabled)
listOf(
"---- AUTOPILOT ENGAGED ----",
- "TGT: " + (target?.name?.toUpperCase() ?: "SELECTING..."),
+ "TGT: " + (target?.name?.uppercase() ?: "SELECTING..."),
"EXE: $strategy" + if (debug.isNotEmpty()) " ($debug)" else "",
)
.joinToString("\n")
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt b/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt
index 95a60c7a5292..61ea08ecbf5d 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt
@@ -236,8 +236,8 @@ fun Telemetry(universe: Universe, showControls: Boolean) {
((closest.pos - pos).mag() - closest.radius).toInt()
listOfNotNull(
landing?.let {
- "LND: ${it.planet.name.toUpperCase()}\n" +
- "JOB: ${it.text.toUpperCase()}"
+ "LND: ${it.planet.name.uppercase()}\n" +
+ "JOB: ${it.text.uppercase()}"
}
?: if (distToClosest < 10_000) {
"ALT: $distToClosest"
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index f692601edcb7..3c70fc15485a 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -96,6 +96,7 @@ public class SecureSettings {
Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED,
Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY,
Settings.Secure.ACCESSIBILITY_AUTOCLICK_PANEL_POSITION,
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK,
Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
Settings.Secure.PREFERRED_TTY_MODE,
Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index e42d3fb9da41..c09e45ed81a6 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -147,6 +147,7 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_AUTOCLICK_DELAY, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_AUTOCLICK_PANEL_POSITION, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Secure.ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_LARGE_POINTER_ICON, BOOLEAN_VALIDATOR);
VALIDATORS.put(
Secure.PREFERRED_TTY_MODE,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index c29a5a20a96f..167674a451b3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1722,6 +1722,9 @@ class SettingsProtoDumpUtil {
Settings.Secure.ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT,
SecureSettingsProto.Accessibility.AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT);
dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK,
+ SecureSettingsProto.Accessibility.AUTOCLICK_REVERT_TO_LEFT_CLICK);
+ dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED,
SecureSettingsProto.Accessibility.AUTOCLICK_ENABLED);
dumpSetting(s, p,
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 b9200c15944c..e9e61a718f08 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
@@ -44,6 +44,7 @@ class ComposedDigitalLayerController(private val clockCtx: ClockContext) :
val dozeState = DefaultClockController.AnimationState(1F)
override val view = FlexClockView(clockCtx)
+ override var onViewBoundsChanged by view::onViewBoundsChanged
init {
fun createController(cfg: LayerConfig) {
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 f24ad1c10c4a..9bb3bac824e9 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
@@ -17,6 +17,7 @@ import android.content.Context
import android.content.res.Resources
import android.graphics.Color
import android.graphics.Rect
+import android.graphics.RectF
import android.icu.text.NumberFormat
import android.util.TypedValue
import android.view.LayoutInflater
@@ -97,7 +98,12 @@ class DefaultClockController(
events.onLocaleChanged(Locale.getDefault())
}
- override fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) {
+ override fun initialize(
+ isDarkTheme: Boolean,
+ dozeFraction: Float,
+ foldFraction: Float,
+ onBoundsChanged: (RectF) -> Unit,
+ ) {
largeClock.recomputePadding(null)
largeClock.animations = LargeClockAnimations(largeClock.view, dozeFraction, foldFraction)
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 1a1033ba42e0..6dfd2268005f 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
@@ -16,6 +16,7 @@
package com.android.systemui.shared.clocks
+import android.graphics.RectF
import com.android.systemui.animation.GSFAxes
import com.android.systemui.customization.R
import com.android.systemui.plugins.clocks.AlarmData
@@ -102,9 +103,15 @@ class FlexClockController(private val clockCtx: ClockContext) : ClockController
}
}
- override fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) {
+ override fun initialize(
+ isDarkTheme: Boolean,
+ dozeFraction: Float,
+ foldFraction: Float,
+ onBoundsChanged: (RectF) -> Unit,
+ ) {
events.onFontAxesChanged(clockCtx.settings.axes)
smallClock.run {
+ layerController.onViewBoundsChanged = onBoundsChanged
events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
animations.doze(dozeFraction)
animations.fold(foldFraction)
@@ -112,6 +119,7 @@ class FlexClockController(private val clockCtx: ClockContext) : ClockController
}
largeClock.run {
+ layerController.onViewBoundsChanged = onBoundsChanged
events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
animations.doze(dozeFraction)
animations.fold(foldFraction)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt
index af00cc264208..336c66eed889 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shared.clocks
+import android.graphics.RectF
import android.view.View
import androidx.annotation.VisibleForTesting
import com.android.systemui.plugins.clocks.ClockAnimations
@@ -31,4 +32,5 @@ interface SimpleClockLayerController {
val config: ClockFaceConfig
@VisibleForTesting var fakeTimeMills: Long?
+ var onViewBoundsChanged: ((RectF) -> Unit)?
}
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 0b7ea1a335ef..97004ef6f9a9 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
@@ -85,6 +85,7 @@ open class SimpleDigitalHandLayerController(
override val view = SimpleDigitalClockTextView(clockCtx, isLargeClock)
private val logger = Logger(clockCtx.messageBuffer, TAG)
val timespec = DigitalTimespecHandler(layerCfg.timespec, layerCfg.dateTimeFormat)
+ override var onViewBoundsChanged by view::onViewBoundsChanged
@VisibleForTesting
override var fakeTimeMills: Long?
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 2d0ca5331299..c765ea9cc84c 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
@@ -100,6 +100,7 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) {
updateLocale(Locale.getDefault())
}
+ var onViewBoundsChanged: ((RectF) -> Unit)? = null
private val digitOffsets = mutableMapOf<Int, Float>()
protected fun calculateSize(
@@ -189,13 +190,21 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) {
fun updateLocation() {
val layoutBounds = this.layoutBounds ?: return
+ val bounds =
+ RectF(
+ layoutBounds.centerX() - measuredWidth / 2f,
+ layoutBounds.centerY() - measuredHeight / 2f,
+ layoutBounds.centerX() + measuredWidth / 2f,
+ layoutBounds.centerY() + measuredHeight / 2f,
+ )
setFrame(
- (layoutBounds.centerX() - measuredWidth / 2f).roundToInt(),
- (layoutBounds.centerY() - measuredHeight / 2f).roundToInt(),
- (layoutBounds.centerX() + measuredWidth / 2f).roundToInt(),
- (layoutBounds.centerY() + measuredHeight / 2f).roundToInt(),
+ bounds.left.roundToInt(),
+ bounds.top.roundToInt(),
+ bounds.right.roundToInt(),
+ bounds.bottom.roundToInt(),
)
updateChildFrames(isLayout = false)
+ onViewBoundsChanged?.let { it(bounds) }
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
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 015a82707ea2..5aea88de061c 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
@@ -117,6 +117,7 @@ open class SimpleDigitalClockTextView(
fidgetFontVariation = buildFidgetVariation(lsFontAxes).toFVar()
}
+ var onViewBoundsChanged: ((RectF) -> Unit)? = null
private val parser = DimensionParser(clockCtx.context)
var maxSingleDigitHeight = -1f
var maxSingleDigitWidth = -1f
@@ -497,6 +498,7 @@ open class SimpleDigitalClockTextView(
targetRect.right.roundToInt(),
targetRect.bottom.roundToInt(),
)
+ onViewBoundsChanged?.let { it(targetRect) }
return targetRect
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 189d554415d0..f4d4b1efa3e2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -25,6 +25,8 @@ import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
+import android.view.ViewTreeObserver
+import android.view.ViewTreeObserver.OnPreDrawListener
import android.view.WindowInsetsController
import android.widget.FrameLayout
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -720,6 +722,37 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
}
@Test
+ fun startAppearAnimation_ifDelayed() {
+ val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
+ whenever(view.isAppearAnimationDelayed).thenReturn(true)
+ val viewTreeObserver: ViewTreeObserver = mock()
+ whenever(view.viewTreeObserver).thenReturn(viewTreeObserver)
+
+ underTest.startAppearAnimationIfDelayed()
+
+ verify(view).alpha = 1f
+ verify(viewTreeObserver).addOnPreDrawListener(argumentCaptor.capture())
+ argumentCaptor.value.onPreDraw()
+
+ verify(view).startAppearAnimation(any(SecurityMode::class.java))
+ verify(view).setIsAppearAnimationDelayed(false)
+ }
+
+ @Test
+ fun appearAnimation_willNotStart_ifNotDelayed() {
+ whenever(view.isAppearAnimationDelayed).thenReturn(false)
+ val viewTreeObserver: ViewTreeObserver = mock()
+ whenever(view.viewTreeObserver).thenReturn(viewTreeObserver)
+
+ underTest.startAppearAnimationIfDelayed()
+
+ verify(view, never()).alpha
+ verify(viewTreeObserver, never()).addOnPreDrawListener(any())
+
+ verify(view, never()).startAppearAnimation(any(SecurityMode::class.java))
+ }
+
+ @Test
fun gravityReappliedOnConfigurationChange() {
// Set initial gravity
testableResources.addOverride(R.integer.keyguard_host_view_gravity, Gravity.CENTER)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 176824fd4c5d..2845f6a2983a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -452,6 +452,14 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
verify(keyguardPasswordView).setDisappearAnimationListener(any());
}
+ @Test
+ public void setupForDelayedAppear() {
+ mKeyguardSecurityContainer.setupForDelayedAppear();
+ assertThat(mKeyguardSecurityContainer.getTranslationY()).isEqualTo(0f);
+ assertThat(mKeyguardSecurityContainer.getAlpha()).isEqualTo(0f);
+ assertThat(mKeyguardSecurityContainer.isAppearAnimationDelayed()).isTrue();
+ }
+
private BackEvent createBackEvent(float touchX, float progress) {
return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT);
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java
index f53f964cd3d9..191ecccd5f71 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java
@@ -28,6 +28,8 @@ import static org.mockito.Mockito.when;
import android.animation.ValueAnimator;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
@@ -54,6 +56,7 @@ import com.android.systemui.scene.ui.view.WindowRootView;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
@@ -127,10 +130,16 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase {
@Mock
WindowRootView mWindowRootView;
+ @Mock
+ Resources mResources;
+
private SceneInteractor mSceneInteractor;
+ private KeyguardStateController mKeyguardStateController;
+
private static final float TOUCH_REGION = .3f;
private static final float MIN_BOUNCER_HEIGHT = .05f;
+ private final Configuration mConfiguration = new Configuration();
private static final Rect SCREEN_BOUNDS = new Rect(0, 0, 1024, 100);
private static final UserInfo CURRENT_USER_INFO = new UserInfo(
@@ -153,6 +162,8 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase {
public void setup() {
mKosmos = new KosmosJavaAdapter(this);
mSceneInteractor = spy(mKosmos.getSceneInteractor());
+ mKeyguardStateController = mKosmos.getKeyguardStateController();
+ mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT;
MockitoAnnotations.initMocks(this);
mTouchHandler = new BouncerSwipeTouchHandler(
@@ -172,7 +183,9 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase {
mKeyguardInteractor,
mSceneInteractor,
mKosmos.getShadeRepository(),
- Optional.of(() -> mWindowRootView));
+ Optional.of(() -> mWindowRootView),
+ mKeyguardStateController,
+ mKosmos.getCommunalSettingsInteractor());
when(mScrimManager.getCurrentController()).thenReturn(mScrimController);
when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator);
@@ -180,6 +193,9 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase {
when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE);
when(mTouchSession.getBounds()).thenReturn(SCREEN_BOUNDS);
when(mKeyguardInteractor.isKeyguardDismissible()).thenReturn(MutableStateFlow(false));
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true);
+ when(mWindowRootView.getResources()).thenReturn(mResources);
+ when(mResources.getConfiguration()).thenReturn(mConfiguration);
}
/**
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
index dd43d817cccc..e8dc6762cc92 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
@@ -16,6 +16,10 @@
package com.android.systemui.ambient.touch;
+import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf;
+
+import static com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2;
+
import static com.google.common.truth.Truth.assertThat;
import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
@@ -34,6 +38,8 @@ import static org.mockito.Mockito.when;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.Region;
import android.platform.test.annotations.DisableFlags;
@@ -63,6 +69,7 @@ import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
@@ -132,12 +139,16 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
@Mock
WindowRootView mWindowRootView;
+ Resources mResources;
+
@Mock
CommunalViewModel mCommunalViewModel;
@Mock
KeyguardInteractor mKeyguardInteractor;
+ private KeyguardStateController mKeyguardStateController;
+
@Captor
ArgumentCaptor<Rect> mRectCaptor;
@@ -147,6 +158,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
private static final int SCREEN_WIDTH_PX = 1024;
private static final int SCREEN_HEIGHT_PX = 100;
private static final float MIN_BOUNCER_HEIGHT = .05f;
+ private final Configuration mConfiguration = new Configuration();
private static final Rect SCREEN_BOUNDS = new Rect(0, 0, 1024, 100);
private static final UserInfo CURRENT_USER_INFO = new UserInfo(
@@ -157,7 +169,8 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
@Parameters(name = "{0}")
public static List<FlagsParameterization> getParams() {
- return SceneContainerFlagParameterizationKt.parameterizeSceneContainerFlag();
+ return SceneContainerFlagParameterizationKt
+ .andSceneContainer(allCombinationsOf(Flags.FLAG_GLANCEABLE_HUB_V2));
}
public BouncerSwipeTouchHandlerTest(FlagsParameterization flags) {
@@ -168,7 +181,13 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
@Before
public void setup() {
mKosmos = new KosmosJavaAdapter(this);
+ mContext.ensureTestableResources();
+ mResources = mContext.getResources();
+ overrideConfiguration(mConfiguration);
+ mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT;
+
mSceneInteractor = spy(mKosmos.getSceneInteractor());
+ mKeyguardStateController = mKosmos.getKeyguardStateController();
MockitoAnnotations.initMocks(this);
mTouchHandler = new BouncerSwipeTouchHandler(
@@ -188,7 +207,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
mKeyguardInteractor,
mSceneInteractor,
mKosmos.getShadeRepository(),
- Optional.of(() -> mWindowRootView)
+ Optional.of(() -> mWindowRootView),
+ mKeyguardStateController,
+ mKosmos.getCommunalSettingsInteractor()
);
when(mScrimManager.getCurrentController()).thenReturn(mScrimController);
@@ -197,6 +218,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE);
when(mTouchSession.getBounds()).thenReturn(SCREEN_BOUNDS);
when(mKeyguardInteractor.isKeyguardDismissible()).thenReturn(MutableStateFlow(false));
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true);
+ when(mWindowRootView.getResources()).thenReturn(mResources);
+ setCommunalV2ConfigEnabled(true);
}
/**
@@ -586,6 +610,43 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
verify(mUiEventLogger).log(BouncerSwipeTouchHandler.DreamEvent.DREAM_BOUNCER_FULLY_VISIBLE);
}
+ @Test
+ @DisableFlags(Flags.FLAG_SCENE_CONTAINER)
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ public void swipeUpAboveThresholdInLandscape_keyguardRotationNotAllowed_showsBouncer() {
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false);
+ mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
+
+ final float swipeUpPercentage = .1f;
+ // The upward velocity is ignored.
+ final float velocityY = -1;
+ swipeToPosition(swipeUpPercentage, velocityY);
+
+ // Ensure show bouncer scrimmed
+ verify(mScrimController).show(true);
+ verify(mValueAnimatorCreator, never()).create(anyFloat(), anyFloat());
+ verify(mValueAnimator, never()).start();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_SCENE_CONTAINER)
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ public void swipeUpBelowThreshold_inLandscapeKeyguardRotationNotAllowed_noBouncer() {
+ mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
+
+ final float swipeUpPercentage = .02f;
+ // The upward velocity is ignored.
+ final float velocityY = -1;
+ swipeToPosition(swipeUpPercentage, velocityY);
+
+ // no bouncer shown scrimmed
+ verify(mScrimController, never()).show(true);
+ // on touch end, bouncer hidden
+ verify(mValueAnimatorCreator).create(eq(1 - swipeUpPercentage),
+ eq(KeyguardBouncerConstants.EXPANSION_HIDDEN));
+ verify(mValueAnimator, never()).addListener(any());
+ }
+
/**
* Tests that swiping up with a speed above the set threshold will continue the expansion.
*/
@@ -672,4 +733,15 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
inputEventListenerCaptor.getValue().onInputEvent(upEvent);
}
+
+ private void setCommunalV2ConfigEnabled(boolean enabled) {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_glanceableHubEnabled,
+ enabled);
+ }
+
+ private void overrideConfiguration(Configuration configuration) {
+ mContext.getOrCreateTestableResources().overrideConfiguration(
+ configuration);
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
index 4d027088ca1a..5249bbe2a861 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
@@ -26,7 +26,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.biometricStatusRepository
import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
@@ -50,7 +53,6 @@ import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.inOrder
-import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
@@ -67,6 +69,7 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
@Mock private lateinit var layoutInflater: LayoutInflater
@Mock private lateinit var sideFpsView: View
+ @Mock private lateinit var lottieAnimationView: LottieAnimationView
@Captor private lateinit var viewCaptor: ArgumentCaptor<View>
@Before
@@ -76,7 +79,7 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() {
context.addMockSystemService(WindowManager::class.java, kosmos.windowManager)
`when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sideFpsView)
`when`(sideFpsView.requireViewById<LottieAnimationView>(eq(R.id.sidefps_animation)))
- .thenReturn(mock(LottieAnimationView::class.java))
+ .thenReturn(lottieAnimationView)
}
@Test
@@ -184,6 +187,20 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() {
}
}
+ @Test
+ fun verifyToggleAnimation_onSideFpsIndicatorViewClickedWhileEnrolling() {
+ kosmos.testScope.runTest {
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ setupTestConfiguration(isInRearDisplayMode = false)
+ val clickListenerCaptor = ArgumentCaptor.forClass(View.OnClickListener::class.java)
+ verify(sideFpsView).setOnClickListener(clickListenerCaptor.capture())
+ clickListenerCaptor.value.onClick(sideFpsView)
+ verify(lottieAnimationView).toggleAnimation()
+ }
+ }
+
private suspend fun TestScope.setupTestConfiguration(isInRearDisplayMode: Boolean) {
kosmos.fingerprintPropertyRepository.setProperties(
sensorId = 1,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index dd4af7bb780e..53ddcfaf9576 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -20,6 +20,7 @@ import android.content.testableContext
import android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
@@ -39,13 +40,22 @@ import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.res.R
+import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.transitionState
import com.android.systemui.testKosmos
import com.android.systemui.util.settings.fakeGlobalSettings
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -368,6 +378,76 @@ class BouncerInteractorTest : SysuiTestCase() {
testableResources.removeOverride(R.bool.can_use_one_handed_bouncer)
}
+ @Test
+ fun bouncerExpansion_lockscreenToBouncer() =
+ kosmos.runTest {
+ val bouncerExpansion by collectLastValue(underTest.bouncerExpansion)
+
+ val progress = MutableStateFlow(0f)
+ kosmos.sceneContainerRepository.setTransitionState(transitionState)
+ transitionState.value =
+ ObservableTransitionState.Transition.showOverlay(
+ overlay = Overlays.Bouncer,
+ fromScene = Scenes.Lockscreen,
+ currentOverlays = flowOf(emptySet()),
+ progress = progress,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+
+ assertThat(bouncerExpansion).isEqualTo(0f)
+
+ progress.value = 1f
+ assertThat(bouncerExpansion).isEqualTo(1f)
+ }
+
+ @Test
+ fun bouncerExpansion_BouncerToLockscreen() =
+ kosmos.runTest {
+ val bouncerExpansion by collectLastValue(underTest.bouncerExpansion)
+
+ val progress = MutableStateFlow(0f)
+ kosmos.sceneContainerRepository.setTransitionState(transitionState)
+ transitionState.value =
+ ObservableTransitionState.Transition.hideOverlay(
+ overlay = Overlays.Bouncer,
+ toScene = Scenes.Lockscreen,
+ currentOverlays = flowOf(emptySet()),
+ progress = progress,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+
+ assertThat(bouncerExpansion).isEqualTo(1f)
+
+ progress.value = 1f
+ assertThat(bouncerExpansion).isEqualTo(0f)
+ }
+
+ @Test
+ fun bouncerExpansion_shadeToLockscreenUnderBouncer() =
+ kosmos.runTest {
+ val bouncerExpansion by collectLastValue(underTest.bouncerExpansion)
+
+ val progress = MutableStateFlow(0f)
+ kosmos.sceneContainerRepository.setTransitionState(transitionState)
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Shade,
+ toScene = Scenes.Lockscreen,
+ currentScene = flowOf(Scenes.Lockscreen),
+ progress = progress,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ currentOverlays = setOf(Overlays.Bouncer),
+ )
+
+ assertThat(bouncerExpansion).isEqualTo(1f)
+
+ progress.value = 1f
+ assertThat(bouncerExpansion).isEqualTo(1f)
+ }
+
companion object {
private const val MESSAGE_ENTER_YOUR_PIN = "Enter your PIN"
private const val MESSAGE_ENTER_YOUR_PASSWORD = "Enter your password"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index 7051f81cfc88..f58391496e65 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -22,6 +22,7 @@ import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.provider.Settings
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
@@ -38,8 +39,13 @@ import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.collectLastValue
@@ -56,11 +62,15 @@ import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.advanceTimeBy
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.kotlin.verify
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
@@ -93,10 +103,12 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
communalInteractor = communalInteractor,
communalSettingsInteractor = communalSettingsInteractor,
communalSceneInteractor = communalSceneInteractor,
+ keyguardTransitionInteractor = keyguardTransitionInteractor,
keyguardInteractor = keyguardInteractor,
systemSettings = fakeSettings,
notificationShadeWindowController = notificationShadeWindowController,
bgScope = applicationCoroutineScope,
+ applicationScope = applicationCoroutineScope,
mainDispatcher = testDispatcher,
uiEventLogger = uiEventLoggerFake,
)
@@ -111,13 +123,13 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
UserHandle.USER_CURRENT,
)
fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
+ setCommunalV2ConfigEnabled(true)
underTest.start()
// Make communal available so that communalInteractor.desiredScene accurately reflects
// scene changes instead of just returning Blank.
runBlocking { setCommunalAvailable(true) }
- setCommunalV2ConfigEnabled(true)
}
}
@@ -414,6 +426,107 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
}
+ @Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun glanceableHubOrientationAware_idleOnCommunal() =
+ kosmos.runTest {
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true)
+ }
+
+ @Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun glanceableHubOrientationAware_transitioningToCommunal() =
+ kosmos.runTest {
+ val progress = MutableStateFlow(0f)
+ val targetScene = CommunalScenes.Communal
+ val currentScene = CommunalScenes.Blank
+ val transitionState =
+ MutableStateFlow(
+ ObservableTransitionState.Transition(
+ fromScene = currentScene,
+ toScene = targetScene,
+ currentScene = flowOf(targetScene),
+ progress = progress,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ )
+ communalSceneInteractor.setTransitionState(transitionState)
+
+ // Partially transition.
+ progress.value = .4f
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
+
+ verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true)
+ }
+
+ @Test
+ @DisableFlags(FLAG_SCENE_CONTAINER)
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun glanceableHubOrientationAware_communalToDreaming() =
+ kosmos.runTest {
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true)
+ Mockito.clearInvocations(notificationShadeWindowController)
+
+ val progress = MutableStateFlow(0f)
+ val currentScene = CommunalScenes.Communal
+ val targetScene = CommunalScenes.Blank
+ val transitionState =
+ MutableStateFlow(
+ ObservableTransitionState.Transition(
+ fromScene = currentScene,
+ toScene = targetScene,
+ currentScene = flowOf(targetScene),
+ progress = progress,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ )
+ communalSceneInteractor.setTransitionState(transitionState)
+
+ // Partially transitioned out of Communal scene
+ progress.value = .4f
+
+ // Started keyguard transitioning from hub -> dreaming.
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.DREAMING,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true)
+ Mockito.clearInvocations(notificationShadeWindowController)
+
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.DREAMING,
+ transitionState = TransitionState.RUNNING,
+ value = 0.5f,
+ )
+
+ // Transitioned to dreaming.
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.DREAMING,
+ transitionState = TransitionState.FINISHED,
+ value = 1f,
+ )
+ // Not on hub anymore, let other states take control
+ verify(notificationShadeWindowController).setGlanceableHubOrientationAware(false)
+ }
+
/**
* Advances time by duration + 1 millisecond, to ensure that tasks scheduled to run at
* currentTime + duration are scheduled.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
index 77d7091e463a..dc21f0692c9e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
@@ -134,7 +134,7 @@ class CommunalSceneInteractorTest(flags: FlagsParameterization) : SysuiTestCase(
underTest.snapToScene(
CommunalScenes.Communal,
"test",
- ActivityTransitionAnimator.TIMINGS.totalDuration
+ ActivityTransitionAnimator.TIMINGS.totalDuration,
)
assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
advanceTimeBy(ActivityTransitionAnimator.TIMINGS.totalDuration)
@@ -269,6 +269,48 @@ class CommunalSceneInteractorTest(flags: FlagsParameterization) : SysuiTestCase(
@DisableFlags(FLAG_SCENE_CONTAINER)
@Test
+ fun isTransitioningToOrIdleOnCommunal() =
+ testScope.runTest {
+ // isIdleOnCommunal is false when not on communal.
+ val isTransitioningToOrIdleOnCommunal by
+ collectLastValue(underTest.isTransitioningToOrIdleOnCommunal)
+ assertThat(isTransitioningToOrIdleOnCommunal).isEqualTo(false)
+
+ val transitionState: MutableStateFlow<ObservableTransitionState> =
+ MutableStateFlow(
+ ObservableTransitionState.Transition(
+ fromScene = CommunalScenes.Blank,
+ toScene = CommunalScenes.Communal,
+ currentScene = flowOf(CommunalScenes.Communal),
+ progress = flowOf(0f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ )
+
+ // Start transition to communal.
+ repository.setTransitionState(transitionState)
+ assertThat(isTransitioningToOrIdleOnCommunal).isEqualTo(true)
+
+ // Finish transition to communal
+ transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal)
+ assertThat(isTransitioningToOrIdleOnCommunal).isEqualTo(true)
+
+ // Start transition away from communal.
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = CommunalScenes.Communal,
+ toScene = CommunalScenes.Blank,
+ currentScene = flowOf(CommunalScenes.Blank),
+ progress = flowOf(.1f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ assertThat(isTransitioningToOrIdleOnCommunal).isEqualTo(false)
+ }
+
+ @DisableFlags(FLAG_SCENE_CONTAINER)
+ @Test
fun isCommunalVisible() =
testScope.runTest {
// isCommunalVisible is false when not on communal.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt
index 6b9e23abd9a4..135e9a55e8b5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt
@@ -16,28 +16,46 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.content.res.mainResources
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND
+import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.transitions.blurConfig
+import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.collectValues
+import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
+import com.android.systemui.statusbar.policy.keyguardStateController
import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
class GlanceableHubToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
- private val kosmos = testKosmos()
+ private val kosmos =
+ testKosmos().apply { mainResources = mContext.orCreateTestableResources.resources }
private val underTest by lazy { kosmos.glanceableHubToPrimaryBouncerTransitionViewModel }
+ @Before
+ fun setUp() {
+ with(kosmos) { setCommunalV2ConfigEnabled(true) }
+ }
+
@Test
@DisableSceneContainer
@DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND)
@@ -84,4 +102,81 @@ class GlanceableHubToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
},
)
}
+
+ @Test
+ @DisableSceneContainer
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun willDelayBouncerAppearAnimation_flagDisabled_isFalse() =
+ kosmos.runTest {
+ // keyguard rotation is not allowed on device.
+ whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false)
+
+ val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+ runCurrent()
+ // Device is idle on communal.
+ assertThat(isIdleOnCommunal).isTrue()
+
+ // in landscape
+ assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isFalse()
+ // in portrait
+ assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse()
+ }
+
+ @Test
+ @DisableSceneContainer
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun willDelayBouncerAppearAnimation_keyguardRotationAllowed_isFalse() =
+ kosmos.runTest {
+ // Keyguard rotation is allowed on device.
+ whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true)
+
+ val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+ runCurrent()
+ // Device is idle on communal.
+ assertThat(isIdleOnCommunal).isTrue()
+
+ // in landscape
+ assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isFalse()
+ // in portrait
+ assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse()
+ }
+
+ @Test
+ @DisableSceneContainer
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun willDelayBouncerAppearAnimation_isNotIdleOnCommunal_isFalse() =
+ kosmos.runTest {
+ whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false)
+
+ val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal)
+ communalSceneInteractor.changeScene(CommunalScenes.Blank, "test")
+ runCurrent()
+ // Device is not on communal.
+ assertThat(isIdleOnCommunal).isFalse()
+
+ // in landscape
+ assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isFalse()
+ // in portrait
+ assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse()
+ }
+
+ @Test
+ @DisableSceneContainer
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun willDelayBouncerAppearAnimation_isIdleOnCommunalAndKeyguardRotationIsNotAllowed() =
+ kosmos.runTest {
+ whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false)
+ val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+ runCurrent()
+ // Device is idle on communal.
+ assertThat(isIdleOnCommunal).isTrue()
+
+ // Will delay in landscape
+ assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isTrue()
+ // Won't delay in portrait
+ assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 764068ec1bf5..3407cd50e76f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -84,12 +84,12 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
-import java.util.List;
-import java.util.concurrent.Executor;
-
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
+import java.util.List;
+import java.util.concurrent.Executor;
+
@RunWith(ParameterizedAndroidJunit4.class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
@@ -410,6 +410,19 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
}
@Test
+ public void hubOrientationAware_layoutParamsUpdated() {
+ mNotificationShadeWindowController.setKeyguardShowing(false);
+ mNotificationShadeWindowController.setBouncerShowing(false);
+ mNotificationShadeWindowController.setGlanceableHubOrientationAware(true);
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false);
+ mNotificationShadeWindowController.onConfigChanged(new Configuration());
+
+ verify(mWindowManager, atLeastOnce()).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat(mLayoutParameters.getValue().screenOrientation)
+ .isEqualTo(ActivityInfo.SCREEN_ORIENTATION_USER);
+ }
+
+ @Test
public void batchApplyWindowLayoutParams_doesNotDispatchEvents() {
mNotificationShadeWindowController.setForceDozeBrightness(true);
verify(mWindowManager).updateViewLayout(any(), any());
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index 9eba410ffdb5..4f301031e77c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -108,7 +108,7 @@ class DefaultClockProviderTest : SysuiTestCase() {
verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA)
verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA)
- clock.initialize(true, 0f, 0f)
+ clock.initialize(true, 0f, 0f, {})
val expectedColor = 0
verify(mockSmallClockView).setColors(DOZE_COLOR, expectedColor)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
index 32fec3277f18..4c1f6450dd78 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
@@ -13,6 +13,7 @@
*/
package com.android.systemui.plugins.clocks
+import android.graphics.RectF
import com.android.systemui.plugins.annotations.ProtectedInterface
import com.android.systemui.plugins.annotations.SimpleProperty
import java.io.PrintWriter
@@ -37,7 +38,12 @@ interface ClockController {
val events: ClockEvents
/** Initializes various rendering parameters. If never called, provides reasonable defaults. */
- fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float)
+ fun initialize(
+ isDarkTheme: Boolean,
+ dozeFraction: Float,
+ foldFraction: Float,
+ onBoundsChanged: (RectF) -> Unit,
+ )
/** Optional method for dumping debug information */
fun dump(pw: PrintWriter)
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 6d446453d9f7..24fd86076d64 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -115,6 +115,7 @@
<dimen name="below_clock_padding_end">16dp</dimen>
<dimen name="below_clock_padding_start_icons">28dp</dimen>
<dimen name="smartspace_padding_horizontal">16dp</dimen>
+ <dimen name="smartspace_padding_vertical">12dp</dimen>
<!-- Proportion of the screen height to use to set the maximum height of the bouncer to when
the device is in the DEVICE_POSTURE_HALF_OPENED posture, for the PIN/pattern entry. 0 will
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 1b8282bf9b93..94342349e727 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -21,6 +21,7 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Resources
+import android.graphics.RectF
import android.os.Trace
import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
import android.provider.Settings.Global.ZEN_MODE_OFF
@@ -78,7 +79,7 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.Job
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -147,7 +148,7 @@ constructor(
val clockStr = clock.toString()
loggers.forEach { it.d({ "New Clock: $str1" }) { str1 = clockStr } }
- clock.initialize(isDarkTheme(), dozeAmount, 0f)
+ clock.initialize(isDarkTheme(), dozeAmount.value, 0f, { onClockBoundsChanged.value = it })
if (!regionSamplingEnabled) {
updateColors()
@@ -240,17 +241,16 @@ constructor(
private var smallClockFrame: ViewGroup? = null
private var onGlobalLayoutListener: OnGlobalLayoutListener? = null
- private var isDozing = false
- private set
-
private var isCharging = false
- private var dozeAmount = 0f
private var isKeyguardVisible = false
private var isRegistered = false
private var disposableHandle: DisposableHandle? = null
private val regionSamplingEnabled = featureFlags.isEnabled(REGION_SAMPLING)
private var largeClockOnSecondaryDisplay = false
+ val dozeAmount = MutableStateFlow(0f)
+ val onClockBoundsChanged = MutableStateFlow<RectF?>(null)
+
private fun isDarkTheme(): Boolean {
val isLightTheme = TypedValue()
context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true)
@@ -306,7 +306,7 @@ constructor(
var smallTimeListener: TimeListener? = null
var largeTimeListener: TimeListener? = null
val shouldTimeListenerRun: Boolean
- get() = isKeyguardVisible && dozeAmount < DOZE_TICKRATE_THRESHOLD
+ get() = isKeyguardVisible && dozeAmount.value < DOZE_TICKRATE_THRESHOLD
private var weatherData: WeatherData? = null
private var zenData: ZenData? = null
@@ -466,7 +466,6 @@ constructor(
disposableHandle =
parent.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
- listenForDozing(this)
if (ModesUi.isEnabled) {
listenForDnd(this)
}
@@ -576,17 +575,17 @@ constructor(
}
private fun handleDoze(doze: Float) {
- dozeAmount = doze
clock?.run {
Trace.beginSection("$TAG#smallClock.animations.doze")
- smallClock.animations.doze(dozeAmount)
+ smallClock.animations.doze(doze)
Trace.endSection()
Trace.beginSection("$TAG#largeClock.animations.doze")
- largeClock.animations.doze(dozeAmount)
+ largeClock.animations.doze(doze)
Trace.endSection()
}
smallTimeListener?.update(doze < DOZE_TICKRATE_THRESHOLD)
largeTimeListener?.update(doze < DOZE_TICKRATE_THRESHOLD)
+ dozeAmount.value = doze
}
@VisibleForTesting
@@ -642,18 +641,6 @@ constructor(
}
}
- @VisibleForTesting
- internal fun listenForDozing(scope: CoroutineScope): Job {
- return scope.launch {
- combine(keyguardInteractor.dozeAmount, keyguardInteractor.isDozing) {
- localDozeAmount,
- localIsDozing ->
- localDozeAmount > dozeAmount || localIsDozing
- }
- .collect { localIsDozing -> isDozing = localIsDozing }
- }
- }
-
class TimeListener(val clockFace: ClockFaceController, val executor: DelayableExecutor) {
val predrawListener =
ViewTreeObserver.OnPreDrawListener {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 73dc28230e65..e2f3955263a1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -172,6 +172,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
private boolean mIsDragging;
private float mStartTouchY = -1;
private boolean mDisappearAnimRunning;
+ private boolean mIsAppearAnimationDelayed;
private SwipeListener mSwipeListener;
private ViewMode mViewMode = new DefaultViewMode();
private boolean mIsInteractable;
@@ -583,6 +584,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
return false;
}
+ boolean isAppearAnimationDelayed() {
+ return mIsAppearAnimationDelayed;
+ }
+
void addMotionEventListener(Gefingerpoken listener) {
mMotionEventListeners.add(listener);
}
@@ -624,6 +629,19 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
mViewMode.startAppearAnimation(securityMode);
}
+ /**
+ * Set view translationY and alpha as we delay bouncer animation.
+ */
+ public void setupForDelayedAppear() {
+ setTranslationY(0f);
+ setAlpha(0f);
+ setIsAppearAnimationDelayed(true);
+ }
+
+ public void setIsAppearAnimationDelayed(boolean isDelayed) {
+ mIsAppearAnimationDelayed = isDelayed;
+ }
+
private void beginJankInstrument(int cuj) {
KeyguardInputView securityView = mSecurityViewFlipper.getSecurityView();
if (securityView == null) return;
@@ -812,6 +830,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
public void reset() {
mViewMode.reset();
mDisappearAnimRunning = false;
+ mIsAppearAnimationDelayed = false;
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index d10fce416150..198c1cb08647 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -18,6 +18,7 @@ package com.android.keyguard;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISSIBLE_KEYGUARD;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
@@ -385,6 +386,10 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
boolean useSplitBouncer = orientation == ORIENTATION_LANDSCAPE;
mSecurityViewFlipperController.updateConstraints(useSplitBouncer);
}
+ if (orientation == ORIENTATION_PORTRAIT) {
+ // If there is any delayed bouncer appear animation it can start now
+ startAppearAnimationIfDelayed();
+ }
}
@Override
@@ -845,6 +850,16 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
}
+ /** Start appear animation which was previously delayed from opening bouncer in landscape. */
+ public void startAppearAnimationIfDelayed() {
+ if (!mView.isAppearAnimationDelayed()) {
+ return;
+ }
+ setAlpha(1f);
+ appear();
+ mView.setIsAppearAnimationDelayed(false);
+ }
+
/** Called when the bouncer changes visibility. */
public void onBouncerVisibilityChanged(boolean isVisible) {
if (!isVisible) {
@@ -1301,4 +1316,13 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
mView.setTranslationY(scaledFraction * mTranslationY);
}
+
+ /** Set up view for delayed appear animation. */
+ public void setupForDelayedAppear() {
+ mView.setupForDelayedAppear();
+ }
+
+ public boolean isLandscapeOrientation() {
+ return mLastOrientation == Configuration.ORIENTATION_LANDSCAPE;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt
index d8e7a168ef3c..97de78c41af7 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt
@@ -18,6 +18,7 @@ package com.android.systemui.ambient.touch
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
+import android.content.res.Configuration
import android.graphics.Rect
import android.graphics.Region
import android.util.Log
@@ -36,6 +37,7 @@ import com.android.systemui.ambient.touch.dagger.BouncerSwipeModule
import com.android.systemui.ambient.touch.scrim.ScrimController
import com.android.systemui.ambient.touch.scrim.ScrimManager
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
+import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
@@ -46,6 +48,7 @@ import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.wm.shell.animation.FlingAnimationUtils
import java.util.Optional
import javax.inject.Inject
@@ -82,6 +85,8 @@ constructor(
private val sceneInteractor: SceneInteractor,
private val shadeRepository: ShadeRepository,
private val windowRootViewProvider: Optional<Provider<WindowRootView>>,
+ private val keyguardStateController: KeyguardStateController,
+ communalSettingsInteractor: CommunalSettingsInteractor,
) : TouchHandler {
/** An interface for creating ValueAnimators. */
interface ValueAnimatorCreator {
@@ -101,6 +106,8 @@ constructor(
private var capture: Boolean? = null
private var expanded: Boolean = false
private var touchSession: TouchSession? = null
+ private var isUserTrackingExpansionDisabled: Boolean = false
+ private var isKeyguardScreenRotationAllowed: Boolean = false
private val scrimManagerCallback =
ScrimManager.Callback { controller ->
currentScrimController?.reset()
@@ -121,6 +128,9 @@ constructor(
distanceX: Float,
distanceY: Float,
): Boolean {
+ val isLandscape =
+ windowRootView.resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE
if (capture == null) {
capture =
if (Flags.dreamOverlayBouncerSwipeDirectionFiltering()) {
@@ -137,7 +147,9 @@ constructor(
// reset expanding
expanded = false
// Since the user is dragging the bouncer up, set scrimmed to false.
- currentScrimController?.show()
+ if (isKeyguardScreenRotationAllowed || !isLandscape) {
+ currentScrimController?.show(false)
+ }
if (SceneContainerFlag.isEnabled) {
sceneInteractor.onRemoteUserInputStarted("bouncer touch handler")
@@ -172,6 +184,37 @@ constructor(
return true
}
+ if (touchSession == null) {
+ return true
+ }
+ val screenTravelPercentage =
+ (abs((y - e2.y).toDouble()) / touchSession!!.bounds.height()).toFloat()
+
+ if (communalSettingsInteractor.isV2FlagEnabled()) {
+ if (isUserTrackingExpansionDisabled) return true
+ // scrolling up in landscape orientation but device doesn't allow keyguard
+ // screen rotation
+ if (y > e2.y && !isKeyguardScreenRotationAllowed && isLandscape) {
+ velocityTracker!!.computeCurrentVelocity(1000)
+ currentExpansion = 1 - screenTravelPercentage
+ expanded =
+ shouldExpandBouncer(
+ velocityTracker!!.yVelocity,
+ velocityTracker!!.xVelocity,
+ EXPANSION_FROM_LANDSCAPE_THRESHOLD,
+ currentExpansion,
+ )
+ if (expanded) {
+ // Once scroll past the percentage threshold, show bouncer scrimmed,
+ // so that user won't be required to drag up and then right to keep
+ // bouncer open after screen rotates to portrait.
+ currentScrimController?.show(true)
+ isUserTrackingExpansionDisabled = true
+ }
+ return true
+ }
+ }
+
if (SceneContainerFlag.isEnabled) {
windowRootView.dispatchTouchEvent(e2)
} else {
@@ -182,12 +225,7 @@ constructor(
// is fully hidden at full expansion (1) and fully visible when fully
// collapsed
// (0).
- touchSession?.apply {
- val screenTravelPercentage =
- (abs((this@outer.y - e2.y).toDouble()) / getBounds().height())
- .toFloat()
- setPanelExpansion(1 - screenTravelPercentage)
- }
+ touchSession?.apply { setPanelExpansion(1 - screenTravelPercentage) }
}
}
@@ -262,6 +300,7 @@ constructor(
}
scrimManager.addCallback(scrimManagerCallback)
currentScrimController = scrimManager.currentController
+ isKeyguardScreenRotationAllowed = keyguardStateController.isKeyguardScreenRotationAllowed()
shadeRepository.setLegacyShadeTracking(true)
session.registerCallback {
@@ -271,6 +310,7 @@ constructor(
scrimManager.removeCallback(scrimManagerCallback)
capture = null
touchSession = null
+ isUserTrackingExpansionDisabled = false
if (!Flags.communalBouncerDoNotModifyPluginOpen()) {
notificationShadeWindowController.setForcePluginOpen(false, this)
}
@@ -299,14 +339,25 @@ constructor(
return
}
+ // We are already in progress of opening bouncer scrimmed
+ if (isUserTrackingExpansionDisabled) {
+ // User is done scrolling, reset
+ isUserTrackingExpansionDisabled = false
+ return
+ }
+
// We must capture the resulting velocities as resetMonitor() will clear these
// values.
velocityTracker!!.computeCurrentVelocity(1000)
val verticalVelocity = velocityTracker!!.yVelocity
- val horizontalVelocity = velocityTracker!!.xVelocity
- val velocityVector =
- hypot(horizontalVelocity.toDouble(), verticalVelocity.toDouble()).toFloat()
- expanded = !flingRevealsOverlay(verticalVelocity, velocityVector)
+ expanded =
+ shouldExpandBouncer(
+ verticalVelocity,
+ velocityTracker!!.xVelocity,
+ FLING_PERCENTAGE_THRESHOLD,
+ currentExpansion,
+ )
+
val expansion =
if (expanded!!) KeyguardBouncerConstants.EXPANSION_VISIBLE
else KeyguardBouncerConstants.EXPANSION_HIDDEN
@@ -339,11 +390,27 @@ constructor(
return animator
}
- protected fun flingRevealsOverlay(velocity: Float, velocityVector: Float): Boolean {
+ private fun shouldExpandBouncer(
+ verticalVelocity: Float,
+ horizontalVelocity: Float,
+ threshold: Float,
+ expansion: Float,
+ ): Boolean {
+ val velocityVector =
+ hypot(horizontalVelocity.toDouble(), verticalVelocity.toDouble()).toFloat()
+ return !flingRevealsOverlay(verticalVelocity, velocityVector, threshold, expansion)
+ }
+
+ protected fun flingRevealsOverlay(
+ velocity: Float,
+ velocityVector: Float,
+ threshold: Float,
+ expansion: Float,
+ ): Boolean {
// Fully expand the space above the bouncer, if the user has expanded the bouncer less
// than halfway or final velocity was positive, indicating a downward direction.
return if (abs(velocityVector.toDouble()) < flingAnimationUtils.minVelocityPxPerSecond) {
- currentExpansion > FLING_PERCENTAGE_THRESHOLD
+ expansion > threshold
} else {
velocity > 0
}
@@ -390,6 +457,7 @@ constructor(
companion object {
const val FLING_PERCENTAGE_THRESHOLD = 0.5f
+ const val EXPANSION_FROM_LANDSCAPE_THRESHOLD = 0.95f
private const val TAG = "BouncerSwipeTouchHandler"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/BouncerScrimController.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/BouncerScrimController.java
index 94c998267598..6f2dd799c409 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/BouncerScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/BouncerScrimController.java
@@ -33,8 +33,8 @@ public class BouncerScrimController implements ScrimController {
}
@Override
- public void show() {
- mStatusBarKeyguardViewManager.showPrimaryBouncer(false);
+ public void show(boolean scrimmed) {
+ mStatusBarKeyguardViewManager.showPrimaryBouncer(scrimmed);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/ScrimController.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/ScrimController.java
index 00543523ec2e..90cbd258f03e 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/ScrimController.java
@@ -25,8 +25,9 @@ import com.android.systemui.shade.ShadeExpansionChangeEvent;
public interface ScrimController {
/**
* Called at the start of expansion before any expansion amount updates.
+ * @param scrimmed true when the bouncer should show scrimmed, false when user will be dragging.
*/
- default void show() {
+ default void show(boolean scrimmed) {
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
index bbf9a19012a4..30b98a658821 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -137,6 +137,9 @@ constructor(
)
bind(overlayView!!, overlayViewModel, windowManager.get())
overlayView!!.visibility = View.INVISIBLE
+ overlayView!!.setOnClickListener { v ->
+ v.requireViewById<LottieAnimationView>(R.id.sidefps_animation).toggleAnimation()
+ }
Log.d(TAG, "show(): adding overlayView $overlayView")
windowManager.get().addView(overlayView, overlayViewModel.defaultOverlayViewParams)
}
@@ -234,3 +237,11 @@ private fun LottieAnimationView.addOverlayDynamicColor(colorCallbacks: List<Lott
resumeAnimation()
}
}
+
+fun LottieAnimationView.toggleAnimation() {
+ if (isAnimating) {
+ pauseAnimation()
+ } else {
+ resumeAnimation()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 75503e8575f0..b26a2c08532e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -17,7 +17,9 @@
package com.android.systemui.bouncer.domain.interactor
import android.app.StatusBarManager.SESSION_KEYGUARD
+import com.android.app.tracing.FlowTracing.traceAsCounter
import com.android.app.tracing.coroutines.asyncTraced as async
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.internal.logging.UiEventLogger
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
@@ -38,9 +40,12 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInt
import com.android.systemui.log.SessionTracker
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
+import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ShadeDisplayAware
+import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -49,7 +54,9 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
/** Encapsulates business logic and application state accessing use-cases. */
@@ -65,6 +72,7 @@ constructor(
private val powerInteractor: PowerInteractor,
private val uiEventLogger: UiEventLogger,
private val sessionTracker: SessionTracker,
+ sceneInteractor: SceneInteractor,
sceneBackInteractor: SceneBackInteractor,
@ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor,
) {
@@ -149,6 +157,31 @@ constructor(
val dismissDestination: Flow<SceneKey> =
sceneBackInteractor.backScene.map { it ?: Scenes.Lockscreen }
+ /** The amount [0-1] that the Bouncer Overlay has been transitioned to. */
+ val bouncerExpansion: Flow<Float> =
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.transitionState.flatMapLatestConflated { state ->
+ when (state) {
+ is ObservableTransitionState.Idle ->
+ flowOf(if (Overlays.Bouncer in state.currentOverlays) 1f else 0f)
+ is ObservableTransitionState.Transition ->
+ if (state.toContent == Overlays.Bouncer) {
+ state.progress
+ } else if (state.fromContent == Overlays.Bouncer) {
+ state.progress.map { progress -> 1 - progress }
+ } else {
+ state.currentOverlays().map {
+ if (Overlays.Bouncer in it) 1f else 0f
+ }
+ }
+ }
+ }
+ } else {
+ flowOf()
+ }
+ .distinctUntilChanged()
+ .traceAsCounter("bouncer_expansion") { (it * 100f).toInt() }
+
/** Notifies that the user has places down a pointer, not necessarily dragging just yet. */
fun onDown() {
falsingInteractor.avoidGesture()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
index 7f268315e566..5d64219c7f90 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
@@ -15,6 +15,7 @@ import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToPrimaryBouncerTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.log.BouncerLogger
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
@@ -30,6 +31,8 @@ data class LegacyBouncerDependencies
constructor(
val viewModel: KeyguardBouncerViewModel,
val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
+ val glanceableHubToPrimaryBouncerTransitionViewModel:
+ GlanceableHubToPrimaryBouncerTransitionViewModel,
val componentFactory: KeyguardBouncerComponent.Factory,
val messageAreaControllerFactory: KeyguardMessageAreaController.Factory,
val bouncerMessageInteractor: BouncerMessageInteractor,
@@ -82,6 +85,7 @@ constructor(
view,
deps.viewModel,
deps.primaryBouncerToGoneTransitionViewModel,
+ deps.glanceableHubToPrimaryBouncerTransitionViewModel,
deps.componentFactory,
deps.messageAreaControllerFactory,
deps.bouncerMessageInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index 7d8945a5b4a7..45f0e13c185e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -33,6 +33,7 @@ import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.bouncer.ui.BouncerViewDelegate
import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToPrimaryBouncerTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.log.BouncerLogger
@@ -49,6 +50,8 @@ object KeyguardBouncerViewBinder {
view: ViewGroup,
viewModel: KeyguardBouncerViewModel,
primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
+ glanceableHubToPrimaryBouncerTransitionViewModel:
+ GlanceableHubToPrimaryBouncerTransitionViewModel,
componentFactory: KeyguardBouncerComponent.Factory,
messageAreaControllerFactory: KeyguardMessageAreaController.Factory,
bouncerMessageInteractor: BouncerMessageInteractor,
@@ -133,7 +136,20 @@ object KeyguardBouncerViewBinder {
/* turningOff= */ false
)
securityContainerController.setInitialMessage()
- securityContainerController.appear()
+ // Delay bouncer appearing animation when opening it from the
+ // glanceable hub in landscape, until after orientation changes
+ // to portrait. This prevents bouncer from showing in landscape
+ // layout, if bouncer rotation is not allowed.
+ if (
+ glanceableHubToPrimaryBouncerTransitionViewModel
+ .willDelayAppearAnimation(
+ securityContainerController.isLandscapeOrientation
+ )
+ ) {
+ securityContainerController.setupForDelayedAppear()
+ } else {
+ securityContainerController.appear()
+ }
securityContainerController.onResume(
KeyguardSecurityView.SCREEN_ON
)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index e36e85565293..49b0bb63545f 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -29,10 +29,17 @@ import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalScenes.isCommunal
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.Edge
+import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
+import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.emitOnStart
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
@@ -45,6 +52,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
@@ -60,10 +68,12 @@ constructor(
private val communalInteractor: CommunalInteractor,
private val communalSettingsInteractor: CommunalSettingsInteractor,
private val communalSceneInteractor: CommunalSceneInteractor,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val keyguardInteractor: KeyguardInteractor,
private val systemSettings: SystemSettings,
private val notificationShadeWindowController: NotificationShadeWindowController,
@Background private val bgScope: CoroutineScope,
+ @Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
private val uiEventLogger: UiEventLogger,
) : CoreStartable {
@@ -154,6 +164,25 @@ constructor(
}
}
}
+
+ if (communalSettingsInteractor.isV2FlagEnabled()) {
+ applicationScope.launch(context = mainDispatcher) {
+ anyOf(
+ communalSceneInteractor.isTransitioningToOrIdleOnCommunal,
+ // when transitioning from hub to dream, allow hub to stay at the current
+ // orientation, as keyguard doesn't allow rotation by default.
+ keyguardTransitionInteractor.isInTransition(
+ edge = Edge.create(from = Scenes.Communal, to = DREAMING),
+ edgeWithoutSceneContainer =
+ Edge.create(from = GLANCEABLE_HUB, to = DREAMING),
+ ),
+ )
+ .distinctUntilChanged()
+ .collectLatest {
+ notificationShadeWindowController.setGlanceableHubOrientationAware(it)
+ }
+ }
+ }
}
private fun cancelHubTimeout() {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
index 3d9e93036dbc..fed99d71fa3b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
@@ -307,6 +307,21 @@ constructor(
initialValue = false,
)
+ /** Flow that emits a boolean if transitioning to or idle on communal scene. */
+ val isTransitioningToOrIdleOnCommunal: Flow<Boolean> =
+ transitionState
+ .map {
+ (it is ObservableTransitionState.Idle &&
+ it.currentScene == CommunalScenes.Communal) ||
+ (it is ObservableTransitionState.Transition &&
+ it.toContent == CommunalScenes.Communal)
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+
private companion object {
const val TAG = "CommunalSceneInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index 63cf4f72e415..ab0efed2cb76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -85,7 +85,7 @@ constructor(
val previewClock: Flow<ClockController> = keyguardClockRepository.previewClock
- val clockEventController: ClockEventController by keyguardClockRepository::clockEventController
+ val clockEventController: ClockEventController = keyguardClockRepository.clockEventController
var clock: ClockController? by keyguardClockRepository.clockEventController::clock
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
index def1ac8742da..e81d5354ec6e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
@@ -81,22 +81,92 @@ object KeyguardSmartspaceViewBinder {
}
if (com.android.systemui.shared.Flags.clockReactiveSmartspaceLayout()) {
+ val xBuffer =
+ keyguardRootView.context.resources.getDimensionPixelSize(
+ R.dimen.smartspace_padding_horizontal
+ )
+ val yBuffer =
+ keyguardRootView.context.resources.getDimensionPixelSize(
+ R.dimen.smartspace_padding_vertical
+ )
+
+ val smallViewIds =
+ listOf(sharedR.id.date_smartspace_view, sharedR.id.weather_smartspace_view)
+
+ val largeViewIds =
+ listOf(
+ sharedR.id.date_smartspace_view_large,
+ sharedR.id.weather_smartspace_view_large,
+ )
+
launch("$TAG#smartspaceViewModel.burnInLayerVisibility") {
- keyguardRootViewModel.burnInLayerVisibility.collect { visibility ->
- if (clockViewModel.isLargeClockVisible.value) {
- // hide small clock date/weather
- val dateView =
- keyguardRootView.requireViewById<View>(
- sharedR.id.date_smartspace_view
- )
- dateView.visibility = View.GONE
- val weatherView =
- keyguardRootView.requireViewById<View>(
- sharedR.id.weather_smartspace_view
- )
- weatherView.visibility = View.GONE
+ combine(
+ keyguardRootViewModel.burnInLayerVisibility,
+ clockViewModel.isLargeClockVisible,
+ ::Pair,
+ )
+ .collect { (visibility, isLargeClock) ->
+ if (isLargeClock) {
+ // hide small clock date/weather
+ for (viewId in smallViewIds) {
+ keyguardRootView.findViewById<View>(viewId)?.let {
+ it.visibility = View.GONE
+ }
+ }
+ }
+ }
+ }
+
+ launch("$TAG#clockEventController.onClockBoundsChanged") {
+ // Whenever the doze amount changes, the clock may update it's view bounds.
+ // We need to update our layout position as a result. We could do this via
+ // `requestLayout`, but that's quite expensive when enclosed in since this
+ // recomputes the entire ConstraintLayout, so instead we do it manually. We
+ // would use translationX/Y for this, but that's used by burnin.
+ combine(
+ clockViewModel.isLargeClockVisible,
+ clockViewModel.clockEventController.onClockBoundsChanged,
+ ::Pair,
+ )
+ .collect { (isLargeClock, clockBounds) ->
+ for (id in (if (isLargeClock) smallViewIds else largeViewIds)) {
+ keyguardRootView.findViewById<View>(id)?.let {
+ it.visibility = View.GONE
+ }
+ }
+
+ if (clockBounds == null) return@collect
+ if (isLargeClock) {
+ val largeDateHeight =
+ keyguardRootView
+ .findViewById<View>(
+ sharedR.id.date_smartspace_view_large
+ )
+ ?.height ?: 0
+ for (id in largeViewIds) {
+ keyguardRootView.findViewById<View>(id)?.let { view ->
+ val viewHeight = view.height
+ val offset = (largeDateHeight - viewHeight) / 2
+ view.top =
+ (clockBounds.bottom + yBuffer + offset).toInt()
+ view.bottom = view.top + viewHeight
+ }
+ }
+ } else {
+ for (id in smallViewIds) {
+ keyguardRootView.findViewById<View>(id)?.let { view ->
+ val viewWidth = view.width
+ if (view.isLayoutRtl()) {
+ view.right = (clockBounds.left - xBuffer).toInt()
+ view.left = view.right - viewWidth
+ } else {
+ view.left = (clockBounds.right + xBuffer).toInt()
+ view.right = view.left + viewWidth
+ }
+ }
+ }
+ }
}
- }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index 37cc852ffe00..d0b5f743c277 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -226,7 +226,7 @@ constructor(
ConstraintSet.TOP,
customR.id.lockscreen_clock_view_large,
ConstraintSet.BOTTOM,
- dateWeatherPaddingStart,
+ context.resources.getDimensionPixelSize(R.dimen.smartspace_padding_vertical),
)
connect(
@@ -291,7 +291,9 @@ constructor(
ConstraintSet.START,
customR.id.lockscreen_clock_view,
ConstraintSet.END,
- 20,
+ context.resources.getDimensionPixelSize(
+ R.dimen.smartspace_padding_horizontal
+ ),
)
connect(
sharedR.id.date_smartspace_view,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt
index 40010548a268..c088900f9304 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt
@@ -17,33 +17,39 @@
package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.Flags
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.FromGlanceableHubTransitionInteractor
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.transitions.BlurConfig
import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition
+import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class GlanceableHubToPrimaryBouncerTransitionViewModel
@Inject
constructor(
private val blurConfig: BlurConfig,
animationFlow: KeyguardTransitionAnimationFlow,
- communalSettingsInteractor: CommunalSettingsInteractor,
+ private val communalSettingsInteractor: CommunalSettingsInteractor,
+ private val communalSceneInteractor: CommunalSceneInteractor,
+ private val keyguardStateController: KeyguardStateController,
) : PrimaryBouncerTransition {
private val transitionAnimation =
animationFlow
.setup(
- duration = FromLockscreenTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION,
+ duration = FromGlanceableHubTransitionInteractor.TO_BOUNCER_DURATION,
edge = Edge.INVALID,
)
.setupWithoutSceneContainer(edge = Edge.create(GLANCEABLE_HUB, PRIMARY_BOUNCER))
@@ -59,6 +65,13 @@ constructor(
transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx)
}
+ /** Whether to delay the animation to fade in bouncer elements. */
+ fun willDelayAppearAnimation(isLandscape: Boolean): Boolean =
+ communalSettingsInteractor.isV2FlagEnabled() &&
+ communalSceneInteractor.isIdleOnCommunal.value &&
+ !keyguardStateController.isKeyguardScreenRotationAllowed() &&
+ isLandscape
+
override val notificationBlurRadius: Flow<Float> =
transitionAnimation.immediatelyTransitionTo(0.0f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index cf5cc264be8d..dcbf7b5a9335 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.content.Context
import android.content.res.Resources
import androidx.constraintlayout.helper.widget.Layer
+import com.android.keyguard.ClockEventController
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.SysUISingleton
@@ -68,6 +69,7 @@ constructor(
initialValue = true,
)
+ val clockEventController: ClockEventController = keyguardClockInteractor.clockEventController
val currentClock = keyguardClockInteractor.currentClock
val hasCustomWeatherDataDisplay =
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index e4cd7ea098af..305444f7ab5e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -451,6 +451,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
} else {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
}
+ } else if (state.glanceableHubOrientationAware) {
+ mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
} else {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
@@ -627,6 +629,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
state.shadeOrQsExpanded,
state.notificationShadeFocusable,
state.glanceableHubShowing,
+ state.glanceableHubOrientationAware,
state.bouncerShowing,
state.keyguardFadingAway,
state.keyguardGoingAway,
@@ -763,6 +766,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
@Override
+ public void setGlanceableHubOrientationAware(boolean isOrientationAware) {
+ mCurrentState.glanceableHubOrientationAware = isOrientationAware;
+ apply(mCurrentState);
+ }
+
+ @Override
public void setBackdropShowing(boolean showing) {
mCurrentState.mediaBackdropShowing = showing;
apply(mCurrentState);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
index 6a4b52af498c..a1eac745b3a1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
@@ -36,6 +36,7 @@ class NotificationShadeWindowState(
@JvmField var notificationShadeFocusable: Boolean = false,
@JvmField var bouncerShowing: Boolean = false,
@JvmField var glanceableHubShowing: Boolean = false,
+ @JvmField var glanceableHubOrientationAware: Boolean = false,
@JvmField var keyguardFadingAway: Boolean = false,
@JvmField var keyguardGoingAway: Boolean = false,
@JvmField var qsExpanded: Boolean = false,
@@ -81,6 +82,7 @@ class NotificationShadeWindowState(
notificationShadeFocusable.toString(),
bouncerShowing.toString(),
glanceableHubShowing.toString(),
+ glanceableHubOrientationAware.toString(),
keyguardFadingAway.toString(),
keyguardGoingAway.toString(),
qsExpanded.toString(),
@@ -122,6 +124,7 @@ class NotificationShadeWindowState(
panelExpanded: Boolean,
notificationShadeFocusable: Boolean,
glanceableHubShowing: Boolean,
+ glanceableHubOrientationAware: Boolean,
bouncerShowing: Boolean,
keyguardFadingAway: Boolean,
keyguardGoingAway: Boolean,
@@ -153,6 +156,7 @@ class NotificationShadeWindowState(
this.shadeOrQsExpanded = panelExpanded
this.notificationShadeFocusable = notificationShadeFocusable
this.glanceableHubShowing = glanceableHubShowing
+ this.glanceableHubOrientationAware = glanceableHubOrientationAware
this.bouncerShowing = bouncerShowing
this.keyguardFadingAway = keyguardFadingAway
this.keyguardGoingAway = keyguardGoingAway
@@ -202,6 +206,7 @@ class NotificationShadeWindowState(
"panelExpanded",
"notificationShadeFocusable",
"glanceableHubShowing",
+ "glanceableHubOrientationAware",
"bouncerShowing",
"keyguardFadingAway",
"keyguardGoingAway",
@@ -223,7 +228,7 @@ class NotificationShadeWindowState(
"dozing",
"scrimsVisibility",
"backgroundBlurRadius",
- "communalVisible"
+ "communalVisible",
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index 246177e0c46d..81146852aefc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -334,7 +334,7 @@ constructor(
} else if (state.fromContent == overlay) {
state.progress.map { progress -> 1 - progress }
} else {
- flowOf(0f)
+ state.currentOverlays().map { if (overlay in it) 1f else 0f }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 85fad420daf1..50cf015af5e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -89,6 +89,9 @@ public interface NotificationShadeWindowController extends RemoteInputController
/** Sets the state of whether the glanceable hub is showing or not. */
default void setGlanceableHubShowing(boolean showing) {}
+ /** Sets the state of whether the glanceable hub can change with user's orientation or not. */
+ default void setGlanceableHubOrientationAware(boolean isOrientationAware) {}
+
/** Sets the state of whether the backdrop is showing or not. */
default void setBackdropShowing(boolean showing) {}
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 4390f1b16ffd..1a17b8efb4ae 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
@@ -1226,6 +1226,14 @@ public class NotificationStackScrollLayout
}
@Override
+ public void setOccluded(boolean isOccluded) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
+ return;
+ }
+ this.setVisibility(isOccluded ? View.INVISIBLE : View.VISIBLE);
+ }
+
+ @Override
public void setScrollState(@NonNull ShadeScrollState scrollState) {
if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
index a7305f7f27ab..9c855e9cd9b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
@@ -49,6 +49,9 @@ interface NotificationScrollView {
/** Max alpha for this view */
fun setMaxAlpha(alpha: Float)
+ /** Set whether this view is occluded by something else. */
+ fun setOccluded(isOccluded: Boolean)
+
/** Sets a clipping shape, which defines the drawable area of this view. */
fun setClippingShape(shape: ShadeScrimShape?)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index a4e39cbd8388..653344ae9203 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -86,6 +86,8 @@ constructor(
.collectTraced { view.setClippingShape(it) }
}
+ launch { viewModel.isOccluded.collectTraced { view.setOccluded(it) } }
+
launch { viewModel.maxAlpha.collectTraced { view.setMaxAlpha(it) } }
launch { viewModel.shadeScrollState.collect { view.setScrollState(it) } }
launch {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 1dbaf2f0f401..a277597e23df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -24,7 +24,9 @@ import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.ObservableTransitionState.Idle
import com.android.compose.animation.scene.ObservableTransitionState.Transition
import com.android.compose.animation.scene.ObservableTransitionState.Transition.ChangeScene
+import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
@@ -70,6 +72,7 @@ constructor(
private val stackAppearanceInteractor: NotificationStackAppearanceInteractor,
shadeInteractor: ShadeInteractor,
shadeModeInteractor: ShadeModeInteractor,
+ bouncerInteractor: BouncerInteractor,
private val remoteInputInteractor: RemoteInputInteractor,
private val sceneInteractor: SceneInteractor,
// TODO(b/336364825) Remove Lazy when SceneContainerFlag is released -
@@ -131,12 +134,15 @@ constructor(
private fun expandFractionDuringOverlayTransition(
transition: Transition,
currentScene: SceneKey,
+ currentOverlays: Set<OverlayKey>,
shadeExpansion: Float,
): Float {
return if (currentScene == Scenes.Lockscreen) {
1f
} else if (transition.isTransitioningFromOrTo(Overlays.NotificationsShade)) {
shadeExpansion
+ } else if (Overlays.NotificationsShade in currentOverlays) {
+ 1f
} else {
0f
}
@@ -161,12 +167,13 @@ constructor(
shadeInteractor.qsExpansion,
shadeModeInteractor.shadeMode,
sceneInteractor.transitionState,
- ) { shadeExpansion, qsExpansion, _, transitionState ->
+ sceneInteractor.currentOverlays,
+ ) { shadeExpansion, qsExpansion, _, transitionState, currentOverlays ->
when (transitionState) {
is Idle ->
if (
expandedInScene(transitionState.currentScene) ||
- Overlays.NotificationsShade in transitionState.currentOverlays
+ Overlays.NotificationsShade in currentOverlays
) {
1f
} else {
@@ -182,12 +189,14 @@ constructor(
expandFractionDuringOverlayTransition(
transition = transitionState,
currentScene = transitionState.currentScene,
+ currentOverlays = currentOverlays,
shadeExpansion = shadeExpansion,
)
is Transition.ReplaceOverlay ->
expandFractionDuringOverlayTransition(
transition = transitionState,
currentScene = transitionState.currentScene,
+ currentOverlays = currentOverlays,
shadeExpansion = shadeExpansion,
)
}
@@ -198,6 +207,12 @@ constructor(
val qsExpandFraction: Flow<Float> =
shadeInteractor.qsExpansion.dumpWhileCollecting("qsExpandFraction")
+ val isOccluded: Flow<Boolean> =
+ bouncerInteractor.bouncerExpansion
+ .map { it == 1f }
+ .distinctUntilChanged()
+ .dumpWhileCollecting("isOccluded")
+
/** Blur radius to be applied to Notifications. */
fun blurRadius(maxBlurRadius: Flow<Int>) =
combine(blurFraction, maxBlurRadius) { fraction, maxRadius -> fraction * maxRadius }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 33cc62c9a75a..9d55e1d9d592 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -21,6 +21,7 @@ import android.content.Context
import androidx.annotation.VisibleForTesting
import com.android.app.tracing.coroutines.flow.flowName
import com.android.systemui.Flags.glanceableHubV2
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
@@ -106,7 +107,6 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
-import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
@@ -132,6 +132,7 @@ constructor(
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val shadeInteractor: ShadeInteractor,
+ private val bouncerInteractor: BouncerInteractor,
shadeModeInteractor: ShadeModeInteractor,
notificationStackAppearanceInteractor: NotificationStackAppearanceInteractor,
private val alternateBouncerToGoneTransitionViewModel:
@@ -516,8 +517,13 @@ constructor(
combineTransform(
shadeInteractor.shadeExpansion,
shadeInteractor.qsExpansion,
- ) { shadeExpansion, qsExpansion ->
- if (qsExpansion == 1f) {
+ bouncerInteractor.bouncerExpansion,
+ ) { shadeExpansion, qsExpansion, bouncerExpansion ->
+ if (bouncerExpansion == 1f) {
+ emit(0f)
+ } else if (bouncerExpansion > 0f) {
+ emit(1 - bouncerExpansion)
+ } else if (qsExpansion == 1f) {
// Ensure HUNs will be visible in QS shade (at least while
// unlocked)
emit(1f)
@@ -526,19 +532,36 @@ constructor(
emit(1f - qsExpansion)
}
}
- Split -> isAnyExpanded.filter { it }.map { 1f }
+ Split ->
+ combineTransform(isAnyExpanded, bouncerInteractor.bouncerExpansion) {
+ isAnyExpanded,
+ bouncerExpansion ->
+ if (bouncerExpansion == 1f) {
+ emit(0f)
+ } else if (bouncerExpansion > 0f) {
+ emit(1 - bouncerExpansion)
+ } else if (isAnyExpanded) {
+ emit(1f)
+ }
+ }
Dual ->
combineTransform(
shadeModeInteractor.isShadeLayoutWide,
headsUpNotificationInteractor.get().isHeadsUpOrAnimatingAway,
shadeInteractor.shadeExpansion,
shadeInteractor.qsExpansion,
+ bouncerInteractor.bouncerExpansion,
) {
isShadeLayoutWide,
isHeadsUpOrAnimatingAway,
shadeExpansion,
- qsExpansion ->
- if (isShadeLayoutWide) {
+ qsExpansion,
+ bouncerExpansion ->
+ if (bouncerExpansion == 1f) {
+ emit(0f)
+ } else if (bouncerExpansion > 0f) {
+ emit(1 - bouncerExpansion)
+ } else if (isShadeLayoutWide) {
if (shadeExpansion > 0f) {
emit(1f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt
index 33e1929ebf8b..952d40ed63eb 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt
@@ -17,8 +17,13 @@
package com.android.systemui.wallpapers
import android.app.Flags
+import android.content.res.Configuration.UI_MODE_NIGHT_MASK
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.graphics.Canvas
+import android.graphics.Color
import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
import android.graphics.RadialGradient
import android.graphics.Shader
import android.service.wallpaper.WallpaperService
@@ -74,9 +79,9 @@ class GradientColorWallpaper : WallpaperService() {
.toFloat()
val totalHeight = destRectF.height() + (offsetPx * 2)
val leftCenterX = -offsetPx
- val leftCenterY = -offsetPx
+ val leftCenterY = totalHeight - offsetPx
val rightCenterX = offsetPx + destRectF.width()
- val rightCenterY = totalHeight - offsetPx
+ val rightCenterY = -offsetPx
val radius = (destRectF.width() / 2) + offsetPx
canvas.drawCircle(
@@ -112,6 +117,28 @@ class GradientColorWallpaper : WallpaperService() {
)
},
)
+
+ val isDarkMode =
+ context.resources.configuration.uiMode and UI_MODE_NIGHT_MASK ==
+ UI_MODE_NIGHT_YES
+ val maskColor =
+ ColorUtils.setAlphaComponent(
+ if (isDarkMode) Color.BLACK else Color.WHITE,
+ /* alpha= */ 87, // 0.34f * 255
+ )
+ val maskPaint =
+ Paint().apply {
+ xfermode =
+ PorterDuffXfermode(
+ if (isDarkMode) {
+ PorterDuff.Mode.DARKEN
+ } else {
+ PorterDuff.Mode.LIGHTEN
+ }
+ )
+ color = maskColor
+ }
+ canvas.drawRect(destRectF, maskPaint)
} catch (exception: IllegalStateException) {
Log.d(TAG, "Fail to draw in the canvas", exception)
} finally {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index f822ee97807e..f18d73d57f83 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -194,7 +194,7 @@ class ClockEventControllerTest : SysuiTestCase() {
@Test
fun clockSet_validateInitialization() {
- verify(clock).initialize(any(), anyFloat(), anyFloat())
+ verify(clock).initialize(any(), anyFloat(), anyFloat(), any())
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt
index b4fbaad6ab37..5f3442048fcd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.wallpapers
import android.app.Flags
import android.content.Context
-import android.content.res.Resources
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
@@ -43,6 +42,7 @@ import org.mockito.Mock
import org.mockito.Mockito.spy
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyZeroInteractions
@@ -61,23 +61,20 @@ class GradientColorWallpaperTest : SysuiTestCase() {
@Mock private lateinit var mockContext: Context
- @Mock private lateinit var mockResources: Resources
-
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ val spyResources = spy(context.resources)
+
whenever(surfaceHolder.surface).thenReturn(surface)
whenever(surfaceHolder.surfaceFrame).thenReturn(surfaceFrame)
whenever(surface.lockHardwareCanvas()).thenReturn(canvas)
whenever(mockContext.getColor(anyInt())).thenReturn(1)
- whenever(mockContext.resources).thenReturn(mockResources)
- whenever(
- mockResources.getDimensionPixelOffset(
- eq(R.dimen.gradient_color_wallpaper_center_offset)
- )
- )
- .thenReturn(OFFSET_PX)
+ whenever(mockContext.resources).thenReturn(spyResources)
+ doReturn(OFFSET_PX)
+ .`when`(spyResources)
+ .getDimensionPixelOffset(eq(R.dimen.gradient_color_wallpaper_center_offset))
}
private fun createGradientColorWallpaperEngine(): Engine {
@@ -106,7 +103,8 @@ class GradientColorWallpaperTest : SysuiTestCase() {
engine.onSurfaceRedrawNeeded(surfaceHolder)
- verify(canvas).drawRect(any<RectF>(), any<Paint>())
+ // One rect for the background, one rect for the foreground mask.
+ verify(canvas, times(2)).drawRect(any<RectF>(), any<Paint>())
verify(canvas, times(2)).drawCircle(anyFloat(), anyFloat(), anyFloat(), any<Paint>())
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt
index d27ecce89937..94d27f73aee7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt
@@ -28,6 +28,7 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.log.sessionTracker
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
val Kosmos.bouncerInteractor by Fixture {
BouncerInteractor(
@@ -39,6 +40,7 @@ val Kosmos.bouncerInteractor by Fixture {
powerInteractor = powerInteractor,
uiEventLogger = uiEventLogger,
sessionTracker = sessionTracker,
+ sceneInteractor = sceneInteractor,
sceneBackInteractor = sceneBackInteractor,
configurationInteractor = configurationInteractor,
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt
index b233d3ff9e0f..c6f55f053d35 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt
@@ -16,16 +16,20 @@
package com.android.systemui.keyguard.ui.viewmodel
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.transitions.blurConfig
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.policy.keyguardStateController
val Kosmos.glanceableHubToPrimaryBouncerTransitionViewModel by Fixture {
GlanceableHubToPrimaryBouncerTransitionViewModel(
animationFlow = keyguardTransitionAnimationFlow,
blurConfig = blurConfig,
communalSettingsInteractor = communalSettingsInteractor,
+ communalSceneInteractor = communalSceneInteractor,
+ keyguardStateController = keyguardStateController,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 02cf1f5a7214..dff9f3abfc05 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -29,6 +29,7 @@ import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
+import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.communal.ui.viewmodel.communalTransitionViewModel
import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
@@ -87,6 +88,7 @@ import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.wifiIntera
import com.android.systemui.statusbar.policy.configurationController
import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
+import com.android.systemui.statusbar.policy.keyguardStateController
import com.android.systemui.statusbar.ui.viewmodel.keyguardStatusBarViewModel
import com.android.systemui.util.time.systemClock
import com.android.systemui.volume.domain.interactor.volumeDialogInteractor
@@ -126,6 +128,7 @@ class KosmosJavaAdapter() {
val keyguardInteractor by lazy { kosmos.keyguardInteractor }
val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor }
+ val keyguardStateController by lazy { kosmos.keyguardStateController }
val keyguardStatusBarViewModel by lazy { kosmos.keyguardStatusBarViewModel }
val powerRepository by lazy { kosmos.fakePowerRepository }
val clock by lazy { kosmos.systemClock }
@@ -147,6 +150,7 @@ class KosmosJavaAdapter() {
val deviceUnlockedInteractor by lazy { kosmos.deviceUnlockedInteractor }
val communalInteractor by lazy { kosmos.communalInteractor }
val communalSceneInteractor by lazy { kosmos.communalSceneInteractor }
+ val communalSettingsInteractor by lazy { kosmos.communalSettingsInteractor }
val sceneContainerPlugin by lazy { kosmos.sceneContainerPlugin }
val deviceProvisioningInteractor by lazy { kosmos.deviceProvisioningInteractor }
val fakeDeviceProvisioningRepository by lazy { kosmos.fakeDeviceProvisioningRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModelKosmos.kt
index 167b11da9dba..87ce501b0402 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModelKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
import com.android.systemui.dump.dumpManager
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
@@ -32,6 +33,7 @@ val Kosmos.notificationScrollViewModel by Fixture {
stackAppearanceInteractor = notificationStackAppearanceInteractor,
shadeInteractor = shadeInteractor,
shadeModeInteractor = shadeModeInteractor,
+ bouncerInteractor = bouncerInteractor,
remoteInputInteractor = remoteInputInteractor,
sceneInteractor = sceneInteractor,
keyguardInteractor = { keyguardInteractor },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 17ef208fe12e..85fe3d9a44ce 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import android.content.applicationContext
+import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.dump.dumpManager
@@ -74,6 +75,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture {
keyguardInteractor = keyguardInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
shadeInteractor = shadeInteractor,
+ bouncerInteractor = bouncerInteractor,
shadeModeInteractor = shadeModeInteractor,
notificationStackAppearanceInteractor = notificationStackAppearanceInteractor,
alternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel,
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
index bb3c710b0c23..0f6f86b39458 100644
--- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
@@ -103,12 +103,16 @@ public class AutoclickController extends BaseEventStreamTransformation {
@Override
public void toggleAutoclickPause(boolean paused) {
if (paused) {
- if (mClickScheduler != null) {
- mClickScheduler.cancel();
- }
- if (mAutoclickIndicatorScheduler != null) {
- mAutoclickIndicatorScheduler.cancel();
- }
+ cancelPendingClick();
+ }
+ }
+
+ @Override
+ public void onHoverChange(boolean hovered) {
+ // Cancel all pending clicks when the mouse moves outside the panel while
+ // autoclick is still paused.
+ if (!hovered && isPaused()) {
+ cancelPendingClick();
}
}
};
@@ -226,8 +230,17 @@ public class AutoclickController extends BaseEventStreamTransformation {
}
private boolean isPaused() {
- // TODO (b/397460424): Unpause when hovering over panel.
- return Flags.enableAutoclickIndicator() && mAutoclickTypePanel.isPaused();
+ return Flags.enableAutoclickIndicator() && mAutoclickTypePanel.isPaused()
+ && !mAutoclickTypePanel.isHovered();
+ }
+
+ private void cancelPendingClick() {
+ if (mClickScheduler != null) {
+ mClickScheduler.cancel();
+ }
+ if (mAutoclickIndicatorScheduler != null) {
+ mAutoclickIndicatorScheduler.cancel();
+ }
}
@VisibleForTesting
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickLinearLayout.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickLinearLayout.java
new file mode 100644
index 000000000000..fe8adf75704d
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickLinearLayout.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 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.accessibility.autoclick;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.LinearLayout;
+
+/**
+ * A custom LinearLayout that provides enhanced hover event handling.
+ * This class overrides hover methods to track hover events for the entire panel ViewGroup,
+ * including the descendant buttons. This allows for consistent hover behavior and feedback
+ * across the entire layout.
+ */
+public class AutoclickLinearLayout extends LinearLayout {
+ public interface OnHoverChangedListener {
+ /**
+ * Called when the hover state of the AutoclickLinearLayout changes.
+ *
+ * @param hovered {@code true} if the view is now hovered, {@code false} otherwise.
+ */
+ void onHoverChanged(boolean hovered);
+ }
+
+ private OnHoverChangedListener mListener;
+
+ public AutoclickLinearLayout(Context context) {
+ super(context);
+ }
+
+ public AutoclickLinearLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AutoclickLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public AutoclickLinearLayout(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public void setOnHoverChangedListener(OnHoverChangedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public boolean onInterceptHoverEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+ setHovered(action == MotionEvent.ACTION_HOVER_ENTER
+ || action == MotionEvent.ACTION_HOVER_MOVE);
+
+ return false;
+ }
+
+ @Override
+ public void onHoverChanged(boolean hovered) {
+ super.onHoverChanged(hovered);
+
+ if (mListener != null) {
+ mListener.onHoverChanged(hovered);
+ }
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
index ab4b3b13eece..57bbb4a7a0a7 100644
--- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
@@ -110,11 +110,18 @@ public class AutoclickTypePanel {
* @param paused {@code true} to pause autoclick, {@code false} to resume.
*/
void toggleAutoclickPause(boolean paused);
+
+ /**
+ * Called when the hovered state of the panel changes.
+ *
+ * @param hovered {@code true} if the panel is now hovered, {@code false} otherwise.
+ */
+ void onHoverChange(boolean hovered);
}
private final Context mContext;
- private final View mContentView;
+ private final AutoclickLinearLayout mContentView;
private final WindowManager mWindowManager;
@@ -164,8 +171,9 @@ public class AutoclickTypePanel {
R.drawable.accessibility_autoclick_resume);
mContentView =
- LayoutInflater.from(context)
+ (AutoclickLinearLayout) LayoutInflater.from(context)
.inflate(R.layout.accessibility_autoclick_type_panel, null);
+ mContentView.setOnHoverChangedListener(mClickPanelController::onHoverChange);
mLeftClickButton =
mContentView.findViewById(R.id.accessibility_autoclick_left_click_layout);
mRightClickButton =
@@ -339,6 +347,10 @@ public class AutoclickTypePanel {
return mPaused;
}
+ public boolean isHovered() {
+ return mContentView.isHovered();
+ }
+
/** Toggles the panel expanded or collapsed state. */
private void togglePanelExpansion(@AutoclickType int clickType) {
final LinearLayout button = getButtonFromClickType(clickType);
@@ -520,7 +532,7 @@ public class AutoclickTypePanel {
@VisibleForTesting
@NonNull
- View getContentViewForTesting() {
+ AutoclickLinearLayout getContentViewForTesting() {
return mContentView;
}
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java b/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java
index 84402c85471f..12c35ae92cbe 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java
@@ -177,6 +177,8 @@ abstract class DiscreteOpsRegistry {
*/
abstract void writeAndClearOldAccessHistory();
+ void shutdown() {}
+
/** Remove all discrete op events. */
abstract void clearHistory();
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java
index 604cb30294a9..dc11be9aadb6 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java
@@ -57,13 +57,18 @@ import java.util.Set;
public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
private static final String TAG = "DiscreteOpsSqlRegistry";
+ private static final long DB_WRITE_INTERVAL = Duration.ofMinutes(10).toMillis();
+ private static final long EXPIRED_ENTRY_DELETION_INTERVAL = Duration.ofHours(6).toMillis();
+
+ // Event type handled by SqliteWriteHandler
+ private static final int WRITE_DATABASE_RECURRING = 1;
+ private static final int DELETE_EXPIRED_ENTRIES = 2;
+ private static final int WRITE_DATABASE_CACHE_FULL = 3;
+
private final Context mContext;
private final DiscreteOpsDbHelper mDiscreteOpsDbHelper;
private final SqliteWriteHandler mSqliteWriteHandler;
private final DiscreteOpCache mDiscreteOpCache = new DiscreteOpCache(512);
- private static final long THREE_HOURS = Duration.ofHours(3).toMillis();
- private static final int WRITE_CACHE_EVICTED_OP_EVENTS = 1;
- private static final int DELETE_OLD_OP_EVENTS = 2;
// Attribution chain id is used to identify an attribution source chain, This is
// set for startOp only. PermissionManagerService resets this ID on device restart, so
// we use previously persisted chain id as offset, and add it to chain id received from
@@ -83,6 +88,9 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
mSqliteWriteHandler = new SqliteWriteHandler(thread.getLooper());
mDiscreteOpsDbHelper = new DiscreteOpsDbHelper(context, databaseFile);
mChainIdOffset = mDiscreteOpsDbHelper.getLargestAttributionChainId();
+ mSqliteWriteHandler.sendEmptyMessageDelayed(WRITE_DATABASE_RECURRING, DB_WRITE_INTERVAL);
+ mSqliteWriteHandler.sendEmptyMessageDelayed(DELETE_EXPIRED_ENTRIES,
+ EXPIRED_ENTRY_DELETION_INTERVAL);
}
@Override
@@ -117,15 +125,14 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
}
@Override
- void writeAndClearOldAccessHistory() {
- // Let the sql impl also follow the same disk write frequencies as xml,
- // controlled by AppOpsService.
+ void shutdown() {
+ mSqliteWriteHandler.removeAllPendingMessages();
mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear());
- if (!mSqliteWriteHandler.hasMessages(DELETE_OLD_OP_EVENTS)) {
- if (mSqliteWriteHandler.sendEmptyMessageDelayed(DELETE_OLD_OP_EVENTS, THREE_HOURS)) {
- Slog.w(TAG, "DELETE_OLD_OP_EVENTS is not queued");
- }
- }
+ }
+
+ @Override
+ void writeAndClearOldAccessHistory() {
+ // no-op
}
@Override
@@ -175,7 +182,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
@Nullable String attributionTagFilter, int opFlagsFilter,
Set<String> attributionExemptPkgs) {
// flush the cache into database before read.
- writeAndClearOldAccessHistory();
+ mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear());
boolean assembleChains = attributionExemptPkgs != null;
IntArray opCodes = getAppOpCodes(filter, opNamesFilter);
beginTimeMillis = Math.max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff,
@@ -363,20 +370,59 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case WRITE_CACHE_EVICTED_OP_EVENTS:
- List<DiscreteOp> opEvents = (List<DiscreteOp>) msg.obj;
- mDiscreteOpsDbHelper.insertDiscreteOps(opEvents);
- break;
- case DELETE_OLD_OP_EVENTS:
+ case WRITE_DATABASE_RECURRING -> {
+ try {
+ List<DiscreteOp> evictedEvents;
+ synchronized (mDiscreteOpCache) {
+ evictedEvents = mDiscreteOpCache.evict();
+ }
+ mDiscreteOpsDbHelper.insertDiscreteOps(evictedEvents);
+ } finally {
+ mSqliteWriteHandler.sendEmptyMessageDelayed(WRITE_DATABASE_RECURRING,
+ DB_WRITE_INTERVAL);
+ // Schedule a cleanup to truncate older (before cutoff time) entries.
+ if (!mSqliteWriteHandler.hasMessages(DELETE_EXPIRED_ENTRIES)) {
+ mSqliteWriteHandler.sendEmptyMessageDelayed(DELETE_EXPIRED_ENTRIES,
+ EXPIRED_ENTRY_DELETION_INTERVAL);
+ }
+ }
+ }
+ case DELETE_EXPIRED_ENTRIES -> {
long cutOffTimeStamp = System.currentTimeMillis() - sDiscreteHistoryCutoff;
mDiscreteOpsDbHelper.execSQL(
DiscreteOpsTable.DELETE_TABLE_DATA_BEFORE_ACCESS_TIME,
new Object[]{cutOffTimeStamp});
- break;
- default:
- throw new IllegalStateException("Unexpected value: " + msg.what);
+ }
+ case WRITE_DATABASE_CACHE_FULL -> {
+ try {
+ List<DiscreteOp> evictedEvents;
+ synchronized (mDiscreteOpCache) {
+ evictedEvents = mDiscreteOpCache.evict();
+ // if nothing to evict, just write the whole cache to database.
+ if (evictedEvents.isEmpty()
+ && mDiscreteOpCache.size() >= mDiscreteOpCache.capacity()) {
+ evictedEvents.addAll(mDiscreteOpCache.mCache);
+ mDiscreteOpCache.clear();
+ }
+ }
+ mDiscreteOpsDbHelper.insertDiscreteOps(evictedEvents);
+ } finally {
+ // Just in case initial message is not scheduled.
+ if (!mSqliteWriteHandler.hasMessages(WRITE_DATABASE_RECURRING)) {
+ mSqliteWriteHandler.sendEmptyMessageDelayed(WRITE_DATABASE_RECURRING,
+ DB_WRITE_INTERVAL);
+ }
+ }
+ }
+ default -> throw new IllegalStateException("Unexpected value: " + msg.what);
}
}
+
+ void removeAllPendingMessages() {
+ removeMessages(WRITE_DATABASE_RECURRING);
+ removeMessages(DELETE_EXPIRED_ENTRIES);
+ removeMessages(WRITE_DATABASE_CACHE_FULL);
+ }
}
/**
@@ -390,6 +436,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
* 4) During shutdown.
*/
class DiscreteOpCache {
+ private static final String TAG = "DiscreteOpCache";
private final int mCapacity;
private final ArraySet<DiscreteOp> mCache;
@@ -404,23 +451,9 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
return;
}
mCache.add(opEvent);
+
if (mCache.size() >= mCapacity) {
- if (DEBUG_LOG) {
- Slog.i(TAG, "Current discrete ops cache size: " + mCache.size());
- }
- List<DiscreteOp> evictedEvents = evict();
- if (DEBUG_LOG) {
- Slog.i(TAG, "Evicted discrete ops size: " + evictedEvents.size());
- }
- // if nothing to evict, just write the whole cache to disk
- if (evictedEvents.isEmpty()) {
- Slog.w(TAG, "No discrete ops event is evicted, write cache to db.");
- evictedEvents.addAll(mCache);
- mCache.clear();
- }
- Message msg = mSqliteWriteHandler.obtainMessage(
- WRITE_CACHE_EVICTED_OP_EVENTS, evictedEvents);
- mSqliteWriteHandler.sendMessage(msg);
+ mSqliteWriteHandler.sendEmptyMessage(WRITE_DATABASE_CACHE_FULL);
}
}
}
@@ -461,6 +494,14 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
}
}
+ int size() {
+ return mCache.size();
+ }
+
+ int capacity() {
+ return mCapacity;
+ }
+
/**
* Remove all entries from the cache.
*/
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 928a4b270b59..d267e0d9e536 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -750,6 +750,7 @@ final class HistoricalRegistry {
}
// Do not call persistPendingHistory inside the memory lock, due to possible deadlock
persistPendingHistory();
+ mDiscreteRegistry.shutdown();
}
void persistPendingHistory() {
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index f51e60c101e4..36686fc086f1 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -312,7 +312,6 @@ public class BackgroundActivityStartController {
private final @ActivityManager.ProcessState int mCallingUidProcState;
private final boolean mIsCallingUidPersistentSystemProcess;
final BackgroundStartPrivileges mBalAllowedByPiSender;
- final BackgroundStartPrivileges mBalAllowedByPiCreatorWithHardening;
final BackgroundStartPrivileges mBalAllowedByPiCreator;
private final String mRealCallingPackage;
private final int mRealCallingUid;
@@ -379,22 +378,14 @@ public class BackgroundActivityStartController {
if (mAutoOptInCaller) {
// grant BAL privileges unless explicitly opted out
- mBalAllowedByPiCreatorWithHardening = mBalAllowedByPiCreator =
+ mBalAllowedByPiCreator =
callerBackgroundActivityStartMode == MODE_BACKGROUND_ACTIVITY_START_DENIED
? BackgroundStartPrivileges.NONE
: BackgroundStartPrivileges.ALLOW_BAL;
} else {
// for PendingIntents we restrict BAL based on target_sdk
- mBalAllowedByPiCreatorWithHardening = getBackgroundStartPrivilegesAllowedByCreator(
+ mBalAllowedByPiCreator = getBackgroundStartPrivilegesAllowedByCreator(
callingUid, callingPackage, checkedOptions);
- final BackgroundStartPrivileges mBalAllowedByPiCreatorWithoutHardening =
- callerBackgroundActivityStartMode
- == MODE_BACKGROUND_ACTIVITY_START_DENIED
- ? BackgroundStartPrivileges.NONE
- : BackgroundStartPrivileges.ALLOW_BAL;
- mBalAllowedByPiCreator = balRequireOptInByPendingIntentCreator()
- ? mBalAllowedByPiCreatorWithHardening
- : mBalAllowedByPiCreatorWithoutHardening;
}
if (mAutoOptInReason != null) {
@@ -585,9 +576,8 @@ public class BackgroundActivityStartController {
if (mCallerApp != null) {
sb.append("; inVisibleTask: ").append(mCallerApp.hasActivityInVisibleTask());
}
- sb.append("; balAllowedByPiCreator: ").append(mBalAllowedByPiCreator);
- sb.append("; balAllowedByPiCreatorWithHardening: ")
- .append(mBalAllowedByPiCreatorWithHardening);
+ sb.append("; balAllowedByPiCreator: ")
+ .append(mBalAllowedByPiCreator);
if (mResultForCaller != null) {
sb.append("; resultIfPiCreatorAllowsBal: ")
.append(balCodeToString(mResultForCaller.mCode));
@@ -638,14 +628,13 @@ public class BackgroundActivityStartController {
}
static class BalVerdict {
- static final BalVerdict BLOCK = new BalVerdict(BAL_BLOCK, false, "Blocked");
+ static final BalVerdict BLOCK = new BalVerdict(BAL_BLOCK, "Blocked");
static final BalVerdict ALLOW_BY_DEFAULT =
- new BalVerdict(BAL_ALLOW_DEFAULT, false, "Default");
+ new BalVerdict(BAL_ALLOW_DEFAULT, "Default");
// Careful using this - it will bypass all ASM checks.
static final BalVerdict ALLOW_PRIVILEGED =
- new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID, false, "PRIVILEGED");
+ new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID, "PRIVILEGED");
private final @BalCode int mCode;
- private final boolean mBackground;
private final String mMessage;
private String mProcessInfo;
// indicates BAL would be blocked because only creator of the PI has the privilege to allow
@@ -654,8 +643,7 @@ public class BackgroundActivityStartController {
/** indicates that this verdict is based on the real calling UID and not the calling UID */
private boolean mBasedOnRealCaller;
- BalVerdict(@BalCode int balCode, boolean background, String message) {
- this.mBackground = background;
+ BalVerdict(@BalCode int balCode, String message) {
this.mCode = balCode;
this.mMessage = message;
}
@@ -708,16 +696,7 @@ public class BackgroundActivityStartController {
builder.append(" [realCaller]");
}
if (DEBUG_ACTIVITY_STARTS) {
- builder.append(" (");
- if (mBackground) {
- builder.append("Background ");
- }
- builder.append("Activity start ");
- if (mCode == BAL_BLOCK) {
- builder.append("denied");
- } else {
- builder.append("allowed: ").append(mMessage);
- }
+ builder.append(" (").append(mMessage);
if (mProcessInfo != null) {
builder.append(" ");
builder.append(mProcessInfo);
@@ -795,7 +774,6 @@ public class BackgroundActivityStartController {
// to realCallingUid when calculating resultForRealCaller below.
if (getService().hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
state.setResultForRealCaller(new BalVerdict(BAL_ALLOW_SDK_SANDBOX,
- /*background*/ false,
"uid in SDK sandbox has visible (non-toast) window"));
return allowBasedOnRealCaller(state);
}
@@ -1059,8 +1037,7 @@ public class BackgroundActivityStartController {
|| state.mAppSwitchState == APP_SWITCH_FG_ONLY
|| isHomeApp(state.mCallingUid, state.mCallingPackage);
if (appSwitchAllowedOrFg && state.mCallingUidHasVisibleActivity) {
- return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW,
- /*background*/ false, "callingUid has visible window");
+ return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "callingUid has visible window");
}
return BalVerdict.BLOCK;
};
@@ -1068,7 +1045,7 @@ public class BackgroundActivityStartController {
private final BalExemptionCheck mCheckCallerNonAppVisible = state -> {
if (state.mCallingUidHasNonAppVisibleWindow) {
return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW,
- /*background*/ false, "callingUid has non-app visible window "
+ "callingUid has non-app visible window "
+ getService().mActiveUids.getNonAppVisibleWindowDetails(state.mCallingUid));
}
return BalVerdict.BLOCK;
@@ -1080,9 +1057,7 @@ public class BackgroundActivityStartController {
if (state.mCallingUid == Process.ROOT_UID
|| callingAppId == Process.SYSTEM_UID
|| callingAppId == Process.NFC_UID) {
- return new BalVerdict(
- BAL_ALLOW_ALLOWLISTED_UID, /*background*/ false,
- "Important callingUid");
+ return new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID, "Important callingUid");
}
return BalVerdict.BLOCK;
};
@@ -1090,9 +1065,7 @@ public class BackgroundActivityStartController {
private final BalExemptionCheck mCheckCallerIsAllowlistedComponent = state -> {
// Always allow home application to start activities.
if (isHomeApp(state.mCallingUid, state.mCallingPackage)) {
- return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ false,
- "Home app");
+ return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Home app");
}
final int callingAppId = UserHandle.getAppId(state.mCallingUid);
@@ -1100,37 +1073,31 @@ public class BackgroundActivityStartController {
final WindowState imeWindow =
getService().mRootWindowContainer.getCurrentInputMethodWindow();
if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
- return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ false,
- "Active ime");
+ return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Active ime");
}
// don't abort if the callingUid is a persistent system process
if (state.mIsCallingUidPersistentSystemProcess) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ false, "callingUid is persistent system process");
+ "callingUid is persistent system process");
}
// don't abort if the caller has the same uid as the recents component
if (getSupervisor().mRecentTasks.isCallerRecents(state.mCallingUid)) {
- return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ true, "Recents Component");
+ return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Recents Component");
}
// don't abort if the callingUid is the device owner
if (getService().isDeviceOwner(state.mCallingUid)) {
- return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ true, "Device Owner");
+ return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Device Owner");
}
// don't abort if the callingUid is a affiliated profile owner
if (getService().isAffiliatedProfileOwner(state.mCallingUid)) {
- return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ true, "Affiliated Profile Owner");
+ return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Affiliated Profile Owner");
}
// don't abort if the callingUid has companion device
final int callingUserId = UserHandle.getUserId(state.mCallingUid);
if (getService().isAssociatedCompanionApp(callingUserId, state.mCallingUid)) {
- return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ true, "Companion App");
+ return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Companion App");
}
return BalVerdict.BLOCK;
};
@@ -1139,7 +1106,6 @@ public class BackgroundActivityStartController {
// don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
if (hasBalPermission(state.mCallingUid, state.mCallingPid)) {
return new BalVerdict(BAL_ALLOW_PERMISSION,
- /*background*/ true,
"START_ACTIVITIES_FROM_BACKGROUND permission granted");
}
return BalVerdict.BLOCK;
@@ -1149,7 +1115,7 @@ public class BackgroundActivityStartController {
if (getService().hasSystemAlertWindowPermission(state.mCallingUid, state.mCallingPid,
state.mCallingPackage)) {
return new BalVerdict(BAL_ALLOW_SAW_PERMISSION,
- /*background*/ true, "SYSTEM_ALERT_WINDOW permission is granted");
+ "SYSTEM_ALERT_WINDOW permission is granted");
}
return BalVerdict.BLOCK;
};
@@ -1159,7 +1125,7 @@ public class BackgroundActivityStartController {
if (isSystemExemptFlagEnabled() && getService().getAppOpsManager().checkOpNoThrow(
AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
state.mCallingUid, state.mCallingPackage) == AppOpsManager.MODE_ALLOWED) {
- return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ true,
+ return new BalVerdict(BAL_ALLOW_PERMISSION,
"OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted");
}
return BalVerdict.BLOCK;
@@ -1200,8 +1166,7 @@ public class BackgroundActivityStartController {
|| state.mAppSwitchState == APP_SWITCH_FG_ONLY
|| isHomeApp(state.mRealCallingUid, state.mRealCallingPackage);
if (appSwitchAllowedOrFg && state.mRealCallingUidHasVisibleActivity) {
- return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW,
- /*background*/ false, "realCallingUid has visible window");
+ return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "realCallingUid has visible window");
}
return BalVerdict.BLOCK;
};
@@ -1209,9 +1174,9 @@ public class BackgroundActivityStartController {
private final BalExemptionCheck mCheckRealCallerNonAppVisible = state -> {
if (state.mRealCallingUidHasNonAppVisibleWindow) {
return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW,
- /*background*/ false, "realCallingUid has non-app visible window "
- + getService().mActiveUids.getNonAppVisibleWindowDetails(
- state.mRealCallingUid));
+ "realCallingUid has non-app visible window "
+ + getService().mActiveUids.getNonAppVisibleWindowDetails(
+ state.mRealCallingUid));
}
return BalVerdict.BLOCK;
};
@@ -1230,9 +1195,7 @@ public class BackgroundActivityStartController {
== MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS;
if (allowAlways
&& hasBalPermission(state.mRealCallingUid, state.mRealCallingPid)) {
- return new BalVerdict(BAL_ALLOW_PERMISSION,
- /*background*/ false,
- "realCallingUid has BAL permission.");
+ return new BalVerdict(BAL_ALLOW_PERMISSION, "realCallingUid has BAL permission.");
}
return BalVerdict.BLOCK;
};
@@ -1245,7 +1208,7 @@ public class BackgroundActivityStartController {
&& getService().hasSystemAlertWindowPermission(state.mRealCallingUid,
state.mRealCallingPid, state.mRealCallingPackage)) {
return new BalVerdict(BAL_ALLOW_SAW_PERMISSION,
- /*background*/ true, "SYSTEM_ALERT_WINDOW permission is granted");
+ "SYSTEM_ALERT_WINDOW permission is granted");
}
return BalVerdict.BLOCK;
};
@@ -1258,7 +1221,6 @@ public class BackgroundActivityStartController {
if ((allowAlways || state.mAllowBalExemptionForSystemProcess)
&& state.mIsRealCallingUidPersistentSystemProcess) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID,
- /*background*/ false,
"realCallingUid is persistent system process AND intent "
+ "sender forced to allow.");
}
@@ -1270,7 +1232,6 @@ public class BackgroundActivityStartController {
if (getService().isAssociatedCompanionApp(
UserHandle.getUserId(state.mRealCallingUid), state.mRealCallingUid)) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ false,
"realCallingUid is a companion app.");
}
return BalVerdict.BLOCK;
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index ccf1aedb3177..31b239421baf 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -125,27 +125,27 @@ class BackgroundLaunchProcessController {
long lastActivityFinishTime) {
// Allow if the proc is instrumenting with background activity starts privs.
if (checkConfiguration.checkOtherExemptions && hasBackgroundActivityStartPrivileges) {
- return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ true,
+ return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/
"process instrumenting with background activity starts privileges");
}
// Allow if the flag was explicitly set.
if (checkConfiguration.checkOtherExemptions && isBackgroundStartAllowedByToken(uid,
packageName, checkConfiguration.isCheckingForFgsStart)) {
return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_TOKEN : BAL_ALLOW_PERMISSION,
- /*background*/ true, "process allowed by token");
+ /*background*/ "process allowed by token");
}
// Allow if the caller is bound by a UID that's currently foreground.
// But still respect the appSwitchState.
if (checkConfiguration.checkVisibility && appSwitchState != APP_SWITCH_DISALLOW
&& isBoundByForegroundUid()) {
return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_BOUND_BY_FOREGROUND
- : BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false,
+ : BAL_ALLOW_VISIBLE_WINDOW, /*background*/
"process bound by foreground uid");
}
// Allow if the caller has an activity in any foreground task.
if (checkConfiguration.checkOtherExemptions && hasActivityInVisibleTask
&& appSwitchState != APP_SWITCH_DISALLOW) {
- return new BalVerdict(BAL_ALLOW_FOREGROUND, /*background*/ false,
+ return new BalVerdict(BAL_ALLOW_FOREGROUND, /*background*/
"process has activity in foreground task");
}
@@ -160,7 +160,7 @@ class BackgroundLaunchProcessController {
long timeSinceLastStartOrFinish = now - Math.max(lastActivityLaunchTime,
lastActivityFinishTime);
if (timeSinceLastStartOrFinish < checkConfiguration.gracePeriod) {
- return new BalVerdict(BAL_ALLOW_GRACE_PERIOD, /*background*/ true,
+ return new BalVerdict(BAL_ALLOW_GRACE_PERIOD, /*background*/
"within " + checkConfiguration.gracePeriod + "ms grace period ("
+ timeSinceLastStartOrFinish + "ms)");
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 64c19ff70c9f..574ab05075c4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6575,6 +6575,22 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
.getKeyguardController().isKeyguardLocked(mDisplayId);
}
+ boolean isKeyguardLockedOrAodShowing() {
+ return isKeyguardLocked() || isAodShowing();
+ }
+
+ /**
+ * @return whether aod is showing for this display
+ */
+ boolean isAodShowing() {
+ final boolean isAodShowing = mRootWindowContainer.mTaskSupervisor
+ .getKeyguardController().isAodShowing(mDisplayId);
+ if (mDisplayId == DEFAULT_DISPLAY && isAodShowing) {
+ return !isKeyguardGoingAway();
+ }
+ return isAodShowing;
+ }
+
/**
* @return whether keyguard is going away on this display
*/
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 6d73739e5046..4eeed5ec8423 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
@@ -216,6 +217,9 @@ class KeyguardController {
} else if (keyguardShowing && !state.mKeyguardShowing) {
transition.addFlag(TRANSIT_FLAG_KEYGUARD_APPEARING);
}
+ if (mWindowManager.mFlags.mAodTransition && aodShowing && !state.mAodShowing) {
+ transition.addFlag(TRANSIT_FLAG_AOD_APPEARING);
+ }
}
}
// Update the task snapshot if the screen will not be turned off. To make sure that the
@@ -238,19 +242,28 @@ class KeyguardController {
state.mAodShowing = aodShowing;
state.writeEventLog("setKeyguardShown");
- if (keyguardChanged) {
- // Irrelevant to AOD.
- state.mKeyguardGoingAway = false;
- if (keyguardShowing) {
- state.mDismissalRequested = false;
+ if (keyguardChanged || (mWindowManager.mFlags.mAodTransition && aodChanged)) {
+ if (keyguardChanged) {
+ // Irrelevant to AOD.
+ state.mKeyguardGoingAway = false;
+ if (keyguardShowing) {
+ state.mDismissalRequested = false;
+ }
}
if (goingAwayRemoved
- || (keyguardShowing && !Display.isOffState(dc.getDisplayInfo().state))) {
+ || (keyguardShowing && !Display.isOffState(dc.getDisplayInfo().state))
+ || (mWindowManager.mFlags.mAodTransition && aodShowing)) {
// Keyguard decided to show or stopped going away. Send a transition to animate back
// to the locked state before holding the sleep token again
if (!ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
- dc.requestTransitionAndLegacyPrepare(
- TRANSIT_TO_FRONT, TRANSIT_FLAG_KEYGUARD_APPEARING, /* trigger= */ null);
+ if (keyguardChanged) {
+ dc.requestTransitionAndLegacyPrepare(TRANSIT_TO_FRONT,
+ TRANSIT_FLAG_KEYGUARD_APPEARING, /* trigger= */ null);
+ }
+ if (mWindowManager.mFlags.mAodTransition && aodChanged && aodShowing) {
+ dc.requestTransitionAndLegacyPrepare(TRANSIT_TO_FRONT,
+ TRANSIT_FLAG_AOD_APPEARING, /* trigger= */ null);
+ }
}
dc.mWallpaperController.adjustWallpaperWindows();
dc.executeAppTransition();
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 3db1d50f3d6a..c78cdaa10df2 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -980,6 +981,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
return false;
}
+ boolean isInAodAppearTransition() {
+ return (mFlags & TRANSIT_FLAG_AOD_APPEARING) != 0;
+ }
+
/**
* Specifies configuration change explicitly for the window container, so it can be chosen as
* transition target. This is usually used with transition mode
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 11c5c9345ab2..9b3b4451a746 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -526,6 +526,19 @@ class TransitionController {
return false;
}
+ boolean isInAodAppearTransition() {
+ if (mCollectingTransition != null && mCollectingTransition.isInAodAppearTransition()) {
+ return true;
+ }
+ for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) {
+ if (mWaitingTransitions.get(i).isInAodAppearTransition()) return true;
+ }
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ if (mPlayingTransitions.get(i).isInAodAppearTransition()) return true;
+ }
+ return false;
+ }
+
/**
* @return A pair of the transition and restore-behind target for the given {@param container}.
* @param container An ancestor of a transient-launch activity
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index a8b9fedcdc73..644417ec98e5 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -166,6 +166,14 @@ class WallpaperController {
mFindResults.setWallpaperTarget(w);
return false;
}
+ } else if (mService.mFlags.mAodTransition
+ && mDisplayContent.isKeyguardLockedOrAodShowing()) {
+ if (mService.mPolicy.isKeyguardHostWindow(w.mAttrs)
+ && w.mTransitionController.isInAodAppearTransition()) {
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Found aod transition wallpaper target: " + w);
+ mFindResults.setWallpaperTarget(w);
+ return true;
+ }
}
final boolean animationWallpaper = animatingContainer != null
@@ -678,7 +686,8 @@ class WallpaperController {
private WallpaperWindowToken getTokenForTarget(WindowState target) {
if (target == null) return null;
WindowState window = mFindResults.getTopWallpaper(
- target.canShowWhenLocked() && mService.isKeyguardLocked());
+ (target.canShowWhenLocked() && mService.isKeyguardLocked())
+ || (mService.mFlags.mAodTransition && mDisplayContent.isAodShowing()));
return window == null ? null : window.mToken.asWallpaperToken();
}
@@ -721,7 +730,9 @@ class WallpaperController {
if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) {
mFindResults.setWallpaperTarget(
- mFindResults.getTopWallpaper(mDisplayContent.isKeyguardLocked()));
+ mFindResults.getTopWallpaper(mService.mFlags.mAodTransition
+ ? mDisplayContent.isKeyguardLockedOrAodShowing()
+ : mDisplayContent.isKeyguardLocked()));
}
}
@@ -885,11 +896,17 @@ class WallpaperController {
if (mDisplayContent.mWmService.mFlags.mEnsureWallpaperInTransitions) {
visibleRequested = mWallpaperTarget != null && mWallpaperTarget.isVisibleRequested();
}
- updateWallpaperTokens(visibleRequested, mDisplayContent.isKeyguardLocked());
+ updateWallpaperTokens(visibleRequested,
+ mService.mFlags.mAodTransition
+ ? mDisplayContent.isKeyguardLockedOrAodShowing()
+ : mDisplayContent.isKeyguardLocked());
ProtoLog.v(WM_DEBUG_WALLPAPER,
"Wallpaper at display %d - visibility: %b, keyguardLocked: %b",
- mDisplayContent.getDisplayId(), visible, mDisplayContent.isKeyguardLocked());
+ mDisplayContent.getDisplayId(), visible,
+ mService.mFlags.mAodTransition
+ ? mDisplayContent.isKeyguardLockedOrAodShowing()
+ : mDisplayContent.isKeyguardLocked());
if (visible && mLastFrozen != mFindResults.isWallpaperTargetForLetterbox) {
mLastFrozen = mFindResults.isWallpaperTargetForLetterbox;
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceMockedTest.java
index 6ad3df1dd6f2..ac11216bdf0a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceMockedTest.java
@@ -102,11 +102,12 @@ import java.io.FileInputStream;
import java.io.IOException;
/**
- * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest}
+ * Run as {@code atest
+ * FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceMockedTest}
*/
-public final class UserManagerServiceTest {
+public final class UserManagerServiceMockedTest {
- private static final String TAG = UserManagerServiceTest.class.getSimpleName();
+ private static final String TAG = UserManagerServiceMockedTest.class.getSimpleName();
/**
* Id for a simple user (that doesn't have profiles).
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
index 17d8882b487c..ea83825cd810 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
@@ -571,6 +571,95 @@ public class AutoclickControllerTest {
assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isNotEqualTo(-1);
}
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+ public void pauseButton_panelNotHovered_clickNotTriggeredWhenPaused() {
+ injectFakeMouseActionHoverMoveEvent();
+
+ // Pause autoclick and ensure the panel is not hovered.
+ AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class);
+ when(mockAutoclickTypePanel.isPaused()).thenReturn(true);
+ when(mockAutoclickTypePanel.isHovered()).thenReturn(false);
+ mController.mAutoclickTypePanel = mockAutoclickTypePanel;
+
+ // Send hover move event.
+ MotionEvent hoverMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 100,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 30f,
+ /* y= */ 0f,
+ /* metaState= */ 0);
+ hoverMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0);
+
+ // Verify click is not triggered.
+ assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse();
+ assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isEqualTo(-1);
+ }
+
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+ public void pauseButton_panelHovered_clickTriggeredWhenPaused() {
+ injectFakeMouseActionHoverMoveEvent();
+
+ // Pause autoclick and hover the panel.
+ AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class);
+ when(mockAutoclickTypePanel.isPaused()).thenReturn(true);
+ when(mockAutoclickTypePanel.isHovered()).thenReturn(true);
+ mController.mAutoclickTypePanel = mockAutoclickTypePanel;
+
+ // Send hover move event.
+ MotionEvent hoverMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 100,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 30f,
+ /* y= */ 0f,
+ /* metaState= */ 0);
+ hoverMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0);
+
+ // Verify click is triggered.
+ assertThat(mController.mClickScheduler.getIsActiveForTesting()).isTrue();
+ assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isNotEqualTo(-1);
+ }
+
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+ public void pauseButton_unhoveringCancelsClickWhenPaused() {
+ injectFakeMouseActionHoverMoveEvent();
+
+ // Pause autoclick and hover the panel.
+ AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class);
+ when(mockAutoclickTypePanel.isPaused()).thenReturn(true);
+ when(mockAutoclickTypePanel.isHovered()).thenReturn(true);
+ mController.mAutoclickTypePanel = mockAutoclickTypePanel;
+
+ // Send hover move event.
+ MotionEvent hoverMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 100,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 30f,
+ /* y= */ 0f,
+ /* metaState= */ 0);
+ hoverMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0);
+
+ // Verify click is triggered.
+ assertThat(mController.mClickScheduler.getIsActiveForTesting()).isTrue();
+ assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isNotEqualTo(-1);
+
+ // Now simulate the pointer being moved outside the panel.
+ when(mockAutoclickTypePanel.isHovered()).thenReturn(false);
+ mController.clickPanelController.onHoverChange(/* hovered= */ false);
+
+ // Verify pending click is canceled.
+ assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse();
+ assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isEqualTo(-1);
+ }
+
private void injectFakeMouseActionHoverMoveEvent() {
MotionEvent event = getFakeMotionHoverMoveEvent();
event.setSource(InputDevice.SOURCE_MOUSE);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickLinearLayoutTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickLinearLayoutTest.java
new file mode 100644
index 000000000000..9e629f7c87a2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickLinearLayoutTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 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.accessibility.autoclick;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.view.MotionEvent;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Test cases for {@link AutoclickLinearLayout}. */
+@RunWith(AndroidTestingRunner.class)
+public class AutoclickLinearLayoutTest {
+ private boolean mHovered;
+
+ private final AutoclickLinearLayout.OnHoverChangedListener mListener =
+ new AutoclickLinearLayout.OnHoverChangedListener() {
+ @Override
+ public void onHoverChanged(boolean hovered) {
+ mHovered = hovered;
+ }
+ };
+
+ @Rule
+ public TestableContext mTestableContext =
+ new TestableContext(getInstrumentation().getContext());
+ private AutoclickLinearLayout mAutoclickLinearLayout;
+
+ @Before
+ public void setUp() {
+ mAutoclickLinearLayout = new AutoclickLinearLayout(mTestableContext);
+ }
+
+ @Test
+ public void autoclickLinearLayout_hoverChangedListener_setHovered() {
+ mHovered = false;
+ mAutoclickLinearLayout.setOnHoverChangedListener(mListener);
+ mAutoclickLinearLayout.onHoverChanged(/* hovered= */ true);
+ assertThat(mHovered).isTrue();
+ }
+
+ @Test
+ public void autoclickLinearLayout_hoverChangedListener_setNotHovered() {
+ mHovered = true;
+
+ mAutoclickLinearLayout.setOnHoverChangedListener(mListener);
+ mAutoclickLinearLayout.onHoverChanged(/* hovered= */ false);
+ assertThat(mHovered).isFalse();
+ }
+
+ @Test
+ public void autoclickLinearLayout_onInterceptHoverEvent_hovered() {
+ mAutoclickLinearLayout.setHovered(false);
+ mAutoclickLinearLayout.onInterceptHoverEvent(
+ getFakeMotionEvent(MotionEvent.ACTION_HOVER_ENTER));
+ assertThat(mAutoclickLinearLayout.isHovered()).isTrue();
+
+ mAutoclickLinearLayout.setHovered(false);
+ mAutoclickLinearLayout.onInterceptHoverEvent(
+ getFakeMotionEvent(MotionEvent.ACTION_HOVER_MOVE));
+ assertThat(mAutoclickLinearLayout.isHovered()).isTrue();
+ }
+
+ @Test
+ public void autoclickLinearLayout_onInterceptHoverEvent_hoveredExit() {
+ mAutoclickLinearLayout.setHovered(true);
+ mAutoclickLinearLayout.onInterceptHoverEvent(
+ getFakeMotionEvent(MotionEvent.ACTION_HOVER_EXIT));
+ assertThat(mAutoclickLinearLayout.isHovered()).isFalse();
+ }
+
+ private MotionEvent getFakeMotionEvent(int motionEventAction) {
+ return MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 0,
+ /* action= */ motionEventAction,
+ /* x= */ 0,
+ /* y= */ 0,
+ /* metaState= */ 0);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java
index 9e123406dff5..f7b16c808c50 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java
@@ -78,6 +78,7 @@ public class AutoclickTypePanelTest {
private @AutoclickType int mActiveClickType = AUTOCLICK_TYPE_LEFT_CLICK;
private boolean mPaused;
+ private boolean mHovered;
private final ClickPanelControllerInterface clickPanelController =
new ClickPanelControllerInterface() {
@@ -90,6 +91,11 @@ public class AutoclickTypePanelTest {
public void toggleAutoclickPause(boolean paused) {
mPaused = paused;
}
+
+ @Override
+ public void onHoverChange(boolean hovered) {
+ mHovered = hovered;
+ }
};
@Before
@@ -412,6 +418,33 @@ public class AutoclickTypePanelTest {
upEvent.recycle();
}
+ @Test
+ public void hovered_IsHovered() {
+ AutoclickLinearLayout mContext = mAutoclickTypePanel.getContentViewForTesting();
+
+ assertThat(mAutoclickTypePanel.isHovered()).isFalse();
+ mContext.onInterceptHoverEvent(getFakeMotionHoverMoveEvent());
+ assertThat(mAutoclickTypePanel.isHovered()).isTrue();
+ }
+
+ @Test
+ public void hovered_OnHoverChange_isHovered() {
+ AutoclickLinearLayout mContext = mAutoclickTypePanel.getContentViewForTesting();
+
+ mHovered = false;
+ mContext.onHoverChanged(true);
+ assertThat(mHovered).isTrue();
+ }
+
+ @Test
+ public void hovered_OnHoverChange_isNotHovered() {
+ AutoclickLinearLayout mContext = mAutoclickTypePanel.getContentViewForTesting();
+
+ mHovered = true;
+ mContext.onHoverChanged(false);
+ assertThat(mHovered).isFalse();
+ }
+
private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) {
GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground();
assertThat(gradientDrawable.getColor().getDefaultColor())
@@ -426,4 +459,14 @@ public class AutoclickTypePanelTest {
assertThat(params.x).isEqualTo(expectedPosition[2]);
assertThat(params.y).isEqualTo(expectedPosition[3]);
}
+
+ private MotionEvent getFakeMotionHoverMoveEvent() {
+ return MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 0,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 0,
+ /* y= */ 0,
+ /* metaState= */ 0);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java
index 84713079c9d3..01fee7f66497 100644
--- a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java
@@ -226,9 +226,9 @@ public class DiscreteAppOpSqlPersistenceTest {
mDiscreteRegistry.recordDiscreteAccess(event2);
}
- /** This clears in-memory cache and push records into the database. */
private void flushDiscreteOpsToDatabase() {
- mDiscreteRegistry.writeAndClearOldAccessHistory();
+ // This clears in-memory cache and push records from cache into the database.
+ mDiscreteRegistry.shutdown();
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java b/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java
index 21cc3bac3938..8eea1c73d4f2 100644
--- a/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java
@@ -106,7 +106,8 @@ public class DiscreteOpsMigrationAndRollbackTest {
opEvent.getDuration(), opEvent.getAttributionFlags(),
(int) opEvent.getChainId(), DiscreteOpsRegistry.ACCESS_TYPE_NOTE_OP);
}
- sqlRegistry.writeAndClearOldAccessHistory();
+ // flush records from cache to the database.
+ sqlRegistry.shutdown();
assertThat(sqlRegistry.getAllDiscreteOps().size()).isEqualTo(RECORD_COUNT);
assertThat(sqlRegistry.getLargestAttributionChainId()).isEqualTo(RECORD_COUNT);
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java
index c934c55dfb8e..e3a8776aca6a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java
@@ -486,7 +486,7 @@ public class BackgroundActivityStartControllerExemptionTests {
// setup state
when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn(
- new BalVerdict(BAL_ALLOW_FOREGROUND, false, "allowed"));
+ new BalVerdict(BAL_ALLOW_FOREGROUND, "allowed"));
when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);
// prepare call
@@ -523,7 +523,7 @@ public class BackgroundActivityStartControllerExemptionTests {
mCallerApp);
when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);
when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn(
- new BalVerdict(BAL_ALLOW_FOREGROUND, false, "allowed"));
+ new BalVerdict(BAL_ALLOW_FOREGROUND, "allowed"));
// prepare call
PendingIntentRecord originatingPendingIntent = mPendingIntentRecord;
@@ -572,7 +572,7 @@ public class BackgroundActivityStartControllerExemptionTests {
when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn(
BalVerdict.BLOCK);
when(otherProcess.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn(
- new BalVerdict(BAL_ALLOW_FOREGROUND, false, "allowed"));
+ new BalVerdict(BAL_ALLOW_FOREGROUND, "allowed"));
// prepare call
PendingIntentRecord originatingPendingIntent = mPendingIntentRecord;
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java
index 99e730ae76cf..cd5f3912bfc6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java
@@ -92,7 +92,7 @@ public class BackgroundActivityStartControllerLogTests {
@Test
public void intent_visible_noLog() {
useIntent();
- BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "visible");
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "visible");
mState.setResultForCaller(finalVerdict);
mState.setResultForRealCaller(BalVerdict.BLOCK);
assertThat(mController.shouldLogStats(finalVerdict, mState)).isFalse();
@@ -101,7 +101,7 @@ public class BackgroundActivityStartControllerLogTests {
@Test
public void intent_saw_log() {
useIntent();
- BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW");
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW");
mState.setResultForCaller(finalVerdict);
mState.setResultForRealCaller(BalVerdict.BLOCK);
assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue();
@@ -111,7 +111,7 @@ public class BackgroundActivityStartControllerLogTests {
@Test
public void pendingIntent_callerOnly_saw_log() {
usePendingIntent();
- BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW");
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW");
mState.setResultForCaller(finalVerdict);
mState.setResultForRealCaller(BalVerdict.BLOCK);
assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue();
@@ -121,7 +121,7 @@ public class BackgroundActivityStartControllerLogTests {
@Test
public void pendingIntent_realCallerOnly_saw_log() {
usePendingIntent();
- BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW")
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW")
.setBasedOnRealCaller();
mState.setResultForCaller(BalVerdict.BLOCK);
mState.setResultForRealCaller(finalVerdict);
@@ -131,7 +131,7 @@ public class BackgroundActivityStartControllerLogTests {
@Test
public void intent_shouldLogIntentActivity() {
- BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW");
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW");
useIntent(APP1_UID);
assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
useIntent(SYSTEM_UID);
@@ -140,7 +140,7 @@ public class BackgroundActivityStartControllerLogTests {
@Test
public void pendingIntent_shouldLogIntentActivityForCaller() {
- BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW");
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW");
usePendingIntent(APP1_UID, APP2_UID);
assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
usePendingIntent(SYSTEM_UID, SYSTEM_UID);
@@ -153,7 +153,7 @@ public class BackgroundActivityStartControllerLogTests {
@Test
public void pendingIntent_shouldLogIntentActivityForRealCaller() {
- BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false,
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION,
"SAW").setBasedOnRealCaller();
usePendingIntent(APP1_UID, APP2_UID);
assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
@@ -168,7 +168,7 @@ public class BackgroundActivityStartControllerLogTests {
@Test
public void pendingIntent_realCallerOnly_visible_noLog() {
usePendingIntent();
- BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false,
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW,
"visible").setBasedOnRealCaller();
mState.setResultForCaller(BalVerdict.BLOCK);
mState.setResultForRealCaller(finalVerdict);
@@ -178,7 +178,7 @@ public class BackgroundActivityStartControllerLogTests {
@Test
public void pendingIntent_callerOnly_visible_noLog() {
usePendingIntent();
- BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "visible");
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "visible");
mState.setResultForCaller(finalVerdict);
mState.setResultForRealCaller(BalVerdict.BLOCK);
assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue();
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java
index 51706d72cb35..fe9a6e746513 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java
@@ -305,7 +305,7 @@ public class BackgroundActivityStartControllerTests {
@Test
public void testRegularActivityStart_allowedByCaller_isAllowed() {
// setup state
- BalVerdict callerVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false,
+ BalVerdict callerVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW,
"CallerIsVisible");
mController.setCallerVerdict(callerVerdict);
mController.setRealCallerVerdict(BalVerdict.BLOCK);
@@ -340,7 +340,7 @@ public class BackgroundActivityStartControllerTests {
@Test
public void testRegularActivityStart_allowedByRealCaller_isAllowed() {
// setup state
- BalVerdict realCallerVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false,
+ BalVerdict realCallerVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW,
"RealCallerIsVisible");
mController.setCallerVerdict(BalVerdict.BLOCK);
mController.setRealCallerVerdict(realCallerVerdict);
@@ -373,9 +373,9 @@ public class BackgroundActivityStartControllerTests {
public void testRegularActivityStart_allowedByCallerAndRealCaller_returnsCallerVerdict() {
// setup state
BalVerdict callerVerdict =
- new BalVerdict(BAL_ALLOW_PERMISSION, false, "CallerHasPermission");
+ new BalVerdict(BAL_ALLOW_PERMISSION, "CallerHasPermission");
BalVerdict realCallerVerdict =
- new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "RealCallerIsVisible");
+ new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "RealCallerIsVisible");
mController.setCallerVerdict(callerVerdict);
mController.setRealCallerVerdict(realCallerVerdict);
@@ -411,9 +411,9 @@ public class BackgroundActivityStartControllerTests {
public void testPendingIntent_allowedByCallerAndRealCallerButOptOut_isBlocked() {
// setup state
BalVerdict callerVerdict =
- new BalVerdict(BAL_ALLOW_PERMISSION, false, "CallerhasPermission");
+ new BalVerdict(BAL_ALLOW_PERMISSION, "CallerhasPermission");
BalVerdict realCallerVerdict =
- new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "RealCallerIsVisible");
+ new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "RealCallerIsVisible");
mController.setCallerVerdict(callerVerdict);
mController.setRealCallerVerdict(realCallerVerdict);
@@ -452,7 +452,7 @@ public class BackgroundActivityStartControllerTests {
public void testPendingIntent_allowedByCallerAndOptIn_isAllowed() {
// setup state
BalVerdict callerVerdict =
- new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "CallerIsVisible");
+ new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "CallerIsVisible");
mController.setCallerVerdict(callerVerdict);
mController.setRealCallerVerdict(BalVerdict.BLOCK);
@@ -489,7 +489,7 @@ public class BackgroundActivityStartControllerTests {
public void testPendingIntent_allowedByRealCallerAndOptIn_isAllowed() {
// setup state
BalVerdict realCallerVerdict =
- new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "RealCallerIsVisible");
+ new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "RealCallerIsVisible");
mController.setCallerVerdict(BalVerdict.BLOCK);
mController.setRealCallerVerdict(realCallerVerdict);
@@ -571,7 +571,6 @@ public class BackgroundActivityStartControllerTests {
+ "callerApp: mCallerApp; "
+ "inVisibleTask: false; "
+ "balAllowedByPiCreator: BSP.ALLOW_BAL; "
- + "balAllowedByPiCreatorWithHardening: BSP.ALLOW_BAL; "
+ "callerStartMode: MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; "
+ "hasRealCaller: true; "
+ "isCallForResult: false; "
@@ -674,7 +673,6 @@ public class BackgroundActivityStartControllerTests {
+ "callerApp: mCallerApp; "
+ "inVisibleTask: false; "
+ "balAllowedByPiCreator: BSP.NONE; "
- + "balAllowedByPiCreatorWithHardening: BSP.NONE; "
+ "callerStartMode: MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; "
+ "hasRealCaller: true; "
+ "isCallForResult: false; "
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index a97f9a837bab..3cccbc419425 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -41,6 +41,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -1088,6 +1089,10 @@ public class VcnManagementServiceTest {
@Test
public void testGetRestrictedTransportsFromCarrierConfig() {
+ assumeTrue(
+ "Configuring restricted transport types is only allowed on a debuggable build",
+ Build.isDebuggable());
+
final Set<Integer> restrictedTransports = new ArraySet<>();
restrictedTransports.add(TRANSPORT_CELLULAR);
restrictedTransports.add(TRANSPORT_WIFI);
@@ -1109,6 +1114,10 @@ public class VcnManagementServiceTest {
@Test
public void testGetRestrictedTransportsFromCarrierConfig_noRestrictPolicyConfigured() {
+ assumeTrue(
+ "Configuring restricted transport types is only allowed on a debuggable build",
+ Build.isDebuggable());
+
final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
final PersistableBundleWrapper carrierConfig =
@@ -1123,6 +1132,10 @@ public class VcnManagementServiceTest {
@Test
public void testGetRestrictedTransportsFromCarrierConfig_noCarrierConfig() {
+ assumeTrue(
+ "Configuring restricted transport types is only allowed on a debuggable build",
+ Build.isDebuggable());
+
final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
final TelephonySubscriptionSnapshot lastSnapshot =
@@ -1134,6 +1147,10 @@ public class VcnManagementServiceTest {
@Test
public void testGetRestrictedTransportsFromCarrierConfigAndVcnConfig() {
+ assumeTrue(
+ "Configuring restricted transport types is only allowed on a debuggable build",
+ Build.isDebuggable());
+
// Configure restricted transport in CarrierConfig
final Set<Integer> restrictedTransportInCarrierConfig =
Collections.singleton(TRANSPORT_WIFI);