summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java9
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java9
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java6
-rw-r--r--core/java/android/provider/CallLog.java6
-rw-r--r--core/java/android/view/InsetsController.java12
-rw-r--r--core/java/android/view/InsetsState.java51
-rw-r--r--core/java/android/view/ViewGroup.java2
-rw-r--r--core/java/android/widget/Editor.java42
-rw-r--r--core/proto/android/server/windowmanagerservice.proto2
-rw-r--r--core/tests/coretests/src/android/view/InsetsStateTest.java91
-rw-r--r--core/tests/coretests/src/android/view/ViewGroupTest.java19
-rw-r--r--data/etc/com.android.systemui.xml1
-rw-r--r--libs/WindowManager/Shell/Android.bp1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java308
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt36
-rw-r--r--packages/SettingsLib/IllustrationPreference/res/values/colors.xml2
-rw-r--r--packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java9
-rw-r--r--packages/SystemUI/Android.bp2
-rw-r--r--packages/SystemUI/OWNERS1
-rw-r--r--packages/SystemUI/TEST_MAPPING30
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt36
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt115
-rw-r--r--packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt4
-rw-r--r--packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt91
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt20
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt12
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt50
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt12
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt12
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt4
-rw-r--r--packages/SystemUI/res/layout/media_projection_app_selector.xml6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt169
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt118
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt (renamed from packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt)25
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelModule.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt30
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java107
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java65
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java102
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt45
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt80
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt53
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt246
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsFingerprintViewModelTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModelTest.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt121
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt)126
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt (renamed from packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerNames.kt)18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java13
-rw-r--r--packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt55
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt31
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java5
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java9
-rw-r--r--services/core/java/com/android/server/os/BugreportManagerServiceImpl.java23
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java22
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java8
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java216
-rw-r--r--services/core/java/com/android/server/wm/StartingData.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java6
-rw-r--r--services/core/java/com/android/server/wm/Transition.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java19
-rw-r--r--services/print/java/com/android/server/print/PrintManagerService.java35
-rw-r--r--services/tests/servicestests/AndroidManifest.xml1
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java57
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java10
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java2
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java15
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl1
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java5
190 files changed, 3204 insertions, 1919 deletions
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 3a660812fd24..c872516014db 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -3535,7 +3535,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_DEFAULT } mode.
* They can be queried through
* {@link android.hardware.camera2.CameraCharacteristics#get } with
- * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION) }.
+ * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION }.
* Unless reported by both
* {@link android.hardware.camera2.params.StreamConfigurationMap }s, the outputs from
* <code>{@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION android.scaler.streamConfigurationMapMaximumResolution}</code> and
@@ -3550,13 +3550,12 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <ul>
* <li>
* <p>The mandatory stream combinations listed in
- * {@link android.hardware.camera2.CameraCharacteristics.mandatoryMaximumResolutionStreamCombinations }
- * would not apply.</p>
+ * {@link CameraCharacteristics#SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS android.scaler.mandatoryMaximumResolutionStreamCombinations} would not apply.</p>
* </li>
* <li>
* <p>The bayer pattern of {@code RAW} streams when
* {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION }
- * is selected will be the one listed in {@link android.sensor.info.binningFactor }.</p>
+ * is selected will be the one listed in {@link CameraCharacteristics#SENSOR_INFO_BINNING_FACTOR android.sensor.info.binningFactor}.</p>
* </li>
* <li>
* <p>The following keys will always be present:</p>
@@ -3576,9 +3575,11 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
*
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+ * @see CameraCharacteristics#SENSOR_INFO_BINNING_FACTOR
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see #SENSOR_PIXEL_MODE_DEFAULT
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 1536376e4eb5..57f7bca1f67e 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -4460,7 +4460,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_DEFAULT } mode.
* They can be queried through
* {@link android.hardware.camera2.CameraCharacteristics#get } with
- * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION) }.
+ * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION }.
* Unless reported by both
* {@link android.hardware.camera2.params.StreamConfigurationMap }s, the outputs from
* <code>{@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION android.scaler.streamConfigurationMapMaximumResolution}</code> and
@@ -4475,13 +4475,12 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <ul>
* <li>
* <p>The mandatory stream combinations listed in
- * {@link android.hardware.camera2.CameraCharacteristics.mandatoryMaximumResolutionStreamCombinations }
- * would not apply.</p>
+ * {@link CameraCharacteristics#SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS android.scaler.mandatoryMaximumResolutionStreamCombinations} would not apply.</p>
* </li>
* <li>
* <p>The bayer pattern of {@code RAW} streams when
* {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION }
- * is selected will be the one listed in {@link android.sensor.info.binningFactor }.</p>
+ * is selected will be the one listed in {@link CameraCharacteristics#SENSOR_INFO_BINNING_FACTOR android.sensor.info.binningFactor}.</p>
* </li>
* <li>
* <p>The following keys will always be present:</p>
@@ -4501,9 +4500,11 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
*
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+ * @see CameraCharacteristics#SENSOR_INFO_BINNING_FACTOR
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see #SENSOR_PIXEL_MODE_DEFAULT
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7b5dd55f385b..795eb4a737ef 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1019,8 +1019,9 @@ public class InputMethodService extends AbstractInputMethodService {
if (!mOnPreparedStylusHwCalled) {
// prepare hasn't been called by Stylus HOVER.
onPrepareStylusHandwriting();
- mOnPreparedStylusHwCalled = true;
}
+ // reset flag as it's not relevant after onStartStylusHandwriting().
+ mOnPreparedStylusHwCalled = false;
if (onStartStylusHandwriting()) {
cancelStylusWindowIdleTimeout();
mPrivOps.onStylusHandwritingReady(requestId, Process.myPid());
@@ -3089,7 +3090,8 @@ public class InputMethodService extends AbstractInputMethodService {
mInputStarted = false;
mStartedInputConnection = null;
mCurCompletions = null;
- if (mInkWindow != null) {
+ if (!mOnPreparedStylusHwCalled) {
+ // If IME didn't prepare to show InkWindow for current handwriting session.
finishStylusHandwriting();
}
// Back callback is typically unregistered in {@link #hideWindow()}, but it's possible
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 3c5757dd5615..5d6dfc760b02 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -63,6 +63,7 @@ import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -1956,9 +1957,8 @@ public class CallLog {
userManager.isUserUnlocked(user) ? CONTENT_URI : SHADOW_CONTENT_URI,
user.getIdentifier());
- if (VERBOSE_LOG) {
- Log.v(LOG_TAG, String.format("Inserting to %s", uri));
- }
+ Log.i(LOG_TAG, String.format(Locale.getDefault(),
+ "addEntryAndRemoveExpiredEntries: provider uri=%s", uri));
try {
// When cleaning up the call log, try to delete older call long entries on a per
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 17afd5576973..4ecfc4044b1d 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -844,12 +844,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
public boolean onStateChanged(InsetsState state) {
boolean stateChanged = false;
if (!CAPTION_ON_SHELL) {
- stateChanged = !mState.equals(state, true /* excludingCaptionInsets */,
- false /* excludeInvisibleIme */)
+ stateChanged = !mState.equals(state, true /* excludesCaptionBar */,
+ false /* excludesInvisibleIme */)
|| captionInsetsUnchanged();
} else {
- stateChanged = !mState.equals(state, false /* excludingCaptionInsets */,
- false /* excludeInvisibleIme */);
+ stateChanged = !mState.equals(state, false /* excludesCaptionBar */,
+ false /* excludesInvisibleIme */);
}
if (!stateChanged && mLastDispatchedState.equals(state)) {
return false;
@@ -862,8 +862,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
applyLocalVisibilityOverride();
updateCompatSysUiVisibility();
- if (!mState.equals(lastState, false /* excludingCaptionInsets */,
- true /* excludeInvisibleIme */)) {
+ if (!mState.equals(lastState, false /* excludesCaptionBar */,
+ true /* excludesInvisibleIme */)) {
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
mHost.notifyInsetsChanged();
if (lastState.getDisplayFrame().equals(mState.getDisplayFrame())) {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index c13b9ab0abd1..af24140086ed 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -380,11 +380,17 @@ public class InsetsState implements Parcelable {
@InternalInsetsSide @Nullable SparseIntArray idSideMap,
@Nullable boolean[] typeVisibilityMap, Insets insets, int type) {
int index = indexOf(type);
- Insets existing = typeInsetsMap[index];
- if (existing == null) {
- typeInsetsMap[index] = insets;
- } else {
- typeInsetsMap[index] = Insets.max(existing, insets);
+
+ // Don't put Insets.NONE into typeInsetsMap. Otherwise, two WindowInsets can be considered
+ // as non-equal while they provide the same insets of each type from WindowInsets#getInsets
+ // if one WindowInsets has Insets.NONE for a type and the other has null for the same type.
+ if (!Insets.NONE.equals(insets)) {
+ Insets existing = typeInsetsMap[index];
+ if (existing == null) {
+ typeInsetsMap[index] = insets;
+ } else {
+ typeInsetsMap[index] = Insets.max(existing, insets);
+ }
}
if (typeVisibilityMap != null) {
@@ -696,15 +702,14 @@ public class InsetsState implements Parcelable {
* An equals method can exclude the caption insets. This is useful because we assemble the
* caption insets information on the client side, and when we communicate with server, it's
* excluded.
- * @param excludingCaptionInsets {@code true} if we want to compare two InsetsState objects but
- * ignore the caption insets source value.
- * @param excludeInvisibleImeFrames If {@link WindowInsets.Type#ime()} frames should be ignored
- * when IME is not visible.
+ * @param excludesCaptionBar If {@link Type#captionBar()}} should be ignored.
+ * @param excludesInvisibleIme If {@link WindowInsets.Type#ime()} should be ignored when IME is
+ * not visible.
* @return {@code true} if the two InsetsState objects are equal, {@code false} otherwise.
*/
@VisibleForTesting
- public boolean equals(@Nullable Object o, boolean excludingCaptionInsets,
- boolean excludeInvisibleImeFrames) {
+ public boolean equals(@Nullable Object o, boolean excludesCaptionBar,
+ boolean excludesInvisibleIme) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
@@ -721,29 +726,35 @@ public class InsetsState implements Parcelable {
final SparseArray<InsetsSource> thisSources = mSources;
final SparseArray<InsetsSource> thatSources = state.mSources;
- if (!excludingCaptionInsets && !excludeInvisibleImeFrames) {
+ if (!excludesCaptionBar && !excludesInvisibleIme) {
return thisSources.contentEquals(thatSources);
} else {
final int thisSize = thisSources.size();
final int thatSize = thatSources.size();
int thisIndex = 0;
int thatIndex = 0;
- while (thisIndex < thisSize && thatIndex < thatSize) {
+ while (thisIndex < thisSize || thatIndex < thatSize) {
+ InsetsSource thisSource = thisIndex < thisSize
+ ? thisSources.valueAt(thisIndex)
+ : null;
+
// Seek to the next non-excluding source of ours.
- InsetsSource thisSource = thisSources.valueAt(thisIndex);
while (thisSource != null
- && (excludingCaptionInsets && thisSource.getType() == captionBar()
- || excludeInvisibleImeFrames && thisSource.getType() == ime()
+ && (excludesCaptionBar && thisSource.getType() == captionBar()
+ || excludesInvisibleIme && thisSource.getType() == ime()
&& !thisSource.isVisible())) {
thisIndex++;
thisSource = thisIndex < thisSize ? thisSources.valueAt(thisIndex) : null;
}
+ InsetsSource thatSource = thatIndex < thatSize
+ ? thatSources.valueAt(thatIndex)
+ : null;
+
// Seek to the next non-excluding source of theirs.
- InsetsSource thatSource = thatSources.valueAt(thatIndex);
while (thatSource != null
- && (excludingCaptionInsets && thatSource.getType() == captionBar()
- || excludeInvisibleImeFrames && thatSource.getType() == ime()
+ && (excludesCaptionBar && thatSource.getType() == captionBar()
+ || excludesInvisibleIme && thatSource.getType() == ime()
&& !thatSource.isVisible())) {
thatIndex++;
thatSource = thatIndex < thatSize ? thatSources.valueAt(thatIndex) : null;
@@ -756,7 +767,7 @@ public class InsetsState implements Parcelable {
thisIndex++;
thatIndex++;
}
- return thisIndex >= thisSize && thatIndex >= thatSize;
+ return true;
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 01a99b92a055..1b1098d9d57a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2539,7 +2539,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final int childrenCount = mChildrenCount;
if (childrenCount != 0) {
final float x = event.getXDispatchLocation(0);
- final float y = event.getXDispatchLocation(0);
+ final float y = event.getYDispatchLocation(0);
final ArrayList<View> preorderedList = buildOrderedChildList();
final boolean customOrder = preorderedList == null
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3da9e96618f3..f39122a0a5c1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -8207,7 +8207,8 @@ public class Editor {
*/
void beforeSetText() {
// TextView#setText is called because our call to
- // TextView#setTransformationMethodInternal in enterInsertMode() or exitInsertMode().
+ // TextView#setTransformationMethodInternal in enterInsertMode(), exitInsertMode() or
+ // updateTransformationMethod().
// Do nothing in this case.
if (mUpdatingTransformationMethod) {
return;
@@ -8218,22 +8219,28 @@ public class Editor {
}
/**
- * Notify the {@link InsertModeController} before the TextView's
- * {@link TransformationMethod} is updated. If it's not in the insert mode,
- * the given method is directly returned. Otherwise, it will wrap the given transformation
- * method with an {@link InsertModeTransformationMethod} and then return.
+ * Notify the {@link InsertModeController} that TextView#setTransformationMethod is called.
+ * If it's not in the insert mode, the given transformation method is directly set to the
+ * TextView. Otherwise, it will wrap the given transformation method with an
+ * {@link InsertModeTransformationMethod} and then set it on the TextView.
*
- * @param oldTransformationMethod the new {@link TransformationMethod} to be set on the
+ * @param transformationMethod the new {@link TransformationMethod} to be set on the
* TextView.
- * @return the updated {@link TransformationMethod} to be set on the Textview.
*/
- TransformationMethod updateTransformationMethod(
- TransformationMethod oldTransformationMethod) {
- if (!mIsInsertModeActive) return oldTransformationMethod;
+ void updateTransformationMethod(TransformationMethod transformationMethod) {
+ if (!mIsInsertModeActive) {
+ setTransformationMethod(transformationMethod, /* updateText */ true);
+ return;
+ }
+ // Changing TransformationMethod will reset selection range to [0, 0), we need to
+ // manually restore the old selection range.
+ final int selectionStart = mTextView.getSelectionStart();
+ final int selectionEnd = mTextView.getSelectionEnd();
mInsertModeTransformationMethod = mInsertModeTransformationMethod.update(
- oldTransformationMethod, mTextView.isSingleLine());
- return mInsertModeTransformationMethod;
+ transformationMethod, mTextView.isSingleLine());
+ setTransformationMethod(mInsertModeTransformationMethod, /* updateText */ true);
+ Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
}
}
@@ -8259,18 +8266,11 @@ public class Editor {
* @param method the {@link TransformationMethod} to be set on the TextView.
*/
void setTransformationMethod(TransformationMethod method) {
- if (mInsertModeController == null || !mInsertModeController.mIsInsertModeActive) {
+ if (mInsertModeController == null) {
mTextView.setTransformationMethodInternal(method, /* updateText */ true);
return;
}
-
- // Changing TransformationMethod will reset selection range to [0, 0), we need to
- // manually restore the old selection range.
- final int selectionStart = mTextView.getSelectionStart();
- final int selectionEnd = mTextView.getSelectionEnd();
- method = mInsertModeController.updateTransformationMethod(method);
- mTextView.setTransformationMethodInternal(method, /* updateText */ true);
- Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
+ mInsertModeController.updateTransformationMethod(method);
}
/**
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 325ebbe885b4..8e619a8bda48 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -609,4 +609,6 @@ message BackNavigationProto {
optional bool animation_in_progress = 1;
optional int32 last_back_type = 2;
optional bool show_wallpaper = 3;
+ optional string main_open_activity = 4;
+ optional bool animation_running = 5;
} \ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index fde1a6d7b04c..b06cd39d9236 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -43,6 +43,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -290,6 +291,18 @@ public class InsetsStateTest {
}
@Test
+ public void testCalculateInsets_emptyIme() {
+ WindowInsets insets1 = mState.calculateInsets(new Rect(), null, false, false,
+ SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ mState.getOrCreateSource(ID_IME, ime());
+ WindowInsets insets2 = mState.calculateInsets(new Rect(), null, false, false,
+ SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ assertEquals(Insets.NONE, insets1.getInsets(ime()));
+ assertEquals(Insets.NONE, insets2.getInsets(ime()));
+ assertEquals(insets1, insets2);
+ }
+
+ @Test
public void testStripForDispatch() {
mState.getOrCreateSource(ID_STATUS_BAR, statusBars())
.setFrame(new Rect(0, 0, 100, 100))
@@ -304,6 +317,73 @@ public class InsetsStateTest {
}
@Test
+ public void testEquals() {
+ final InsetsState state1 = new InsetsState();
+ final InsetsState state2 = new InsetsState();
+ assertTrue(state1.equals(state2));
+
+ state1.addSource(new InsetsSource(ID_STATUS_BAR, statusBars()));
+ assertFalse(state1.equals(state2));
+
+ state2.addSource(new InsetsSource(ID_STATUS_BAR, statusBars()));
+ assertTrue(state1.equals(state2));
+
+ state2.addSource(new InsetsSource(ID_NAVIGATION_BAR, navigationBars()));
+ assertFalse(state1.equals(state2));
+ }
+
+ @Test
+ public void testEquals_excludesCaptionBar() {
+ final InsetsState state1 = new InsetsState();
+ final InsetsState state2 = new InsetsState();
+
+ state1.addSource(new InsetsSource(ID_CAPTION_BAR, captionBar()).setFrame(0, 0, 0, 5));
+ assertFalse(state1.equals(
+ state2, false /* excludesCaptionBar */, false /* excludesInvisibleIme */));
+ assertTrue(state1.equals(
+ state2, true /* excludesCaptionBar */, false /* excludesInvisibleIme */));
+
+ state2.addSource(new InsetsSource(ID_CAPTION_BAR, captionBar()).setFrame(0, 0, 0, 10));
+ assertFalse(state1.equals(
+ state2, false /* excludesCaptionBar */, false /* excludesInvisibleIme */));
+ assertTrue(state1.equals(
+ state2, true /* excludesCaptionBar */, false /* excludesInvisibleIme */));
+
+ state1.addSource(new InsetsSource(ID_STATUS_BAR, statusBars()));
+ state2.addSource(new InsetsSource(ID_STATUS_BAR, statusBars()));
+ assertFalse(state1.equals(
+ state2, false /* excludesCaptionBar */, false /* excludesInvisibleIme */));
+ assertTrue(state1.equals(
+ state2, true /* excludesCaptionBar */, false /* excludesInvisibleIme */));
+ }
+
+ @Test
+ public void testEquals_excludesInvisibleIme() {
+ final InsetsState state1 = new InsetsState();
+ final InsetsState state2 = new InsetsState();
+
+ final InsetsSource imeSource1 = new InsetsSource(ID_IME, ime()).setVisible(true);
+ state1.addSource(imeSource1);
+ assertFalse(state1.equals(
+ state2, false /* excludesCaptionBar */, false /* excludesInvisibleIme */));
+ assertFalse(state1.equals(
+ state2, false /* excludesCaptionBar */, true /* excludesInvisibleIme */));
+
+ imeSource1.setVisible(false);
+ assertFalse(state1.equals(
+ state2, false /* excludesCaptionBar */, false /* excludesInvisibleIme */));
+ assertTrue(state1.equals(
+ state2, false /* excludesCaptionBar */, true /* excludesInvisibleIme */));
+
+ final InsetsSource imeSource2 = new InsetsSource(ID_IME, ime()).setFrame(0, 0, 0, 10);
+ state2.addSource(imeSource2);
+ assertFalse(state1.equals(
+ state2, false /* excludesCaptionBar */, false /* excludesInvisibleIme */));
+ assertTrue(state1.equals(
+ state2, false /* excludesCaptionBar */, true /* excludesInvisibleIme */));
+ }
+
+ @Test
public void testEquals_differentRect() {
mState.getOrCreateSource(ID_STATUS_BAR, statusBars())
.setFrame(new Rect(0, 0, 100, 100));
@@ -404,17 +484,6 @@ public class InsetsStateTest {
}
@Test
- public void testEquals_excludeInvisibleIme() {
- mState.getOrCreateSource(ID_IME, ime())
- .setFrame(new Rect(0, 0, 100, 100))
- .setVisible(false);
- mState2.getOrCreateSource(ID_IME, ime())
- .setFrame(new Rect(0, 0, 100, 200))
- .setVisible(false);
- assertTrue(mState2.equals(mState, true, true /* excludeInvisibleIme */));
- }
-
- @Test
public void testParcelUnparcel() {
mState.getOrCreateSource(ID_IME, ime())
.setFrame(new Rect(0, 0, 100, 100))
diff --git a/core/tests/coretests/src/android/view/ViewGroupTest.java b/core/tests/coretests/src/android/view/ViewGroupTest.java
index b37c8fd8c34e..bce3f3e8f2e1 100644
--- a/core/tests/coretests/src/android/view/ViewGroupTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupTest.java
@@ -49,11 +49,11 @@ public class ViewGroupTest {
public void testDispatchMouseEventsUnderCursor() {
final Context context = getInstrumentation().getContext();
final TestView viewGroup = new TestView(context, 0 /* left */, 0 /* top */,
- 200 /* right */, 200 /* bottom */);
+ 200 /* right */, 100 /* bottom */);
final TestView viewA = spy(new TestView(context, 0 /* left */, 0 /* top */,
- 100 /* right */, 200 /* bottom */));
+ 100 /* right */, 100 /* bottom */));
final TestView viewB = spy(new TestView(context, 100 /* left */, 0 /* top */,
- 200 /* right */, 200 /* bottom */));
+ 200 /* right */, 100 /* bottom */));
viewGroup.addView(viewA);
viewGroup.addView(viewB);
@@ -73,10 +73,10 @@ public class ViewGroupTest {
MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[2];
coords[0] = new MotionEvent.PointerCoords();
coords[0].x = 80;
- coords[0].y = 100;
+ coords[0].y = 50;
coords[1] = new MotionEvent.PointerCoords();
coords[1].x = 240;
- coords[1].y = 100;
+ coords[1].y = 50;
MotionEvent event;
// Make sure the down event is active with a pointer which coordinate is different from the
@@ -91,6 +91,10 @@ public class ViewGroupTest {
viewGroup.onResolvePointerIcon(event, 0 /* pointerIndex */);
verify(viewB).onResolvePointerIcon(event, 0);
+ event.setAction(MotionEvent.ACTION_SCROLL);
+ viewGroup.dispatchGenericMotionEvent(event);
+ verify(viewB).dispatchGenericMotionEvent(event);
+
event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
MotionEvent.ACTION_POINTER_DOWN | (1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT),
2 /* pointerCount */, properties, coords, 0 /* metaState */, 0 /* buttonState */,
@@ -102,8 +106,13 @@ public class ViewGroupTest {
viewGroup.onResolvePointerIcon(event, 1 /* pointerIndex */);
verify(viewB).onResolvePointerIcon(event, 1);
+ event.setAction(MotionEvent.ACTION_SCROLL);
+ viewGroup.dispatchGenericMotionEvent(event);
+ verify(viewB).dispatchGenericMotionEvent(event);
+
verify(viewA, never()).dispatchTouchEvent(any());
verify(viewA, never()).onResolvePointerIcon(any(), anyInt());
+ verify(viewA, never()).dispatchGenericMotionEvent(any());
}
/**
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 43683ffad432..c6a9033210e3 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -87,5 +87,6 @@
<permission name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
<permission name="android.permission.READ_SEARCH_INDEXABLES" />
<permission name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT"/>
+ <permission name="android.permission.QUERY_CLONED_APPS"/>
</privapp-permissions>
</permissions>
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 71598938f42f..603272e3df1d 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -151,6 +151,7 @@ android_library {
],
static_libs: [
"androidx.appcompat_appcompat",
+ "androidx.core_core-animation",
"androidx.arch.core_core-runtime",
"androidx-constraintlayout_constraintlayout",
"androidx.dynamicanimation_dynamicanimation",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
index 798250de89d0..26edd7d2268b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
@@ -117,6 +117,20 @@ public class FlingAnimationUtils {
* @param endValue the end value of the animator
* @param velocity the current velocity of the motion
*/
+ public void apply(androidx.core.animation.Animator animator,
+ float currValue, float endValue, float velocity) {
+ apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
+ }
+
+ /**
+ * Applies the interpolator and length to the animator, such that the fling animation is
+ * consistent with the finger motion.
+ *
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
+ */
public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
float velocity) {
apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
@@ -152,6 +166,24 @@ public class FlingAnimationUtils {
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
+ public void apply(androidx.core.animation.Animator animator,
+ float currValue, float endValue, float velocity, float maxDistance) {
+ AnimatorProperties properties = getProperties(currValue, endValue, velocity, maxDistance);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.getInterpolator());
+ }
+
+ /**
+ * Applies the interpolator and length to the animator, such that the fling animation is
+ * consistent with the finger motion.
+ *
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
+ * @param maxDistance the maximum distance for this interaction; the maximum animation length
+ * gets multiplied by the ratio between the actual distance and this value
+ */
public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
float velocity, float maxDistance) {
AnimatorProperties properties = getProperties(currValue, endValue, velocity,
@@ -367,6 +399,11 @@ public class FlingAnimationUtils {
private static class AnimatorProperties {
Interpolator mInterpolator;
long mDuration;
+
+ /** Get an AndroidX interpolator wrapper of the current mInterpolator */
+ public androidx.core.animation.Interpolator getInterpolator() {
+ return mInterpolator::getInterpolation;
+ }
}
/** Builder for {@link #FlingAnimationUtils}. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 8def8ff1ab01..99c8acdb3116 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -817,13 +817,17 @@ public class BubbleController implements ConfigurationChangeListener,
* @param interceptBack whether back should be intercepted or not.
*/
void updateWindowFlagsForBackpress(boolean interceptBack) {
- if (mStackView != null && mAddedToWindowManager) {
+ if (mAddedToWindowManager) {
mWmLayoutParams.flags = interceptBack
? 0
: WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- mWindowManager.updateViewLayout(mStackView, mWmLayoutParams);
+ if (mStackView != null) {
+ mWindowManager.updateViewLayout(mStackView, mWmLayoutParams);
+ } else if (mLayerView != null) {
+ mWindowManager.updateViewLayout(mLayerView, mWmLayoutParams);
+ }
}
}
@@ -1049,6 +1053,20 @@ public class BubbleController implements ConfigurationChangeListener,
mBubbleData.setExpanded(false /* expanded */);
}
+ /**
+ * Update expanded state when a single bubble is dragged in Launcher.
+ * Will be called only when bubble bar is expanded.
+ * @param bubbleKey key of the bubble to collapse/expand
+ * @param isBeingDragged whether the bubble is being dragged
+ */
+ public void onBubbleDrag(String bubbleKey, boolean isBeingDragged) {
+ if (mBubbleData.getSelectedBubble() != null
+ && mBubbleData.getSelectedBubble().getKey().equals(bubbleKey)) {
+ // Should collapse/expand only if equals to selected bubble.
+ mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ !isBeingDragged);
+ }
+ }
+
@VisibleForTesting
public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) {
boolean isSuppressedBubble = (mBubbleData.hasAnyBubbleWithKey(key)
@@ -1434,6 +1452,17 @@ public class BubbleController implements ConfigurationChangeListener,
}
}
+ /**
+ * Removes all the bubbles.
+ * <p>
+ * Must be called from the main thread.
+ */
+ @VisibleForTesting
+ @MainThread
+ public void removeAllBubbles(@Bubbles.DismissReason int reason) {
+ mBubbleData.dismissAll(reason);
+ }
+
private void onEntryAdded(BubbleEntry entry) {
if (canLaunchInTaskView(mContext, entry)) {
updateBubble(entry);
@@ -2095,14 +2124,25 @@ public class BubbleController implements ConfigurationChangeListener,
}
@Override
- public void removeBubble(String key, int reason) {
- // TODO (b/271466616) allow removals from launcher
+ public void removeBubble(String key) {
+ mMainExecutor.execute(
+ () -> mController.removeBubble(key, Bubbles.DISMISS_USER_GESTURE));
+ }
+
+ @Override
+ public void removeAllBubbles() {
+ mMainExecutor.execute(() -> mController.removeAllBubbles(Bubbles.DISMISS_USER_GESTURE));
}
@Override
public void collapseBubbles() {
mMainExecutor.execute(() -> mController.collapseStack());
}
+
+ @Override
+ public void onBubbleDrag(String bubbleKey, boolean isBeingDragged) {
+ mMainExecutor.execute(() -> mController.onBubbleDrag(bubbleKey, isBeingDragged));
+ }
}
private class BubblesImpl implements Bubbles {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 282db9e18d81..f58b121ae04f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -108,8 +108,10 @@ import java.util.stream.Collectors;
public class BubbleStackView extends FrameLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ // LINT.IfChange
public static final boolean ENABLE_FLING_TO_DISMISS_BUBBLE =
SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_bubble", true);
+ // LINT.ThenChange(com/android/launcher3/taskbar/bubbles/BubbleDismissController.java)
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
index 351319f5fb5e..4dda0688b790 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
@@ -31,8 +31,12 @@ interface IBubbles {
oneway void showBubble(in String key, in int bubbleBarOffsetX, in int bubbleBarOffsetY) = 3;
- oneway void removeBubble(in String key, in int reason) = 4;
+ oneway void removeBubble(in String key) = 4;
- oneway void collapseBubbles() = 5;
+ oneway void removeAllBubbles() = 5;
+
+ oneway void collapseBubbles() = 6;
+
+ oneway void onBubbleDrag(in String key, in boolean isBeingDragged) = 7;
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index b3602b30072d..689323b725ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -215,6 +215,14 @@ public class BubbleBarAnimationHelper {
mExpandedViewAlphaAnimator.reverse();
}
+ /**
+ * Cancel current animations
+ */
+ public void cancelAnimations() {
+ PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
+ mExpandedViewAlphaAnimator.cancel();
+ }
+
private void updateExpandedView() {
if (mExpandedBubble == null || mExpandedBubble.getBubbleBarExpandedView() == null) {
Log.w(TAG, "Trying to update the expanded view without a bubble");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index 8ead18b139de..bc04bfc8c18b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -150,6 +150,12 @@ public class BubbleBarLayerView extends FrameLayout
mExpandedView = null;
}
if (mExpandedView == null) {
+ if (expandedView.getParent() != null) {
+ // Expanded view might be animating collapse and is still attached
+ // Cancel current animations and remove from parent
+ mAnimationHelper.cancelAnimations();
+ removeView(expandedView);
+ }
mExpandedBubble = b;
mExpandedView = expandedView;
boolean isOverflowExpanded = b.getKey().equals(BubbleOverflow.KEY);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
index 76ca68bbfa75..517f9f2aba27 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
@@ -54,6 +54,15 @@ public class DesktopModeStatus {
public static final boolean IS_DISPLAY_CHANGE_ENABLED = SystemProperties.getBoolean(
"persist.wm.debug.desktop_change_display", false);
+
+ /**
+ * Flag to indicate that desktop stashing is enabled.
+ * When enabled, swiping home from desktop stashes the open apps. Next app that launches,
+ * will be added to the desktop.
+ */
+ private static final boolean IS_STASHING_ENABLED = SystemProperties.getBoolean(
+ "persist.wm.debug.desktop_stashing", false);
+
/**
* Return {@code true} if desktop mode support is enabled
*/
@@ -84,6 +93,13 @@ public class DesktopModeStatus {
}
/**
+ * Return {@code true} if desktop task stashing is enabled when going home.
+ * Allows users to use home screen to add tasks to desktop.
+ */
+ public static boolean isStashingEnabled() {
+ return IS_STASHING_ENABLED;
+ }
+ /**
* Check if desktop mode is active
*
* @return {@code true} if active
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 f8d7b6bc3aad..b15fd912e32d 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
@@ -150,20 +150,24 @@ class DesktopTasksController(
* back to front during the launch.
*/
fun stashDesktopApps(displayId: Int) {
- KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: stashDesktopApps")
- desktopModeTaskRepository.setStashed(displayId, true)
+ if (DesktopModeStatus.isStashingEnabled()) {
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: stashDesktopApps")
+ desktopModeTaskRepository.setStashed(displayId, true)
+ }
}
/**
* Clear the stashed state for the given display
*/
fun hideStashedDesktopApps(displayId: Int) {
- KtProtoLog.v(
- WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: hideStashedApps displayId=%d",
- displayId
- )
- desktopModeTaskRepository.setStashed(displayId, false)
+ if (DesktopModeStatus.isStashingEnabled()) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: hideStashedApps displayId=%d",
+ displayId
+ )
+ desktopModeTaskRepository.setStashed(displayId, false)
+ }
}
/** Get number of tasks that are marked as visible */
@@ -172,9 +176,13 @@ class DesktopTasksController(
}
/** Move a task with given `taskId` to desktop */
- fun moveToDesktop(taskId: Int, wct: WindowContainerTransaction = WindowContainerTransaction()) {
+ fun moveToDesktop(
+ decor: DesktopModeWindowDecoration,
+ taskId: Int,
+ wct: WindowContainerTransaction = WindowContainerTransaction()
+ ) {
shellTaskOrganizer.getRunningTaskInfo(taskId)?.let {
- task -> moveToDesktop(task, wct)
+ task -> moveToDesktop(decor, task, wct)
}
}
@@ -182,6 +190,7 @@ class DesktopTasksController(
* Move a task to desktop
*/
fun moveToDesktop(
+ decor: DesktopModeWindowDecoration,
task: RunningTaskInfo,
wct: WindowContainerTransaction = WindowContainerTransaction()
) {
@@ -195,7 +204,7 @@ class DesktopTasksController(
addMoveToDesktopChanges(wct, task)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
+ enterDesktopTaskTransitionHandler.moveToDesktop(wct, decor)
} else {
shellTaskOrganizer.applyTransaction(wct)
}
@@ -730,7 +739,7 @@ class DesktopTasksController(
*
* @param taskInfo the task being dragged.
* @param position position of surface when drag ends.
- * @param y the Y position of the motion event.
+ * @param y the Y position of the top edge of the task
* @param windowDecor the window decoration for the task being dragged
*/
fun onDragPositioningEnd(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 22929c763f27..16b23935559c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.graphics.PointF;
@@ -36,6 +37,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration;
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator;
import java.util.ArrayList;
@@ -60,6 +62,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
private MoveToDesktopAnimator mMoveToDesktopAnimator;
+ private DesktopModeWindowDecoration mDesktopModeWindowDecoration;
public EnterDesktopTaskTransitionHandler(
Transitions transitions) {
@@ -128,6 +131,18 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
onAnimationEndCallback);
}
+ /**
+ * Starts Transition of type TRANSIT_MOVE_TO_DESKTOP
+ * @param wct WindowContainerTransaction for transition
+ * @param decor {@link DesktopModeWindowDecoration} of task being animated
+ */
+ public void moveToDesktop(@NonNull WindowContainerTransaction wct,
+ DesktopModeWindowDecoration decor) {
+ mDesktopModeWindowDecoration = decor;
+ startTransition(Transitions.TRANSIT_MOVE_TO_DESKTOP, wct,
+ null /* onAnimationEndCallback */);
+ }
+
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startT,
@@ -167,136 +182,207 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
}
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (type == Transitions.TRANSIT_START_DRAG_TO_DESKTOP_MODE
+ if (type == Transitions.TRANSIT_MOVE_TO_DESKTOP
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
- // Transitioning to freeform but keeping fullscreen bounds, so the crop is set
- // to null and we don't require an animation
- final SurfaceControl sc = change.getLeash();
- startT.setWindowCrop(sc, null);
-
- if (mMoveToDesktopAnimator == null
- || mMoveToDesktopAnimator.getTaskId() != change.getTaskInfo().taskId) {
- Slog.e(TAG, "No animator available for this transition");
- return false;
- }
-
- // Calculate and set position of the task
- final PointF position = mMoveToDesktopAnimator.getPosition();
- startT.setPosition(sc, position.x, position.y);
- finishT.setPosition(sc, position.x, position.y);
-
- startT.apply();
-
- mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ return animateMoveToDesktop(change, startT, finishCallback);
+ }
- return true;
+ if (type == Transitions.TRANSIT_START_DRAG_TO_DESKTOP_MODE
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ return animateStartDragToDesktopMode(change, startT, finishT, finishCallback);
}
- Rect endBounds = change.getEndAbsBounds();
+ final Rect endBounds = change.getEndAbsBounds();
if (type == Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
&& !endBounds.isEmpty()) {
- // This Transition animates a task to freeform bounds after being dragged into freeform
- // mode and brings the remaining freeform tasks to front
- final SurfaceControl sc = change.getLeash();
- startT.setWindowCrop(sc, endBounds.width(),
- endBounds.height());
- startT.apply();
-
- // End the animation that shrinks the window when task is first dragged from fullscreen
- if (mMoveToDesktopAnimator != null) {
- mMoveToDesktopAnimator.endAnimator();
- }
-
- // We want to find the scale of the current bounds relative to the end bounds. The
- // task is currently scaled to DRAG_FREEFORM_SCALE and the final bounds will be
- // scaled to FINAL_FREEFORM_SCALE. So, it is scaled to
- // DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE relative to the freeform bounds
- final ValueAnimator animator =
- ValueAnimator.ofFloat(
- MoveToDesktopAnimator.DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE, 1f);
- animator.setDuration(FREEFORM_ANIMATION_DURATION);
- final SurfaceControl.Transaction t = mTransactionSupplier.get();
- animator.addUpdateListener(animation -> {
- final float animationValue = (float) animation.getAnimatedValue();
- t.setScale(sc, animationValue, animationValue);
-
- final float animationWidth = endBounds.width() * animationValue;
- final float animationHeight = endBounds.height() * animationValue;
- final int animationX = endBounds.centerX() - (int) (animationWidth / 2);
- final int animationY = endBounds.centerY() - (int) (animationHeight / 2);
-
- t.setPosition(sc, animationX, animationY);
- t.apply();
- });
-
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mOnAnimationFinishedCallback != null) {
- mOnAnimationFinishedCallback.accept(finishT);
- }
- mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
- }
- });
-
- animator.start();
- return true;
+ return animateFinalizeDragToDesktopMode(change, startT, finishT, finishCallback,
+ endBounds);
}
if (type == Transitions.TRANSIT_CANCEL_DRAG_TO_DESKTOP_MODE
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
- // This Transition animates a task to fullscreen after being dragged from the status
- // bar and then released back into the status bar area
- final SurfaceControl sc = change.getLeash();
- // Hide the first (fullscreen) frame because the animation will start from the smaller
- // scale size.
- startT.hide(sc)
- .setWindowCrop(sc, endBounds.width(), endBounds.height())
- .apply();
+ return animateCancelDragToDesktopMode(change, startT, finishT, finishCallback,
+ endBounds);
+ }
- if (mMoveToDesktopAnimator == null
- || mMoveToDesktopAnimator.getTaskId() != change.getTaskInfo().taskId) {
- Slog.e(TAG, "No animator available for this transition");
- return false;
+ return false;
+ }
+
+ private boolean animateMoveToDesktop(
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ if (mDesktopModeWindowDecoration == null) {
+ Slog.e(TAG, "Window Decoration is not available for this transition");
+ return false;
+ }
+
+ final SurfaceControl leash = change.getLeash();
+ final Rect startBounds = change.getStartAbsBounds();
+ startT.setPosition(leash, startBounds.left, startBounds.right)
+ .setWindowCrop(leash, startBounds.width(), startBounds.height())
+ .show(leash);
+ mDesktopModeWindowDecoration.showResizeVeil(startT, startBounds);
+
+ final ValueAnimator animator = ValueAnimator.ofObject(new RectEvaluator(),
+ change.getStartAbsBounds(), change.getEndAbsBounds());
+ animator.setDuration(FREEFORM_ANIMATION_DURATION);
+ SurfaceControl.Transaction t = mTransactionSupplier.get();
+ animator.addUpdateListener(animation -> {
+ final Rect animationValue = (Rect) animator.getAnimatedValue();
+ t.setPosition(leash, animationValue.left, animationValue.right)
+ .setWindowCrop(leash, animationValue.width(), animationValue.height())
+ .show(leash);
+ mDesktopModeWindowDecoration.updateResizeVeil(t, animationValue);
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDesktopModeWindowDecoration.hideResizeVeil();
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null, null));
}
+ });
+ animator.start();
+ return true;
+ }
- // End the animation that shrinks the window when task is first dragged from fullscreen
+ private boolean animateStartDragToDesktopMode(
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ // Transitioning to freeform but keeping fullscreen bounds, so the crop is set
+ // to null and we don't require an animation
+ final SurfaceControl sc = change.getLeash();
+ startT.setWindowCrop(sc, null);
+
+ if (mMoveToDesktopAnimator == null
+ || mMoveToDesktopAnimator.getTaskId() != change.getTaskInfo().taskId) {
+ Slog.e(TAG, "No animator available for this transition");
+ return false;
+ }
+
+ // Calculate and set position of the task
+ final PointF position = mMoveToDesktopAnimator.getPosition();
+ startT.setPosition(sc, position.x, position.y);
+ finishT.setPosition(sc, position.x, position.y);
+
+ startT.apply();
+
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null, null));
+
+ return true;
+ }
+
+ private boolean animateFinalizeDragToDesktopMode(
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback,
+ @NonNull Rect endBounds) {
+ // This Transition animates a task to freeform bounds after being dragged into freeform
+ // mode and brings the remaining freeform tasks to front
+ final SurfaceControl sc = change.getLeash();
+ startT.setWindowCrop(sc, endBounds.width(),
+ endBounds.height());
+ startT.apply();
+
+ // End the animation that shrinks the window when task is first dragged from fullscreen
+ if (mMoveToDesktopAnimator != null) {
mMoveToDesktopAnimator.endAnimator();
+ }
- final ValueAnimator animator = new ValueAnimator();
- animator.setFloatValues(MoveToDesktopAnimator.DRAG_FREEFORM_SCALE, 1f);
- animator.setDuration(FREEFORM_ANIMATION_DURATION);
- final SurfaceControl.Transaction t = mTransactionSupplier.get();
-
- // Get position of the task
- final float x = mMoveToDesktopAnimator.getPosition().x;
- final float y = mMoveToDesktopAnimator.getPosition().y;
-
- animator.addUpdateListener(animation -> {
- final float scale = (float) animation.getAnimatedValue();
- t.setPosition(sc, x * (1 - scale), y * (1 - scale))
- .setScale(sc, scale, scale)
- .show(sc)
- .apply();
- });
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mOnAnimationFinishedCallback != null) {
- mOnAnimationFinishedCallback.accept(finishT);
- }
- mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ // We want to find the scale of the current bounds relative to the end bounds. The
+ // task is currently scaled to DRAG_FREEFORM_SCALE and the final bounds will be
+ // scaled to FINAL_FREEFORM_SCALE. So, it is scaled to
+ // DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE relative to the freeform bounds
+ final ValueAnimator animator =
+ ValueAnimator.ofFloat(
+ MoveToDesktopAnimator.DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE, 1f);
+ animator.setDuration(FREEFORM_ANIMATION_DURATION);
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+ animator.addUpdateListener(animation -> {
+ final float animationValue = (float) animation.getAnimatedValue();
+ t.setScale(sc, animationValue, animationValue);
+
+ final float animationWidth = endBounds.width() * animationValue;
+ final float animationHeight = endBounds.height() * animationValue;
+ final int animationX = endBounds.centerX() - (int) (animationWidth / 2);
+ final int animationY = endBounds.centerY() - (int) (animationHeight / 2);
+
+ t.setPosition(sc, animationX, animationY);
+ t.apply();
+ });
+
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
}
- });
- animator.start();
- return true;
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null, null));
+ }
+ });
+
+ animator.start();
+ return true;
+ }
+ private boolean animateCancelDragToDesktopMode(
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback,
+ @NonNull Rect endBounds) {
+ // This Transition animates a task to fullscreen after being dragged from the status
+ // bar and then released back into the status bar area
+ final SurfaceControl sc = change.getLeash();
+ // Hide the first (fullscreen) frame because the animation will start from the smaller
+ // scale size.
+ startT.hide(sc)
+ .setWindowCrop(sc, endBounds.width(), endBounds.height())
+ .apply();
+
+ if (mMoveToDesktopAnimator == null
+ || mMoveToDesktopAnimator.getTaskId() != change.getTaskInfo().taskId) {
+ Slog.e(TAG, "No animator available for this transition");
+ return false;
}
- return false;
+ // End the animation that shrinks the window when task is first dragged from fullscreen
+ mMoveToDesktopAnimator.endAnimator();
+
+ final ValueAnimator animator = new ValueAnimator();
+ animator.setFloatValues(MoveToDesktopAnimator.DRAG_FREEFORM_SCALE, 1f);
+ animator.setDuration(FREEFORM_ANIMATION_DURATION);
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+
+ // Get position of the task
+ final float x = mMoveToDesktopAnimator.getPosition().x;
+ final float y = mMoveToDesktopAnimator.getPosition().y;
+
+ animator.addUpdateListener(animation -> {
+ final float scale = (float) animation.getAnimatedValue();
+ t.setPosition(sc, x * (1 - scale), y * (1 - scale))
+ .setScale(sc, scale, scale)
+ .show(sc)
+ .apply();
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null, null));
+ }
+ });
+ animator.start();
+ return true;
}
@Nullable
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index e45dacf1189d..e2dce88d5958 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -168,6 +168,9 @@ public class Transitions implements RemoteCallable<Transitions>,
public static final int TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE =
WindowManager.TRANSIT_FIRST_CUSTOM + 14;
+ /** Transition to animate task to desktop. */
+ public static final int TRANSIT_MOVE_TO_DESKTOP = WindowManager.TRANSIT_FIRST_CUSTOM + 15;
+
private final WindowOrganizer mOrganizer;
private final Context mContext;
private final ShellExecutor mMainExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 2d7e6a602f2f..4cc755bdf632 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -222,7 +222,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
&& (info.getType() == Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE
|| info.getType() == Transitions.TRANSIT_CANCEL_DRAG_TO_DESKTOP_MODE
|| info.getType() == Transitions.TRANSIT_EXIT_DESKTOP_MODE
- || info.getType() == Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE)) {
+ || info.getType() == Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE
+ || info.getType() == Transitions.TRANSIT_MOVE_TO_DESKTOP)) {
mWindowDecorByTaskId.get(change.getTaskInfo().taskId)
.addTransitionPausingRelayout(transition);
}
@@ -356,7 +357,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
// App sometimes draws before the insets from WindowDecoration#relayout have
// been added, so they must be added here
mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct);
- mDesktopTasksController.get().moveToDesktop(mTaskId, wct);
+ decoration.incrementRelayoutBlock();
+ mDesktopTasksController.get().moveToDesktop(decoration, mTaskId, wct);
}
decoration.closeHandleMenu();
} else if (id == R.id.fullscreen_button) {
@@ -429,10 +431,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mDragPointerId = e.getPointerId(0);
}
final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
- mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo,
- decoration.mTaskSurface, e.getRawY(dragPointerIdx)));
- mDragPositioningCallback.onDragPositioningMove(
+ final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningMove(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
+ mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo,
+ decoration.mTaskSurface, newTaskBounds.top));
mIsDragging = true;
mShouldClick = false;
return true;
@@ -458,10 +460,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
final Point position = new Point(
(int) (e.getRawX(dragPointerIdx) - e.getX(dragPointerIdx)),
(int) (e.getRawY(dragPointerIdx) - e.getY(dragPointerIdx)));
- mDragPositioningCallback.onDragPositioningEnd(
+ final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningEnd(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
mDesktopTasksController.ifPresent(c -> c.onDragPositioningEnd(taskInfo,
- position, e.getRawY(), mWindowDecorByTaskId.get(mTaskId)));
+ position, newTaskBounds.top, mWindowDecorByTaskId.get(mTaskId)));
mIsDragging = false;
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
index 941617de3aec..1669cf4a222c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.windowdecor;
import android.annotation.IntDef;
+import android.graphics.Rect;
/**
* Callback called when receiving drag-resize or drag-move related input events.
@@ -46,13 +47,15 @@ public interface DragPositioningCallback {
* Called when the pointer moves during a drag-resize or drag-move.
* @param x x coordinate in window decoration coordinate system of the new pointer location
* @param y y coordinate in window decoration coordinate system of the new pointer location
+ * @return the updated task bounds
*/
- void onDragPositioningMove(float x, float y);
+ Rect onDragPositioningMove(float x, float y);
/**
* Called when a drag-resize or drag-move stops.
* @param x x coordinate in window decoration coordinate system where the drag resize stops
* @param y y coordinate in window decoration coordinate system where the drag resize stops
+ * @return the final bounds for the dragged task
*/
- void onDragPositioningEnd(float x, float y);
+ Rect onDragPositioningEnd(float x, float y);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
index e1b6db595975..e0ee25242550 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
@@ -85,7 +85,7 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
}
@Override
- public void onDragPositioningMove(float x, float y) {
+ public Rect onDragPositioningMove(float x, float y) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint);
if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType,
@@ -106,10 +106,11 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y);
t.apply();
}
+ return new Rect(mRepositionTaskBounds);
}
@Override
- public void onDragPositioningEnd(float x, float y) {
+ public Rect onDragPositioningEnd(float x, float y) {
// If task has been resized or task was dragged into area outside of
// mDisallowedAreaForEndBounds, apply WCT to finish it.
if (isResizing() && mHasDragResized) {
@@ -136,6 +137,7 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
mRepositionStartPoint.set(0, 0);
mCtrlType = CTRL_TYPE_UNDEFINED;
mHasDragResized = false;
+ return new Rect(mRepositionTaskBounds);
}
private boolean isResizing() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index ae3b5eb6a5b5..fb05c696af82 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -105,7 +105,7 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
}
@Override
- public void onDragPositioningMove(float x, float y) {
+ public Rect onDragPositioningMove(float x, float y) {
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint);
if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType,
mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
@@ -117,10 +117,11 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y);
t.apply();
}
+ return new Rect(mRepositionTaskBounds);
}
@Override
- public void onDragPositioningEnd(float x, float y) {
+ public Rect onDragPositioningEnd(float x, float y) {
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y,
mRepositionStartPoint);
if (isResizing()) {
@@ -151,6 +152,7 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
mCtrlType = CTRL_TYPE_UNDEFINED;
mTaskBoundsAtDragStart.setEmpty();
mRepositionStartPoint.set(0, 0);
+ return new Rect(mRepositionTaskBounds);
}
private boolean isResizing() {
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 1477cf7415cf..5d87cf8b25a6 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
@@ -57,6 +57,7 @@ import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.After
@@ -92,6 +93,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Mock lateinit var mToggleResizeDesktopTaskTransitionHandler:
ToggleResizeDesktopTaskTransitionHandler
@Mock lateinit var launchAdjacentController: LaunchAdjacentController
+ @Mock lateinit var desktopModeWindowDecoration: DesktopModeWindowDecoration
private lateinit var mockitoSession: StaticMockitoSession
private lateinit var controller: DesktopTasksController
@@ -276,8 +278,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun moveToDesktop_displayFullscreen_windowingModeSetToFreeform() {
val task = setUpFullscreenTask()
task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FULLSCREEN
- controller.moveToDesktop(task)
- val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
+ controller.moveToDesktop(desktopModeWindowDecoration, task)
+ val wct = getLatestMoveToDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_FREEFORM)
}
@@ -286,15 +288,15 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun moveToDesktop_displayFreeform_windowingModeSetToUndefined() {
val task = setUpFullscreenTask()
task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FREEFORM
- controller.moveToDesktop(task)
- val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
+ controller.moveToDesktop(desktopModeWindowDecoration, task)
+ val wct = getLatestMoveToDesktopWct()
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
.isEqualTo(WINDOWING_MODE_UNDEFINED)
}
@Test
fun moveToDesktop_nonExistentTask_doesNothing() {
- controller.moveToDesktop(999)
+ controller.moveToDesktop(desktopModeWindowDecoration, 999)
verifyWCTNotExecuted()
}
@@ -305,9 +307,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val fullscreenTask = setUpFullscreenTask()
markTaskHidden(freeformTask)
- controller.moveToDesktop(fullscreenTask)
+ controller.moveToDesktop(desktopModeWindowDecoration, fullscreenTask)
- with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
+ with(getLatestMoveToDesktopWct()) {
// Operations should include home task, freeform task
assertThat(hierarchyOps).hasSize(3)
assertReorderSequence(homeTask, freeformTask, fullscreenTask)
@@ -327,9 +329,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
val freeformTaskSecond = setUpFreeformTask(displayId = SECOND_DISPLAY)
markTaskHidden(freeformTaskSecond)
- controller.moveToDesktop(fullscreenTaskDefault)
+ controller.moveToDesktop(desktopModeWindowDecoration, fullscreenTaskDefault)
- with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
+ with(getLatestMoveToDesktopWct()) {
// Check that hierarchy operations do not include tasks from second display
assertThat(hierarchyOps.map { it.container })
.doesNotContain(homeTaskSecond.token.asBinder())
@@ -498,6 +500,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Test
fun handleRequest_fullscreenTask_desktopStashed_returnWCTWithAllAppsBroughtToFront() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
val stashedFreeformTask = setUpFreeformTask(DEFAULT_DISPLAY)
markTaskHidden(stashedFreeformTask)
@@ -569,6 +572,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Test
fun handleRequest_freeformTask_desktopStashed_returnWCTWithAllAppsBroughtToFront() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
val stashedFreeformTask = setUpFreeformTask(DEFAULT_DISPLAY)
markTaskHidden(stashedFreeformTask)
@@ -626,6 +630,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Test
fun stashDesktopApps_stateUpdates() {
+ whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
+
controller.stashDesktopApps(DEFAULT_DISPLAY)
assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isTrue()
@@ -634,6 +640,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Test
fun hideStashedDesktopApps_stateUpdates() {
+ whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
+
desktopModeTaskRepository.setStashed(DEFAULT_DISPLAY, true)
desktopModeTaskRepository.setStashed(SECOND_DISPLAY, true)
controller.hideStashedDesktopApps(DEFAULT_DISPLAY)
@@ -715,6 +723,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
return arg.value
}
+ private fun getLatestMoveToDesktopWct(): WindowContainerTransaction {
+ val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ if (ENABLE_SHELL_TRANSITIONS) {
+ verify(enterDesktopTransitionHandler).moveToDesktop(arg.capture(), any())
+ } else {
+ verify(shellTaskOrganizer).applyTransaction(arg.capture())
+ }
+ return arg.value
+ }
+
private fun verifyWCTNotExecuted() {
if (ENABLE_SHELL_TRANSITIONS) {
verify(transitions, never()).startTransition(anyInt(), any(), isNull())
diff --git a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
index 5d6c343c1fbc..accaa67db1fc 100644
--- a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
@@ -25,10 +25,12 @@
<color name="settingslib_color_blue100">#d2e3fc</color>
<color name="settingslib_color_blue50">#e8f0fe</color>
<color name="settingslib_color_green600">#1e8e3e</color>
+ <color name="settingslib_color_green500">#34A853</color>
<color name="settingslib_color_green400">#5bb974</color>
<color name="settingslib_color_green100">#ceead6</color>
<color name="settingslib_color_green50">#e6f4ea</color>
<color name="settingslib_color_red600">#d93025</color>
+ <color name="settingslib_color_red500">#B3261E</color>
<color name="settingslib_color_red400">#ee675c</color>
<color name="settingslib_color_red100">#fad2cf</color>
<color name="settingslib_color_red50">#fce8e6</color>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
index 5e2c43735361..f166a18f528d 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
@@ -42,9 +42,6 @@ public class LottieColorUtils {
".grey600",
R.color.settingslib_color_grey400);
map.put(
- ".grey700",
- R.color.settingslib_color_grey500);
- map.put(
".grey800",
R.color.settingslib_color_grey300);
map.put(
@@ -62,6 +59,12 @@ public class LottieColorUtils {
map.put(
".green400",
R.color.settingslib_color_green600);
+ map.put(
+ ".green200",
+ R.color.settingslib_color_green500);
+ map.put(
+ ".red200",
+ R.color.settingslib_color_red500);
DARK_TO_LIGHT_THEME_COLOR_MAP = Collections.unmodifiableMap(map);
}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 2bac32785d41..dca9e2148237 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -200,6 +200,7 @@ android_library {
"lottie",
"LowLightDreamLib",
"motion_tool_lib",
+ "IntentResolver-core",
],
manifest: "AndroidManifest.xml",
@@ -383,6 +384,7 @@ android_library {
"motion_tool_lib",
"androidx.core_core-animation-testing-nodeps",
"androidx.compose.ui_ui",
+ "IntentResolver-core",
],
}
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 1ce347215954..b708fc27448d 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -88,7 +88,6 @@ thiruram@google.com
tracyzhou@google.com
tsuji@google.com
twickham@google.com
-vadimt@google.com
victortulias@google.com
winsonc@google.com
wleshner@google.com
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 2711dad4080b..3af7a4502856 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -56,20 +56,6 @@
]
},
{
- "name": "SystemUIGoogleScreenshotTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.Postsubmit"
- }
- ]
- },
- {
// TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
"name": "SystemUIGoogleBiometricsScreenshotTests",
"options": [
@@ -151,21 +137,5 @@
}
]
}
- ],
- "postsubmit": [
- {
- "name": "SystemUIGoogleScreenshotTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- }
- ]
- }
]
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt
new file mode 100644
index 000000000000..c94fad7246fa
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.surfaceeffects.shaders
+
+import android.graphics.RuntimeShader
+
+/** Simply renders a solid color. */
+class SolidColorShader(color: Int) : RuntimeShader(SHADER) {
+ // language=AGSL
+ private companion object {
+ private const val SHADER =
+ """
+ layout(color) uniform vec4 in_color;
+ vec4 main(vec2 p) {
+ return in_color;
+ }
+ """
+ }
+
+ init {
+ setColorUniform("in_color", color)
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt
new file mode 100644
index 000000000000..df07856e325e
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.surfaceeffects.shaders
+
+import android.graphics.Color
+import android.graphics.RuntimeShader
+import android.graphics.Shader
+import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
+
+/**
+ * Renders sparkles based on the luma matte.
+ *
+ * For example, you can pass in simplex noise as the luma matte and have a cloud looking sparkles.
+ *
+ * You may want to utilize this shader by: (Preferred) 1. Create a RuntimeShaderEffect and set the
+ * [RenderEffect] to the target [View].
+ * 2. Create a custom [View], set the shader to the [Paint] and use [Canvas.drawPaint] in [onDraw].
+ */
+class SparkleShader : RuntimeShader(SPARKLE_SHADER) {
+ // language=AGSL
+ companion object {
+ private const val UNIFORMS =
+ """
+ // Used it for RenderEffect. For example:
+ // myView.setRenderEffect(
+ // RenderEffect.createRuntimeShaderEffect(SparkleShader(), "in_src")
+ // )
+ uniform shader in_src;
+ uniform half in_time;
+ uniform half in_pixelate;
+ uniform shader in_lumaMatte;
+ layout(color) uniform vec4 in_color;
+ """
+ private const val MAIN_SHADER =
+ """vec4 main(vec2 p) {
+ half3 src = in_src.eval(p).rgb;
+ half luma = getLuminosity(in_lumaMatte.eval(p).rgb);
+ half sparkle = sparkles(p - mod(p, in_pixelate), in_time);
+ half3 mask = maskLuminosity(in_color.rgb * sparkle, luma);
+
+ return vec4(src * mask * in_color.a, in_color.a);
+ }
+ """
+ private const val SPARKLE_SHADER = UNIFORMS + ShaderUtilLibrary.SHADER_LIB + MAIN_SHADER
+
+ /** Highly recommended to use this value unless specified by design spec. */
+ const val DEFAULT_SPARKLE_PIXELATE_AMOUNT = 0.8f
+ }
+
+ init {
+ // Initializes the src and luma matte to be white.
+ setInputShader("in_src", SolidColorShader(Color.WHITE))
+ setLumaMatteColor(Color.WHITE)
+ }
+
+ /**
+ * Sets the time of the sparkle animation.
+ *
+ * This is used for animating sparkles. Note that this only makes the sparkles sparkle in place.
+ * In order to move the sparkles in x, y directions, move the luma matte input instead.
+ */
+ fun setTime(time: Float) {
+ setFloatUniform("in_time", time)
+ }
+
+ /**
+ * Sets pixelated amount of the sparkle.
+ *
+ * This value *must* be based on [resources.displayMetrics.density]. Otherwise, this will result
+ * in having different sparkle sizes on different screens.
+ *
+ * Expected to be used as follows:
+ * <pre>
+ * {@code
+ * val pixelDensity = context.resources.displayMetrics.density
+ * // Sparkles will be 0.8 of the pixel size.
+ * val sparkleShader = SparkleShader().apply { setPixelateAmount(pixelDensity * 0.8f) }
+ * }
+ * </pre>
+ */
+ fun setPixelateAmount(pixelateAmount: Float) {
+ setFloatUniform("in_pixelate", pixelateAmount)
+ }
+
+ /**
+ * Sets the luma matte for the sparkles. The luminosity determines the sparkle's visibility.
+ * Useful for setting a complex mask (e.g. simplex noise, texture, etc.)
+ */
+ fun setLumaMatte(lumaMatte: Shader) {
+ setInputShader("in_lumaMatte", lumaMatte)
+ }
+
+ /** Sets the luma matte for the sparkles. Useful for setting a solid color. */
+ fun setLumaMatteColor(color: Int) {
+ setInputShader("in_lumaMatte", SolidColorShader(color))
+ }
+
+ /** Sets the color of the sparkles. Expect to have the alpha value encoded. */
+ fun setColor(color: Int) {
+ setColorUniform("in_color", color)
+ }
+}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
index 5413f9097c5b..24064b1261b7 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
@@ -17,12 +17,10 @@
package com.android.systemui.scene.ui.composable
import com.android.systemui.scene.shared.model.Scene
-import com.android.systemui.scene.shared.model.SceneContainerNames
import dagger.Module
import dagger.multibindings.Multibinds
-import javax.inject.Named
@Module
interface SceneModule {
- @Multibinds @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) fun scenes(): Set<Scene>
+ @Multibinds fun scenes(): Set<Scene>
}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
index d3643747ad91..3e9b3975eef4 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
@@ -16,35 +16,29 @@
package com.android.systemui.scene.ui.composable
+import android.app.AlertDialog
import android.content.Context
import com.android.systemui.bouncer.ui.composable.BouncerScene
-import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
+import com.android.systemui.bouncer.ui.composable.BouncerSceneDialogFactory
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.ui.composable.LockscreenScene
-import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
import com.android.systemui.qs.ui.composable.QuickSettingsScene
-import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
import com.android.systemui.scene.shared.model.Scene
-import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.shade.ui.composable.ShadeScene
-import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
import com.android.systemui.statusbar.phone.SystemUIDialog
import dagger.Module
import dagger.Provides
-import javax.inject.Named
-import kotlinx.coroutines.CoroutineScope
@Module
object SceneModule {
@Provides
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
fun scenes(
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) bouncer: BouncerScene,
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) gone: GoneScene,
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) lockScreen: LockscreenScene,
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) qs: QuickSettingsScene,
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) shade: ShadeScene,
+ bouncer: BouncerScene,
+ gone: GoneScene,
+ lockScreen: LockscreenScene,
+ qs: QuickSettingsScene,
+ shade: ShadeScene,
): Set<Scene> {
return setOf(
bouncer,
@@ -57,70 +51,11 @@ object SceneModule {
@Provides
@SysUISingleton
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
- fun bouncerScene(
- @Application context: Context,
- viewModelFactory: BouncerViewModel.Factory,
- ): BouncerScene {
- return BouncerScene(
- viewModel =
- viewModelFactory.create(
- containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
- ),
- dialogFactory = { SystemUIDialog(context) },
- )
- }
-
- @Provides
- @SysUISingleton
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
- fun goneScene(): GoneScene {
- return GoneScene()
- }
-
- @Provides
- @SysUISingleton
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
- fun lockscreenScene(
- @Application applicationScope: CoroutineScope,
- viewModelFactory: LockscreenSceneViewModel.Factory,
- ): LockscreenScene {
- return LockscreenScene(
- applicationScope = applicationScope,
- viewModel =
- viewModelFactory.create(
- containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
- ),
- )
- }
-
- @Provides
- @SysUISingleton
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
- fun quickSettingsScene(
- viewModelFactory: QuickSettingsSceneViewModel.Factory,
- ): QuickSettingsScene {
- return QuickSettingsScene(
- viewModel =
- viewModelFactory.create(
- containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
- ),
- )
- }
-
- @Provides
- @SysUISingleton
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
- fun shadeScene(
- @Application applicationScope: CoroutineScope,
- viewModelFactory: ShadeSceneViewModel.Factory,
- ): ShadeScene {
- return ShadeScene(
- applicationScope = applicationScope,
- viewModel =
- viewModelFactory.create(
- containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
- ),
- )
+ fun bouncerSceneDialogFactory(@Application context: Context): BouncerSceneDialogFactory {
+ return object : BouncerSceneDialogFactory {
+ override fun invoke(): AlertDialog {
+ return SystemUIDialog(context)
+ }
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index d83596eeb853..6d9497dac8ea 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -52,24 +52,27 @@ import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.composable.ComposableScene
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/** The bouncer scene displays authentication challenges like PIN, password, or pattern. */
-class BouncerScene(
+@SysUISingleton
+class BouncerScene
+@Inject
+constructor(
private val viewModel: BouncerViewModel,
- private val dialogFactory: () -> AlertDialog,
+ private val dialogFactory: BouncerSceneDialogFactory,
) : ComposableScene {
override val key = SceneKey.Bouncer
- override fun destinationScenes(
- containerName: String,
- ): StateFlow<Map<UserAction, SceneModel>> =
+ override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
MutableStateFlow<Map<UserAction, SceneModel>>(
mapOf(
UserAction.Back to SceneModel(SceneKey.Lockscreen),
@@ -79,7 +82,6 @@ class BouncerScene(
@Composable
override fun Content(
- containerName: String,
modifier: Modifier,
) = BouncerScene(viewModel, dialogFactory, modifier)
}
@@ -87,7 +89,7 @@ class BouncerScene(
@Composable
private fun BouncerScene(
viewModel: BouncerViewModel,
- dialogFactory: () -> AlertDialog,
+ dialogFactory: BouncerSceneDialogFactory,
modifier: Modifier = Modifier,
) {
val message: BouncerViewModel.MessageViewModel by viewModel.message.collectAsState()
@@ -175,3 +177,7 @@ private fun BouncerScene(
}
}
}
+
+interface BouncerSceneDialogFactory {
+ operator fun invoke(): AlertDialog
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index 10652678739c..ab7bc26d59e1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -31,6 +31,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
import com.android.systemui.scene.shared.model.Direction
@@ -38,6 +39,7 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.composable.ComposableScene
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -45,15 +47,16 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** The lock screen scene shows when the device is locked. */
-class LockscreenScene(
+@SysUISingleton
+class LockscreenScene
+@Inject
+constructor(
@Application private val applicationScope: CoroutineScope,
private val viewModel: LockscreenSceneViewModel,
) : ComposableScene {
override val key = SceneKey.Lockscreen
- override fun destinationScenes(
- containerName: String,
- ): StateFlow<Map<UserAction, SceneModel>> =
+ override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
viewModel.upDestinationSceneKey
.map { pageKey -> destinationScenes(up = pageKey) }
.stateIn(
@@ -64,7 +67,6 @@ class LockscreenScene(
@Composable
override fun Content(
- containerName: String,
modifier: Modifier,
) {
LockscreenScene(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
index f88fc21addff..d84e67620177 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
@@ -20,7 +20,6 @@ import android.annotation.StringRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@@ -28,9 +27,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.LazyListScope
+import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
@@ -39,6 +38,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
@@ -134,10 +134,11 @@ private fun PeopleScreenWithConversations(
)
}
- LazyColumn(
- Modifier.fillMaxWidth().sysuiResTag("scroll_view"),
- contentPadding =
- PaddingValues(
+ Column(
+ Modifier.fillMaxWidth()
+ .sysuiResTag("scroll_view")
+ .verticalScroll(rememberScrollState())
+ .padding(
top = 16.dp,
bottom = PeopleSpacePadding,
start = 8.dp,
@@ -151,7 +152,7 @@ private fun PeopleScreenWithConversations(
if (recentTiles.isNotEmpty()) {
if (hasPriorityConversations) {
- item { Spacer(Modifier.height(35.dp)) }
+ Spacer(Modifier.height(35.dp))
}
ConversationList(R.string.recent_conversations, recentTiles, onTileClicked)
@@ -160,33 +161,30 @@ private fun PeopleScreenWithConversations(
}
}
-private fun LazyListScope.ConversationList(
+@Composable
+private fun ConversationList(
@StringRes headerTextResource: Int,
tiles: List<PeopleTileViewModel>,
onTileClicked: (PeopleTileViewModel) -> Unit
) {
- item {
- Text(
- stringResource(headerTextResource),
- Modifier.padding(start = 16.dp),
- style = MaterialTheme.typography.labelLarge,
- color = LocalAndroidColorScheme.current.deprecated.colorAccentPrimaryVariant,
- )
-
- Spacer(Modifier.height(10.dp))
- }
+ Text(
+ stringResource(headerTextResource),
+ Modifier.padding(start = 16.dp),
+ style = MaterialTheme.typography.labelLarge,
+ color = LocalAndroidColorScheme.current.deprecated.colorAccentPrimaryVariant,
+ )
+
+ Spacer(Modifier.height(10.dp))
tiles.forEachIndexed { index, tile ->
if (index > 0) {
- item {
- Divider(
- color = LocalAndroidColorScheme.current.deprecated.colorBackground,
- thickness = 2.dp,
- )
- }
+ Divider(
+ color = LocalAndroidColorScheme.current.deprecated.colorBackground,
+ thickness = 2.dp,
+ )
}
- item(tile.key.toString()) {
+ key(tile.key.toString()) {
Tile(
tile,
onTileClicked,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 30b80ca7fc1e..130395a38512 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -27,25 +27,28 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.composable.ComposableScene
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/** The Quick Settings (AKA "QS") scene shows the quick setting tiles. */
-class QuickSettingsScene(
+@SysUISingleton
+class QuickSettingsScene
+@Inject
+constructor(
private val viewModel: QuickSettingsSceneViewModel,
) : ComposableScene {
override val key = SceneKey.QuickSettings
- override fun destinationScenes(
- containerName: String,
- ): StateFlow<Map<UserAction, SceneModel>> =
+ override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
MutableStateFlow<Map<UserAction, SceneModel>>(
mapOf(
UserAction.Swipe(Direction.UP) to SceneModel(SceneKey.Shade),
@@ -55,7 +58,6 @@ class QuickSettingsScene(
@Composable
override fun Content(
- containerName: String,
modifier: Modifier,
) {
QuickSettingsScene(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt
index 6f3363e940e5..a21366695f66 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt
@@ -22,5 +22,5 @@ import com.android.systemui.scene.shared.model.Scene
/** Compose-capable extension of [Scene]. */
interface ComposableScene : Scene {
- @Composable fun Content(containerName: String, modifier: Modifier)
+ @Composable fun Content(modifier: Modifier)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index 0a4da1d6ba1e..007055221691 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -23,10 +23,12 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -35,12 +37,11 @@ import kotlinx.coroutines.flow.asStateFlow
* "Gone" is not a real scene but rather the absence of scenes when we want to skip showing any
* content from the scene framework.
*/
-class GoneScene : ComposableScene {
+@SysUISingleton
+class GoneScene @Inject constructor() : ComposableScene {
override val key = SceneKey.Gone
- override fun destinationScenes(
- containerName: String,
- ): StateFlow<Map<UserAction, SceneModel>> =
+ override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
MutableStateFlow<Map<UserAction, SceneModel>>(
mapOf(
UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade),
@@ -50,7 +51,6 @@ class GoneScene : ComposableScene {
@Composable
override fun Content(
- containerName: String,
modifier: Modifier,
) {
/*
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 32986649388d..49e2bf97b3f0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -75,7 +75,6 @@ fun SceneContainer(
if (key == currentSceneKey) {
Scene(
scene = composableScene,
- containerName = viewModel.containerName,
onSceneChanged = viewModel::setCurrentScene,
modifier = Modifier.fillMaxSize(),
)
@@ -88,12 +87,10 @@ fun SceneContainer(
@Composable
private fun Scene(
scene: ComposableScene,
- containerName: String,
onSceneChanged: (SceneModel) -> Unit,
modifier: Modifier = Modifier,
) {
- val destinationScenes: Map<UserAction, SceneModel> by
- scene.destinationScenes(containerName).collectAsState()
+ val destinationScenes: Map<UserAction, SceneModel> by scene.destinationScenes().collectAsState()
val swipeLeftDestinationScene = destinationScenes[UserAction.Swipe(Direction.LEFT)]
val swipeUpDestinationScene = destinationScenes[UserAction.Swipe(Direction.UP)]
val swipeRightDestinationScene = destinationScenes[UserAction.Swipe(Direction.RIGHT)]
@@ -107,7 +104,6 @@ private fun Scene(
modifier = Modifier.align(Alignment.Center),
) {
scene.Content(
- containerName = containerName,
modifier = Modifier,
)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 27358f53aaf2..b73e0b26f208 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -26,6 +26,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.footer.ui.compose.QuickSettings
@@ -35,6 +36,7 @@ import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -42,15 +44,16 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** The shade scene shows scrolling list of notifications and some of the quick setting tiles. */
-class ShadeScene(
+@SysUISingleton
+class ShadeScene
+@Inject
+constructor(
@Application private val applicationScope: CoroutineScope,
private val viewModel: ShadeSceneViewModel,
) : ComposableScene {
override val key = SceneKey.Shade
- override fun destinationScenes(
- containerName: String,
- ): StateFlow<Map<UserAction, SceneModel>> =
+ override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
viewModel.upDestinationSceneKey
.map { sceneKey -> destinationScenes(up = sceneKey) }
.stateIn(
@@ -61,7 +64,6 @@ class ShadeScene(
@Composable
override fun Content(
- containerName: String,
modifier: Modifier,
) = ShadeScene(viewModel, modifier)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
index d43276c00f87..46f5971405df 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
@@ -190,6 +190,10 @@ object CustomizationProviderContract {
/** Flag denoting transit clock are enabled in wallpaper picker. */
const val FLAG_NAME_PAGE_TRANSITIONS = "wallpaper_picker_page_transitions"
+ /** Flag denoting whether preview loading animation is enabled. */
+ const val FLAG_NAME_WALLPAPER_PICKER_PREVIEW_ANIMATION =
+ "wallpaper_picker_preview_animation"
+
object Columns {
/** String. Unique ID for the flag. */
const val NAME = "name"
diff --git a/packages/SystemUI/res/layout/media_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml
index e4749381243a..5404cfad25c5 100644
--- a/packages/SystemUI/res/layout/media_projection_app_selector.xml
+++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.internal.widget.ResolverDrawerLayout
+<com.android.intentresolver.widget.ResolverDrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
@@ -84,7 +84,7 @@
android:id="@*android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <com.android.internal.app.ResolverViewPager
+ <com.android.intentresolver.ResolverViewPager
android:id="@*android:id/profile_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
@@ -92,4 +92,4 @@
</LinearLayout>
</TabHost>
-</com.android.internal.widget.ResolverDrawerLayout>
+</com.android.intentresolver.widget.ResolverDrawerLayout>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 16eb21d8c4db..4d196aa5466d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -421,6 +421,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
* Refresh clock. Called in response to TIME_TICK broadcasts.
*/
void refresh() {
+ mLogBuffer.log(TAG, LogLevel.INFO, "refresh");
if (mSmartspaceController != null) {
mSmartspaceController.requestSmartspaceUpdate();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 42a4e7202c82..dc1ddc77dd6c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -1197,6 +1197,8 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
});
mPopup.show();
});
+
+ mUserSwitcherViewGroup.setAlpha(0f);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index bc24249b23c9..3b09910fbe88 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -81,7 +81,6 @@ import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
-import com.android.systemui.scene.shared.model.SceneContainerNames;
import com.android.systemui.scene.shared.model.SceneKey;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -476,7 +475,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
// When the scene framework transitions from bouncer to gone, we dismiss the keyguard.
mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow(
- mSceneInteractor.get().sceneTransitions(SceneContainerNames.SYSTEM_UI_DEFAULT),
+ mSceneInteractor.get().getTransitions(),
sceneTransitionModel -> {
if (sceneTransitionModel != null
&& sceneTransitionModel.getFrom() == SceneKey.Bouncer.INSTANCE
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index a04d13b93ddd..8e92941c79fa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -20,6 +20,7 @@ import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.animation.Animator;
import android.animation.ValueAnimator;
@@ -51,6 +52,10 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.shared.model.ScreenModel;
+import com.android.systemui.keyguard.shared.model.ScreenState;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -62,6 +67,9 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
+import kotlin.coroutines.CoroutineContext;
+import kotlin.coroutines.EmptyCoroutineContext;
+
import java.io.PrintWriter;
import javax.inject.Inject;
@@ -91,6 +99,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
private final FeatureFlags mFeatureFlags;
private final InteractionJankMonitor mInteractionJankMonitor;
private final Rect mClipBounds = new Rect();
+ private final KeyguardInteractor mKeyguardInteractor;
private Boolean mStatusViewCentered = true;
@@ -122,6 +131,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
KeyguardLogger logger,
FeatureFlags featureFlags,
InteractionJankMonitor interactionJankMonitor,
+ KeyguardInteractor keyguardInteractor,
DumpManager dumpManager) {
super(keyguardStatusView);
mKeyguardSliceViewController = keyguardSliceViewController;
@@ -134,12 +144,34 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
mInteractionJankMonitor = interactionJankMonitor;
mFeatureFlags = featureFlags;
mDumpManager = dumpManager;
+ mKeyguardInteractor = keyguardInteractor;
}
@Override
public void onInit() {
mKeyguardClockSwitchController.init();
mDumpManager.registerDumpable(this);
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ startCoroutines(EmptyCoroutineContext.INSTANCE);
+ }
+ }
+
+ void startCoroutines(CoroutineContext context) {
+ collectFlow(mView, mKeyguardInteractor.getDozeTimeTick(),
+ (Long millis) -> {
+ dozeTimeTick();
+ }, context);
+
+ collectFlow(mView, mKeyguardInteractor.getScreenModel(),
+ (ScreenModel model) -> {
+ if (model.getState() == ScreenState.SCREEN_TURNING_ON) {
+ dozeTimeTick();
+ }
+ }, context);
+ }
+
+ public KeyguardStatusView getView() {
+ return mView;
}
@Override
@@ -308,6 +340,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onTimeChanged() {
+ Slog.v(TAG, "onTimeChanged");
refreshTime();
}
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index f00615bc0fe6..7c377d2841e3 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -19,9 +19,6 @@ package com.android.systemui;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_ROW_EXPAND;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.FloatProperty;
import android.util.Log;
@@ -34,6 +31,11 @@ import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
+import androidx.annotation.NonNull;
+import androidx.core.animation.Animator;
+import androidx.core.animation.AnimatorListenerAdapter;
+import androidx.core.animation.ObjectAnimator;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -616,7 +618,7 @@ public class ExpandHelper implements Gefingerpoken {
public boolean mCancelled;
@Override
- public void onAnimationEnd(Animator animation) {
+ public void onAnimationEnd(@NonNull Animator animation) {
if (!mCancelled) {
mCallback.setUserExpandedChild(scaledView, expand);
if (!mExpanding) {
@@ -633,7 +635,7 @@ public class ExpandHelper implements Gefingerpoken {
}
@Override
- public void onAnimationCancel(Animator animation) {
+ public void onAnimationCancel(@NonNull Animator animation) {
mCancelled = true;
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
index e60d4e10f957..0c7d56f46530 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
@@ -100,6 +100,9 @@ class AuthBiometricFaceIconController(
)
} else if (newState == STATE_ERROR && oldState != STATE_ERROR) {
animateIconOnce(R.drawable.face_dialog_dark_to_error)
+ iconView.contentDescription = context.getString(
+ R.string.keyguard_face_failed
+ )
} else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
iconView.contentDescription = context.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index a1b15f4498a7..d82f458cbde2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -122,9 +122,7 @@ open class AuthBiometricFingerprintIconController(
if (shouldAnimateIconViewForTransition(lastState, newState)) {
iconView.playAnimation()
}
- if (isSideFps) {
- LottieColorUtils.applyDynamicColors(context, iconView)
- }
+ LottieColorUtils.applyDynamicColors(context, iconView)
}
override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index ebff0b05a52d..39a45f7f60a2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -26,6 +26,7 @@ import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROL
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
+import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -50,6 +51,7 @@ import android.os.Trace;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.util.Log;
+import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -234,6 +236,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
public static final VibrationEffect EFFECT_CLICK =
VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+ public static final int LONG_PRESS = HapticFeedbackConstants.LONG_PRESS;
+
private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
@Override
public void onScreenTurnedOn() {
@@ -926,12 +930,24 @@ public class UdfpsController implements DozeReceiver, Dumpable {
@VisibleForTesting
public void playStartHaptic() {
if (mAccessibilityManager.isTouchExplorationEnabled()) {
- mVibrator.vibrate(
- Process.myUid(),
- mContext.getOpPackageName(),
- EFFECT_CLICK,
- "udfps-onStart-click",
- UDFPS_VIBRATION_ATTRIBUTES);
+ if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
+ if (mOverlay != null && mOverlay.getOverlayView() != null) {
+ mVibrator.performHapticFeedback(
+ mOverlay.getOverlayView(),
+ HapticFeedbackConstants.CONTEXT_CLICK
+ );
+ } else {
+ Log.e(TAG, "No haptics played. Could not obtain overlay view to perform"
+ + "vibration. Either the controller overlay is null or has no view");
+ }
+ } else {
+ mVibrator.vibrate(
+ Process.myUid(),
+ mContext.getOpPackageName(),
+ EFFECT_CLICK,
+ "udfps-onStart-click",
+ UDFPS_VIBRATION_ATTRIBUTES);
+ }
}
}
@@ -1024,12 +1040,24 @@ public class UdfpsController implements DozeReceiver, Dumpable {
mKeyguardViewManager.showPrimaryBouncer(true);
// play the same haptic as the LockIconViewController longpress
- mVibrator.vibrate(
- Process.myUid(),
- mContext.getOpPackageName(),
- UdfpsController.EFFECT_CLICK,
- "aod-lock-icon-longpress",
- LOCK_ICON_VIBRATION_ATTRIBUTES);
+ if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
+ if (mOverlay != null && mOverlay.getOverlayView() != null) {
+ mVibrator.performHapticFeedback(
+ mOverlay.getOverlayView(),
+ UdfpsController.LONG_PRESS
+ );
+ } else {
+ Log.e(TAG, "No haptics played. Could not obtain overlay view to perform"
+ + "vibration. Either the controller overlay is null or has no view");
+ }
+ } else {
+ mVibrator.vibrate(
+ Process.myUid(),
+ mContext.getOpPackageName(),
+ UdfpsController.EFFECT_CLICK,
+ "aod-lock-icon-longpress",
+ LOCK_ICON_VIBRATION_ATTRIBUTES);
+ }
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 9bbf1ef04481..b68b92119836 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -26,6 +26,7 @@ import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.util.Log
import android.view.View
+import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO
import android.view.accessibility.AccessibilityManager
import android.widget.Button
import android.widget.TextView
@@ -335,6 +336,13 @@ object BiometricViewBinder {
// dismiss prompt when authenticated and confirmed
launch {
viewModel.isAuthenticated.collect { authState ->
+ // Disable background view for cancelling authentication once authenticated,
+ // and remove from talkback
+ if (authState.isAuthenticated) {
+ backgroundView.setOnClickListener(null)
+ backgroundView.importantForAccessibility =
+ IMPORTANT_FOR_ACCESSIBILITY_NO
+ }
if (authState.isAuthenticatedAndConfirmed) {
view.announceForAccessibility(
view.resources.getString(R.string.biometric_dialog_authenticated)
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 8e14237c0586..d8cf398b696b 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
@@ -24,6 +24,7 @@ import com.android.systemui.authentication.domain.interactor.AuthenticationInter
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.bouncer.data.repository.BouncerRepository
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -31,9 +32,7 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.util.kotlin.pairwise
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -44,8 +43,9 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
/** Encapsulates business logic and application state accessing use-cases. */
+@SysUISingleton
class BouncerInteractor
-@AssistedInject
+@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
@Application private val applicationContext: Context,
@@ -53,7 +53,6 @@ constructor(
private val authenticationInteractor: AuthenticationInteractor,
private val sceneInteractor: SceneInteractor,
featureFlags: FeatureFlags,
- @Assisted private val containerName: String,
) {
/** The user-facing message to show in the bouncer. */
@@ -118,23 +117,19 @@ constructor(
/**
* Either shows the bouncer or unlocks the device, if the bouncer doesn't need to be shown.
*
- * @param containerName The name of the scene container to show the bouncer in.
* @param message An optional message to show to the user in the bouncer.
*/
fun showOrUnlockDevice(
- containerName: String,
message: String? = null,
) {
applicationScope.launch {
if (authenticationInteractor.isAuthenticationRequired()) {
repository.setMessage(message ?: promptMessage(getAuthenticationMethod()))
sceneInteractor.setCurrentScene(
- containerName = containerName,
scene = SceneModel(SceneKey.Bouncer),
)
} else {
sceneInteractor.setCurrentScene(
- containerName = containerName,
scene = SceneModel(SceneKey.Gone),
)
}
@@ -180,7 +175,6 @@ constructor(
if (isAuthenticated) {
sceneInteractor.setCurrentScene(
- containerName = containerName,
scene = SceneModel(SceneKey.Gone),
)
} else {
@@ -228,11 +222,4 @@ constructor(
else -> ""
}
}
-
- @AssistedFactory
- interface Factory {
- fun create(
- containerName: String,
- ): BouncerInteractor
- }
}
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 34e934bec003..d9ec5d0d1744 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
@@ -120,6 +120,8 @@ object KeyguardBouncerViewBinder {
viewModel.isShowing.collect { isShowing ->
view.visibility = if (isShowing) View.VISIBLE else View.INVISIBLE
if (isShowing) {
+ // Reset security container because these views are not reinflated.
+ securityContainerController.reset()
securityContainerController.reinflateViewFlipper {
// Reset Security Container entirely.
securityContainerController.onBouncerVisibilityChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index a4ef5cec6525..68e1a29bc609 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -22,13 +22,12 @@ import android.content.Context
import com.android.systemui.R
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.util.kotlin.pairwise
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
import kotlin.math.ceil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -45,17 +44,15 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
/** Holds UI state and handles user input on bouncer UIs. */
+@SysUISingleton
class BouncerViewModel
-@AssistedInject
+@Inject
constructor(
@Application private val applicationContext: Context,
@Application private val applicationScope: CoroutineScope,
- interactorFactory: BouncerInteractor.Factory,
+ private val interactor: BouncerInteractor,
featureFlags: FeatureFlags,
- @Assisted containerName: String,
) {
- private val interactor: BouncerInteractor = interactorFactory.create(containerName)
-
private val isInputEnabled: StateFlow<Boolean> =
interactor.isThrottled
.map { !it }
@@ -222,11 +219,4 @@ constructor(
*/
val isUpdateAnimated: Boolean,
)
-
- @AssistedFactory
- interface Factory {
- fun create(
- containerName: String,
- ): BouncerViewModel
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index b387e4a66bd2..4c9dbe02fad8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -40,8 +40,6 @@ import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.controls.ui.ControlsActivity
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.settings.UserTracker
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -50,7 +48,6 @@ import javax.inject.Inject
* Activity for rearranging and removing controls for a given structure
*/
open class ControlsEditingActivity @Inject constructor(
- featureFlags: FeatureFlags,
@Main private val mainExecutor: Executor,
private val controller: ControlsControllerImpl,
private val userTracker: UserTracker,
@@ -76,8 +73,6 @@ open class ControlsEditingActivity @Inject constructor(
private var isFromFavoriting: Boolean = false
- private val isNewFlowEnabled: Boolean =
- featureFlags.isEnabled(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS)
private val userTrackerCallback: UserTracker.Callback = object : UserTracker.Callback {
private val startingUser = controller.currentUserId
@@ -176,7 +171,7 @@ open class ControlsEditingActivity @Inject constructor(
private fun bindButtons() {
addControls = requireViewById<Button>(R.id.addControls).apply {
isEnabled = true
- visibility = if (isNewFlowEnabled) View.VISIBLE else View.GONE
+ visibility = View.VISIBLE
setOnClickListener {
if (saveButton.isEnabled) {
// The user has made changes
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 59fa7f53fc17..23721c93508b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -33,7 +33,6 @@ import android.view.ViewStub
import android.widget.Button
import android.widget.FrameLayout
import android.widget.TextView
-import android.widget.Toast
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
import androidx.activity.ComponentActivity
@@ -41,24 +40,19 @@ import androidx.annotation.VisibleForTesting
import androidx.viewpager2.widget.ViewPager2
import com.android.systemui.Prefs
import com.android.systemui.R
-import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.TooltipManager
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.controls.ui.ControlsActivity
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.settings.UserTracker
import java.text.Collator
import java.util.concurrent.Executor
import javax.inject.Inject
open class ControlsFavoritingActivity @Inject constructor(
- featureFlags: FeatureFlags,
@Main private val executor: Executor,
private val controller: ControlsControllerImpl,
- private val listingController: ControlsListingController,
private val userTracker: UserTracker,
) : ComponentActivity() {
@@ -92,7 +86,6 @@ open class ControlsFavoritingActivity @Inject constructor(
private lateinit var pageIndicator: ManagementPageIndicator
private var mTooltipManager: TooltipManager? = null
private lateinit var doneButton: View
- private lateinit var otherAppsButton: View
private lateinit var rearrangeButton: Button
private var listOfStructures = emptyList<StructureContainer>()
@@ -104,8 +97,6 @@ open class ControlsFavoritingActivity @Inject constructor(
get() = openSource == EXTRA_SOURCE_VALUE_FROM_PROVIDER_SELECTOR
private val fromEditing: Boolean
get() = openSource == EXTRA_SOURCE_VALUE_FROM_EDITING
- private val isNewFlowEnabled: Boolean =
- featureFlags.isEnabled(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS)
private val userTrackerCallback: UserTracker.Callback = object : UserTracker.Callback {
private val startingUser = controller.currentUserId
@@ -124,20 +115,6 @@ open class ControlsFavoritingActivity @Inject constructor(
onBackPressed()
}
- private val listingCallback = object : ControlsListingController.ControlsListingCallback {
-
- override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
- if (serviceInfos.size > 1) {
- val newVisibility = if (isNewFlowEnabled) View.GONE else View.VISIBLE
- if (otherAppsButton.visibility != newVisibility) {
- otherAppsButton.post {
- otherAppsButton.visibility = newVisibility
- }
- }
- }
- }
- }
-
override fun onBackPressed() {
if (fromEditing) {
animateExitAndFinish()
@@ -342,7 +319,7 @@ open class ControlsFavoritingActivity @Inject constructor(
getString(R.string.controls_favorite_rearrange_button)
}
isEnabled = false
- visibility = if (isNewFlowEnabled) View.VISIBLE else View.GONE
+ visibility = View.VISIBLE
setOnClickListener {
if (component == null) return@setOnClickListener
saveFavorites()
@@ -361,24 +338,6 @@ open class ControlsFavoritingActivity @Inject constructor(
)
}
}
- otherAppsButton = requireViewById<Button>(R.id.other_apps).apply {
- setOnClickListener {
- if (doneButton.isEnabled) {
- // The user has made changes
- Toast.makeText(
- applicationContext,
- R.string.controls_favorite_toast_no_changes,
- Toast.LENGTH_SHORT
- ).show()
- }
- startActivity(
- Intent(context, ControlsProviderSelectorActivity::class.java),
- ActivityOptions
- .makeSceneTransitionAnimation(this@ControlsFavoritingActivity).toBundle()
- )
- animateExitAndFinish()
- }
- }
doneButton = requireViewById<Button>(R.id.done).apply {
isEnabled = false
@@ -415,7 +374,6 @@ open class ControlsFavoritingActivity @Inject constructor(
override fun onStart() {
super.onStart()
- listingController.addCallback(listingCallback)
userTracker.addCallback(userTrackerCallback, executor)
if (DEBUG) {
@@ -440,7 +398,6 @@ open class ControlsFavoritingActivity @Inject constructor(
override fun onStop() {
super.onStop()
- listingController.removeCallback(listingCallback)
userTracker.removeCallback(userTrackerCallback)
if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 1eba66765ce3..83bec664876d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -124,8 +124,7 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
}
private fun updateServices(newServices: List<ControlsServiceInfo>) {
- if (featureFlags.isEnabled(Flags.USE_APP_PANELS) &&
- activityTaskManagerProxy.supportsMultiWindow(context)) {
+ if (activityTaskManagerProxy.supportsMultiWindow(context)) {
val allowAllApps = featureFlags.isEnabled(Flags.APP_PANELS_ALL_APPS_ALLOWED)
newServices.forEach {
it.resolvePanelActivity(allowAllApps) }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 37138114c740..a7e9efd8ab03 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -34,12 +34,9 @@ import android.view.HapticFeedbackConstants
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.controls.ControlsMetricsLogger
-import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.controls.settings.ControlsSettingsRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -60,8 +57,6 @@ class ControlActionCoordinatorImpl @Inject constructor(
private val controlsMetricsLogger: ControlsMetricsLogger,
private val vibrator: VibratorHelper,
private val controlsSettingsRepository: ControlsSettingsRepository,
- private val controlsSettingsDialogManager: ControlsSettingsDialogManager,
- private val featureFlags: FeatureFlags,
) : ControlActionCoordinator {
private var dialog: Dialog? = null
private var pendingAction: Action? = null
@@ -77,9 +72,6 @@ class ControlActionCoordinatorImpl @Inject constructor(
}
override fun closeDialogs() {
- if (!featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
- controlsSettingsDialogManager.closeDialog()
- }
val isActivityFinishing =
(activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed }
if (isActivityFinishing == true) {
@@ -169,7 +161,6 @@ class ControlActionCoordinatorImpl @Inject constructor(
override fun runPendingAction(controlId: String) {
if (isLocked) return
if (pendingAction?.controlId == controlId) {
- showSettingsDialogIfNeeded(pendingAction!!)
pendingAction?.invoke()
pendingAction = null
}
@@ -208,7 +199,6 @@ class ControlActionCoordinatorImpl @Inject constructor(
true
}, { pendingAction = null }, true /* afterKeyguardGone */)
} else {
- showSettingsDialogIfNeeded(action)
action.invoke()
}
}
@@ -243,15 +233,6 @@ class ControlActionCoordinatorImpl @Inject constructor(
}
}
- private fun showSettingsDialogIfNeeded(action: Action) {
- if (action.authIsRequired) {
- return
- }
- if (!featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
- controlsSettingsDialogManager.maybeShowDialog(activityContext) {}
- }
- }
-
@VisibleForTesting
fun createAction(
controlId: String,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index 557dcf4accc7..8341964e1533 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -36,7 +36,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.management.ControlsAnimations
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
@@ -66,9 +65,7 @@ open class ControlsActivity @Inject constructor(
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lastConfiguration.setTo(resources.configuration)
- if (featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
- window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
- }
+ window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
setContentView(R.layout.controls_fullscreen)
@@ -77,7 +74,7 @@ open class ControlsActivity @Inject constructor(
requireViewById(R.id.control_detail_root),
window,
intent,
- !featureFlags.isEnabled(Flags.USE_APP_PANELS)
+ false
)
)
@@ -114,7 +111,7 @@ open class ControlsActivity @Inject constructor(
parent = requireViewById(R.id.control_detail_root)
parent.alpha = 0f
- if (featureFlags.isEnabled(Flags.USE_APP_PANELS) && !keyguardStateController.isUnlocked) {
+ if (!keyguardStateController.isUnlocked) {
controlsSettingsDialogManager.maybeShowDialog(this) {
uiController.show(parent, { finishOrReturnToDream() }, this)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 56c898d1e9b4..89204eb90857 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -506,30 +506,22 @@ class ControlsUiControllerImpl @Inject constructor (
val isPanel = selectedItem is SelectedItem.PanelItem
val selectedStructure = (selectedItem as? SelectedItem.StructureItem)?.structure
?: EMPTY_STRUCTURE
- val newFlows = featureFlags.isEnabled(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS)
val items = buildList {
add(OverflowMenuAdapter.MenuItem(
context.getText(R.string.controls_open_app),
OPEN_APP_ID
))
- if (newFlows || isPanel) {
- if (extraApps) {
- add(OverflowMenuAdapter.MenuItem(
- context.getText(R.string.controls_menu_add_another_app),
- ADD_APP_ID
- ))
- }
- if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) {
- add(OverflowMenuAdapter.MenuItem(
- context.getText(R.string.controls_menu_remove),
- REMOVE_APP_ID,
- ))
- }
- } else {
+ if (extraApps) {
+ add(OverflowMenuAdapter.MenuItem(
+ context.getText(R.string.controls_menu_add_another_app),
+ ADD_APP_ID
+ ))
+ }
+ if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) {
add(OverflowMenuAdapter.MenuItem(
- context.getText(R.string.controls_menu_add),
- ADD_CONTROLS_ID
+ context.getText(R.string.controls_menu_remove),
+ REMOVE_APP_ID,
))
}
if (!isPanel) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 553405f2c944..5577cbcb0dd7 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -17,6 +17,7 @@
package com.android.systemui.dreams;
import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_WINDOW_TITLE;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_TOUCH_INSET_MANAGER;
import android.content.ComponentName;
import android.content.Context;
@@ -161,7 +162,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
DreamOverlayStateController stateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
UiEventLogger uiEventLogger,
- TouchInsetManager touchInsetManager,
+ @Named(DREAM_TOUCH_INSET_MANAGER) TouchInsetManager touchInsetManager,
@Nullable @Named(LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT)
ComponentName lowLightDreamComponent,
DreamOverlayCallbackController dreamOverlayCallbackController,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index c61b47758ab7..4bafe325cda0 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -31,11 +31,13 @@ import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
import com.android.systemui.dreams.DreamOverlayService;
import com.android.systemui.dreams.complication.dagger.ComplicationComponent;
import com.android.systemui.dreams.touch.scrim.dagger.ScrimModule;
+import com.android.systemui.touch.TouchInsetManager;
import dagger.Module;
import dagger.Provides;
import java.util.Optional;
+import java.util.concurrent.Executor;
import javax.inject.Named;
@@ -55,7 +57,7 @@ public interface DreamModule {
String DREAM_ONLY_ENABLED_FOR_DOCK_USER = "dream_only_enabled_for_dock_user";
String DREAM_OVERLAY_SERVICE_COMPONENT = "dream_overlay_service_component";
String DREAM_OVERLAY_ENABLED = "dream_overlay_enabled";
-
+ String DREAM_TOUCH_INSET_MANAGER = "dream_touch_inset_manager";
String DREAM_SUPPORTED = "dream_supported";
String DREAM_OVERLAY_WINDOW_TITLE = "dream_overlay_window_title";
@@ -69,6 +71,15 @@ public interface DreamModule {
}
/**
+ * Provides a touch inset manager for dreams.
+ */
+ @Provides
+ @Named(DREAM_TOUCH_INSET_MANAGER)
+ static TouchInsetManager providesTouchInsetManager(@Main Executor executor) {
+ return new TouchInsetManager(executor);
+ }
+
+ /**
* Provides whether dream overlay is enabled.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b04d9705f857..775992be5a55 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -62,11 +62,12 @@ object Flags {
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply")
/**
- * This flag is server-controlled and should stay as [unreleasedFlag] since we never want to
- * enable it on release builds.
+ * This flag controls whether we register a listener for StatsD notification memory reports.
+ * For statsd to actually call the listener however, a server-side toggle needs to be
+ * enabled as well.
*/
val NOTIFICATION_MEMORY_LOGGING_ENABLED =
- unreleasedFlag(119, "notification_memory_logging_enabled")
+ releasedFlag(119, "notification_memory_logging_enabled")
// TODO(b/260335638): Tracking Bug
@JvmField
@@ -239,7 +240,7 @@ object Flags {
/** Whether to delay showing bouncer UI when face auth or active unlock are enrolled. */
// TODO(b/279794160): Tracking bug.
- @JvmField val DELAY_BOUNCER = unreleasedFlag(235, "delay_bouncer", teamfood = true)
+ @JvmField val DELAY_BOUNCER = releasedFlag(235, "delay_bouncer")
/** Keyguard Migration */
@@ -282,6 +283,15 @@ object Flags {
// TODO(b/291767565): Tracking bug.
@JvmField val MIGRATE_KEYGUARD_STATUS_VIEW = unreleasedFlag(243, "migrate_keyguard_status_view")
+ /** Enables preview loading animation in the wallpaper picker. */
+ // TODO(b/274443705): Tracking Bug
+ @JvmField
+ val WALLPAPER_PICKER_PREVIEW_ANIMATION =
+ unreleasedFlag(
+ 244,
+ "wallpaper_picker_preview_animation"
+ )
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -616,13 +626,8 @@ object Flags {
@JvmField val NOTE_TASKS = releasedFlag(1900, "keycode_flag")
// 2000 - device controls
- @Keep @JvmField val USE_APP_PANELS = releasedFlag(2000, "use_app_panels")
-
@JvmField val APP_PANELS_ALL_APPS_ALLOWED = releasedFlag(2001, "app_panels_all_apps_allowed")
- @JvmField
- val CONTROLS_MANAGEMENT_NEW_FLOWS = releasedFlag(2002, "controls_management_new_flows")
-
// Enables removing app from Home control panel as a part of a new flow
// TODO(b/269132640): Tracking Bug
@JvmField
@@ -734,4 +739,12 @@ object Flags {
// TODO(b/290213663): Tracking Bug
@JvmField
val ONE_WAY_HAPTICS_API_MIGRATION = unreleasedFlag(3100, "oneway_haptics_api_migration")
+
+ /** Enable the Compose implementation of the PeopleSpaceActivity. */
+ @JvmField
+ val COMPOSE_PEOPLE_SPACE = unreleasedFlag(293570761, "compose_people_space")
+
+ /** Enable the Compose implementation of the Quick Settings footer actions. */
+ @JvmField
+ val COMPOSE_QS_FOOTER_ACTIONS = unreleasedFlag(293569320, "compose_qs_footer_actions")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 5d7ea1cc5819..e2929aec0295 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -100,6 +100,7 @@ import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -173,6 +174,8 @@ import com.android.wm.shell.keyguard.KeyguardTransitions;
import dagger.Lazy;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
@@ -257,6 +260,22 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private static final int SYSTEM_READY = 18;
private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
+ /** Enum for reasons behind updating wakeAndUnlock state. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ value = {
+ WakeAndUnlockUpdateReason.HIDE,
+ WakeAndUnlockUpdateReason.SHOW,
+ WakeAndUnlockUpdateReason.FULFILL,
+ WakeAndUnlockUpdateReason.WAKE_AND_UNLOCK,
+ })
+ @interface WakeAndUnlockUpdateReason {
+ int HIDE = 0;
+ int SHOW = 1;
+ int FULFILL = 2;
+ int WAKE_AND_UNLOCK = 3;
+ }
+
/**
* The default amount of time we stay awake (used for all key input)
*/
@@ -808,7 +827,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// dreaming. It's time to wake up.
if (mUnlockingAndWakingFromDream) {
Log.d(TAG, "waking from dream after unlock");
- mUnlockingAndWakingFromDream = false;
+ setUnlockAndWakeFromDream(false, WakeAndUnlockUpdateReason.FULFILL);
if (mKeyguardStateController.isShowing()) {
Log.d(TAG, "keyguard showing after keyguardGone, dismiss");
@@ -2685,7 +2704,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mKeyguardExitAnimationRunner = null;
mWakeAndUnlocking = false;
- mUnlockingAndWakingFromDream = false;
+ setUnlockAndWakeFromDream(false, WakeAndUnlockUpdateReason.SHOW);
setPendingLock(false);
// Force if we we're showing in the middle of hiding, to ensure we end up in the correct
@@ -2791,6 +2810,51 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
tryKeyguardDone();
};
+ private void setUnlockAndWakeFromDream(boolean updatedValue,
+ @WakeAndUnlockUpdateReason int reason) {
+ if (updatedValue == mUnlockingAndWakingFromDream) {
+ return;
+ }
+
+ final String reasonDescription;
+
+ switch(reason) {
+ case WakeAndUnlockUpdateReason.FULFILL:
+ reasonDescription = "fulfilling existing request";
+ break;
+ case WakeAndUnlockUpdateReason.HIDE:
+ reasonDescription = "hiding keyguard";
+ break;
+ case WakeAndUnlockUpdateReason.SHOW:
+ reasonDescription = "showing keyguard";
+ break;
+ case WakeAndUnlockUpdateReason.WAKE_AND_UNLOCK:
+ reasonDescription = "waking to unlock";
+ break;
+ default:
+ throw new IllegalStateException("Unexpected value: " + reason);
+ }
+
+ final boolean unsetUnfulfilled = !updatedValue
+ && reason != WakeAndUnlockUpdateReason.FULFILL;
+
+ mUnlockingAndWakingFromDream = updatedValue;
+
+ final String description;
+
+ if (unsetUnfulfilled) {
+ description = "Interrupting request to wake and unlock";
+ } else if (mUnlockingAndWakingFromDream) {
+ description = "Initiating request to wake and unlock";
+ } else {
+ description = "Fulfilling request to wake and unlock";
+ }
+
+ Log.d(TAG, String.format(
+ "Updating waking and unlocking request to %b. description:[%s]. reason:[%s]",
+ mUnlockingAndWakingFromDream, description, reasonDescription));
+ }
+
/**
* Handle message sent by {@link #hideLocked()}
* @see #HIDE
@@ -2810,8 +2874,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mHiding = true;
- mUnlockingAndWakingFromDream = mStatusBarStateController.isDreaming()
- && !mStatusBarStateController.isDozing();
+ // If waking and unlocking, waking from dream has been set properly.
+ if (!mWakeAndUnlocking) {
+ setUnlockAndWakeFromDream(mStatusBarStateController.isDreaming()
+ && mPM.isInteractive(), WakeAndUnlockUpdateReason.HIDE);
+ }
if ((mShowing && !mOccluded) || mUnlockingAndWakingFromDream) {
if (mUnlockingAndWakingFromDream) {
@@ -3218,7 +3285,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
flags |= StatusBarManager.DISABLE_RECENT;
}
- if (mPowerGestureIntercepted && mOccluded && isSecure()) {
+ if (mPowerGestureIntercepted && mOccluded && isSecure()
+ && mUpdateMonitor.isFaceEnrolled()) {
flags |= StatusBarManager.DISABLE_RECENT;
}
@@ -3313,9 +3381,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
}
- public void onWakeAndUnlocking() {
+ /**
+ * Informs the keyguard view mediator that the device is waking and unlocking.
+ * @param fromDream Whether waking and unlocking is happening over an interactive dream.
+ */
+ public void onWakeAndUnlocking(boolean fromDream) {
Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
mWakeAndUnlocking = true;
+ setUnlockAndWakeFromDream(fromDream, WakeAndUnlockUpdateReason.WAKE_AND_UNLOCK);
mKeyguardViewControllerLazy.get().notifyKeyguardAuthenticated(/* primaryAuth */ false);
userActivity();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 6fd3e21b25a4..30f8f3edfa8f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -110,6 +110,18 @@ interface DeviceEntryFaceAuthRepository {
fun lockoutFaceAuth()
/**
+ * Cancel current face authentication and prevent it from running until [resumeFaceAuth] is
+ * invoked.
+ */
+ fun pauseFaceAuth()
+
+ /**
+ * Allow face auth paused using [pauseFaceAuth] to run again. The next invocation to
+ * [authenticate] will run as long as other gating conditions don't stop it from running.
+ */
+ fun resumeFaceAuth()
+
+ /**
* Trigger face authentication.
*
* [uiEvent] provided should be logged whenever face authentication runs. Invocation should be
@@ -186,6 +198,15 @@ constructor(
override val isAuthRunning: StateFlow<Boolean>
get() = _isAuthRunning
+ private val faceAuthPaused = MutableStateFlow(false)
+ override fun pauseFaceAuth() {
+ faceAuthPaused.value = true
+ }
+
+ override fun resumeFaceAuth() {
+ faceAuthPaused.value = false
+ }
+
private val keyguardSessionId: InstanceId?
get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD)
@@ -329,11 +350,7 @@ constructor(
"isFaceAuthenticationEnabled",
tableLogBuffer
),
- logAndObserve(
- userRepository.userSwitchingInProgress.isFalse(),
- "userSwitchingNotInProgress",
- tableLogBuffer
- ),
+ logAndObserve(faceAuthPaused.isFalse(), "faceAuthIsNotPaused", tableLogBuffer),
logAndObserve(
keyguardRepository.isKeyguardGoingAway.isFalse(),
"keyguardNotGoingAway",
@@ -454,7 +471,6 @@ constructor(
}
private fun handleFaceCancellationError() {
- cancelNotReceivedHandlerJob?.cancel()
applicationScope.launch {
faceAuthRequestedWhileCancellation?.let {
faceAuthLogger.launchingQueuedFaceAuthRequest(it)
@@ -483,6 +499,7 @@ constructor(
}
private fun onFaceAuthRequestCompleted() {
+ cancelNotReceivedHandlerJob?.cancel()
cancellationInProgress = false
_isAuthRunning.value = false
authCancellationSignal = null
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 9ee990243b96..f1b344199516 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -47,16 +47,15 @@ import com.android.systemui.statusbar.phone.BiometricUnlockController.WakeAndUnl
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
@@ -177,7 +176,7 @@ interface KeyguardRepository {
val keyguardRootViewVisibility: Flow<KeyguardRootViewVisibilityState>
/** Receive an event for doze time tick */
- val dozeTimeTick: Flow<Unit>
+ val dozeTimeTick: Flow<Long>
/**
* Returns `true` if the keyguard is showing; `false` otherwise.
@@ -248,6 +247,7 @@ constructor(
private val dreamOverlayCallbackController: DreamOverlayCallbackController,
@Main private val mainDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
+ private val systemClock: SystemClock,
) : KeyguardRepository {
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
@@ -398,11 +398,11 @@ constructor(
_isDozing.value = isDozing
}
- private val _dozeTimeTick = MutableSharedFlow<Unit>()
- override val dozeTimeTick = _dozeTimeTick.asSharedFlow()
+ private val _dozeTimeTick = MutableStateFlow<Long>(0)
+ override val dozeTimeTick = _dozeTimeTick.asStateFlow()
override fun dozeTimeTick() {
- _dozeTimeTick.tryEmit(Unit)
+ _dozeTimeTick.value = systemClock.uptimeMillis()
}
private val _lastDozeTapToWakePosition = MutableStateFlow<Point?>(null)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
index 5ef9a9e0482c..e4e6a6dae6b0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
@@ -56,6 +56,9 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA
get() = emptyFlow()
override fun lockoutFaceAuth() = Unit
+ override fun pauseFaceAuth() = Unit
+
+ override fun resumeFaceAuth() = Unit
/**
* Trigger face authentication.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
index 252982fd019f..ac936b10fe43 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
@@ -24,14 +24,11 @@ import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.doze.util.BurnInHelperWrapper
-import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
@@ -46,24 +43,17 @@ constructor(
private val burnInHelperWrapper: BurnInHelperWrapper,
@Application private val scope: CoroutineScope,
private val configurationRepository: ConfigurationRepository,
- private val systemClock: SystemClock,
+ private val keyguardInteractor: KeyguardInteractor,
) {
- private val _dozeTimeTick = MutableStateFlow<Long>(0)
- val dozeTimeTick: StateFlow<Long> = _dozeTimeTick.asStateFlow()
-
val udfpsBurnInXOffset: StateFlow<Int> =
burnInOffsetDefinedInPixels(R.dimen.udfps_burn_in_offset_x, isXAxis = true)
val udfpsBurnInYOffset: StateFlow<Int> =
burnInOffsetDefinedInPixels(R.dimen.udfps_burn_in_offset_y, isXAxis = false)
val udfpsBurnInProgress: StateFlow<Float> =
- dozeTimeTick
+ keyguardInteractor.dozeTimeTick
.mapLatest { burnInHelperWrapper.burnInProgressOffset() }
.stateIn(scope, SharingStarted.Lazily, burnInHelperWrapper.burnInProgressOffset())
- fun dozeTimeTick() {
- _dozeTimeTick.value = systemClock.uptimeMillis()
- }
-
/**
* Use for max burn-in offsets that are NOT specified in pixels. This flow will recalculate the
* max burn-in offset on any configuration changes. If the max burn-in offset is specified in
@@ -77,7 +67,9 @@ constructor(
.flatMapLatest {
val maxBurnInOffsetPixels =
context.resources.getDimensionPixelSize(maxBurnInOffsetResourceId)
- dozeTimeTick.mapLatest { calculateOffset(maxBurnInOffsetPixels, isXAxis) }
+ keyguardInteractor.dozeTimeTick.mapLatest {
+ calculateOffset(maxBurnInOffsetPixels, isXAxis)
+ }
}
.stateIn(
scope,
@@ -102,7 +94,9 @@ constructor(
.flatMapLatest { scale ->
val maxBurnInOffsetPixels =
context.resources.getDimensionPixelSize(maxBurnInOffsetResourceId)
- dozeTimeTick.mapLatest { calculateOffset(maxBurnInOffsetPixels, isXAxis, scale) }
+ keyguardInteractor.dozeTimeTick.mapLatest {
+ calculateOffset(maxBurnInOffsetPixels, isXAxis, scale)
+ }
}
.stateIn(
scope,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt
new file mode 100644
index 000000000000..dac6ef5e6082
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.animation.ValueAnimator
+import com.android.app.animation.Interpolators
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.util.kotlin.Utils.Companion.toTriple
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class FromDreamingLockscreenHostedTransitionInteractor
+@Inject
+constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
+ @Application private val scope: CoroutineScope,
+ private val keyguardInteractor: KeyguardInteractor,
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ ) {
+
+ override fun start() {
+ listenForDreamingLockscreenHostedToLockscreen()
+ listenForDreamingLockscreenHostedToGone()
+ listenForDreamingLockscreenHostedToDozing()
+ listenForDreamingLockscreenHostedToOccluded()
+ listenForDreamingLockscreenHostedToPrimaryBouncer()
+ }
+
+ private fun listenForDreamingLockscreenHostedToLockscreen() {
+ scope.launch {
+ keyguardInteractor.isActiveDreamLockscreenHosted
+ // Add a slight delay to prevent transitioning to lockscreen from happening too soon
+ // as dozing can arrive in a slight gap after the lockscreen hosted dream stops.
+ .onEach { delay(50) }
+ .sample(
+ combine(
+ keyguardInteractor.dozeTransitionModel,
+ transitionInteractor.startedKeyguardTransitionStep,
+ ::Pair
+ ),
+ ::toTriple
+ )
+ .collect {
+ (isActiveDreamLockscreenHosted, dozeTransitionModel, lastStartedTransition) ->
+ if (
+ !isActiveDreamLockscreenHosted &&
+ DozeStateModel.isDozeOff(dozeTransitionModel.to) &&
+ lastStartedTransition.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+ ) {
+ startTransitionTo(KeyguardState.LOCKSCREEN)
+ }
+ }
+ }
+ }
+
+ private fun listenForDreamingLockscreenHostedToOccluded() {
+ scope.launch {
+ keyguardInteractor.isActiveDreamLockscreenHosted
+ .sample(
+ combine(
+ keyguardInteractor.isKeyguardOccluded,
+ transitionInteractor.startedKeyguardTransitionStep,
+ ::Pair,
+ ),
+ ::toTriple
+ )
+ .collect { (isActiveDreamLockscreenHosted, isOccluded, lastStartedTransition) ->
+ if (
+ isOccluded &&
+ !isActiveDreamLockscreenHosted &&
+ lastStartedTransition.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+ ) {
+ startTransitionTo(KeyguardState.OCCLUDED)
+ }
+ }
+ }
+ }
+
+ private fun listenForDreamingLockscreenHostedToPrimaryBouncer() {
+ scope.launch {
+ keyguardInteractor.primaryBouncerShowing
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (isBouncerShowing, lastStartedTransitionStep) ->
+ if (
+ isBouncerShowing &&
+ lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+ ) {
+ startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
+ }
+ }
+ }
+ }
+
+ private fun listenForDreamingLockscreenHostedToGone() {
+ scope.launch {
+ keyguardInteractor.biometricUnlockState
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (biometricUnlockState, lastStartedTransitionStep) ->
+ if (
+ lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED &&
+ biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM
+ ) {
+ startTransitionTo(KeyguardState.GONE)
+ }
+ }
+ }
+ }
+
+ private fun listenForDreamingLockscreenHostedToDozing() {
+ scope.launch {
+ combine(
+ keyguardInteractor.dozeTransitionModel,
+ transitionInteractor.startedKeyguardTransitionStep,
+ ::Pair
+ )
+ .collect { (dozeTransitionModel, lastStartedTransitionStep) ->
+ if (
+ dozeTransitionModel.to == DozeStateModel.DOZE &&
+ lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+ ) {
+ startTransitionTo(KeyguardState.DOZING)
+ }
+ }
+ }
+ }
+
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
+ return ValueAnimator().apply {
+ interpolator = Interpolators.LINEAR
+ duration =
+ if (toState == KeyguardState.LOCKSCREEN) TO_LOCKSCREEN_DURATION.inWholeMilliseconds
+ else DEFAULT_DURATION.inWholeMilliseconds
+ }
+ }
+
+ companion object {
+ private val DEFAULT_DURATION = 500.milliseconds
+ val TO_LOCKSCREEN_DURATION = 1167.milliseconds
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 98d7434166b4..954ff6f23561 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -94,11 +94,16 @@ constructor(
private fun listenForDreamingToGone() {
scope.launch {
- keyguardInteractor.biometricUnlockState.collect { biometricUnlockState ->
- if (biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM) {
- startTransitionTo(KeyguardState.GONE)
+ keyguardInteractor.biometricUnlockState
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (biometricUnlockState, lastStartedTransitionStep) ->
+ if (
+ lastStartedTransitionStep.to == KeyguardState.DREAMING &&
+ biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM
+ ) {
+ startTransitionTo(KeyguardState.GONE)
+ }
}
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index f82633fbba27..2b08b3d04e19 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -48,6 +48,7 @@ constructor(
listenForGoneToAodOrDozing()
listenForGoneToDreaming()
listenForGoneToLockscreen()
+ listenForGoneToDreamingLockscreenHosted()
}
// Primarily for when the user chooses to lock down the device
@@ -63,12 +64,35 @@ constructor(
}
}
+ private fun listenForGoneToDreamingLockscreenHosted() {
+ scope.launch {
+ keyguardInteractor.isActiveDreamLockscreenHosted
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (isActiveDreamLockscreenHosted, lastStartedStep) ->
+ if (isActiveDreamLockscreenHosted && lastStartedStep.to == KeyguardState.GONE) {
+ startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ }
+ }
+ }
+ }
+
private fun listenForGoneToDreaming() {
scope.launch {
keyguardInteractor.isAbleToDream
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
- .collect { (isAbleToDream, lastStartedStep) ->
- if (isAbleToDream && lastStartedStep.to == KeyguardState.GONE) {
+ .sample(
+ combine(
+ transitionInteractor.startedKeyguardTransitionStep,
+ keyguardInteractor.isActiveDreamLockscreenHosted,
+ ::Pair
+ ),
+ ::toTriple
+ )
+ .collect { (isAbleToDream, lastStartedStep, isActiveDreamLockscreenHosted) ->
+ if (
+ isAbleToDream &&
+ lastStartedStep.to == KeyguardState.GONE &&
+ !isActiveDreamLockscreenHosted
+ ) {
startTransitionTo(KeyguardState.DREAMING)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index ed1bf3ef2753..6b28b270032e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -70,17 +70,27 @@ constructor(
combine(
transitionInteractor.startedKeyguardTransitionStep,
transitionInteractor.finishedKeyguardState,
- ::Pair
+ keyguardInteractor.isActiveDreamLockscreenHosted,
+ ::Triple
),
- ::toTriple
+ ::toQuad
)
- .collect { (isAbleToDream, lastStartedTransition, finishedKeyguardState) ->
+ .collect {
+ (
+ isAbleToDream,
+ lastStartedTransition,
+ finishedKeyguardState,
+ isActiveDreamLockscreenHosted) ->
val isOnLockscreen = finishedKeyguardState == KeyguardState.LOCKSCREEN
val isTransitionInterruptible =
lastStartedTransition.to == KeyguardState.LOCKSCREEN &&
!invalidFromStates.contains(lastStartedTransition.from)
if (isAbleToDream && (isOnLockscreen || isTransitionInterruptible)) {
- startTransitionTo(KeyguardState.DREAMING)
+ if (isActiveDreamLockscreenHosted) {
+ startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ } else {
+ startTransitionTo(KeyguardState.DREAMING)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index e1754f55b1dd..9142d1faa90a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -27,6 +27,8 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
+import com.android.systemui.util.kotlin.Utils.Companion.toQuint
+import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
@@ -52,6 +54,7 @@ constructor(
listenForPrimaryBouncerToGone()
listenForPrimaryBouncerToAodOrDozing()
listenForPrimaryBouncerToLockscreenOrOccluded()
+ listenForPrimaryBouncerToDreamingLockscreenHosted()
}
private fun listenForPrimaryBouncerToLockscreenOrOccluded() {
@@ -62,17 +65,24 @@ constructor(
keyguardInteractor.wakefulnessModel,
transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
- ::Triple
+ keyguardInteractor.isActiveDreamLockscreenHosted,
+ ::toQuad
),
- ::toQuad
+ ::toQuint
)
- .collect { (isBouncerShowing, wakefulnessState, lastStartedTransitionStep, occluded)
- ->
+ .collect {
+ (
+ isBouncerShowing,
+ wakefulnessState,
+ lastStartedTransitionStep,
+ occluded,
+ isActiveDreamLockscreenHosted) ->
if (
!isBouncerShowing &&
lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER &&
(wakefulnessState.state == WakefulnessState.AWAKE ||
- wakefulnessState.state == WakefulnessState.STARTING_TO_WAKE)
+ wakefulnessState.state == WakefulnessState.STARTING_TO_WAKE) &&
+ !isActiveDreamLockscreenHosted
) {
startTransitionTo(
if (occluded) KeyguardState.OCCLUDED else KeyguardState.LOCKSCREEN
@@ -111,6 +121,30 @@ constructor(
}
}
+ private fun listenForPrimaryBouncerToDreamingLockscreenHosted() {
+ scope.launch {
+ keyguardInteractor.primaryBouncerShowing
+ .sample(
+ combine(
+ keyguardInteractor.isActiveDreamLockscreenHosted,
+ transitionInteractor.startedKeyguardTransitionStep,
+ ::Pair
+ ),
+ ::toTriple
+ )
+ .collect {
+ (isBouncerShowing, isActiveDreamLockscreenHosted, lastStartedTransitionStep) ->
+ if (
+ !isBouncerShowing &&
+ isActiveDreamLockscreenHosted &&
+ lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER
+ ) {
+ startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ }
+ }
+ }
+ }
+
private fun listenForPrimaryBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index cc159168009e..53d3c076247e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -34,9 +34,9 @@ import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState
+import com.android.systemui.keyguard.shared.model.ScreenModel
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
@@ -87,7 +87,7 @@ constructor(
/** Whether the system is in doze mode. */
val isDozing: Flow<Boolean> = repository.isDozing
/** Receive an event for doze time tick */
- val dozeTimeTick: Flow<Unit> = repository.dozeTimeTick
+ val dozeTimeTick: Flow<Long> = repository.dozeTimeTick
/** Whether Always-on Display mode is available. */
val isAodAvailable: Flow<Boolean> = repository.isAodAvailable
/** Doze transition information. */
@@ -100,7 +100,7 @@ constructor(
/** Whether the system is dreaming with an overlay active */
val isDreamingWithOverlay: Flow<Boolean> = repository.isDreamingWithOverlay
/** Whether the system is dreaming and the active dream is hosted in lockscreen */
- val isActiveDreamLockscreenHosted: Flow<Boolean> = repository.isActiveDreamLockscreenHosted
+ val isActiveDreamLockscreenHosted: StateFlow<Boolean> = repository.isActiveDreamLockscreenHosted
/** Event for when the camera gesture is detected */
val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> = conflatedCallbackFlow {
val callback =
@@ -122,6 +122,9 @@ constructor(
/** The device wake/sleep state */
val wakefulnessModel: StateFlow<WakefulnessModel> = repository.wakefulness
+ /** The device screen state */
+ val screenModel: StateFlow<ScreenModel> = repository.screenModel
+
/**
* Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
* that doze mode is not running and DREAMING is ok to commence.
@@ -237,8 +240,16 @@ constructor(
repository.setQuickSettingsVisible(isVisible)
}
- fun setKeyguardRootVisibility(statusBarState: Int, goingToFullShade: Boolean, isOcclusionTransitionRunning: Boolean) {
- repository.setKeyguardVisibility(statusBarState, goingToFullShade, isOcclusionTransitionRunning)
+ fun setKeyguardRootVisibility(
+ statusBarState: Int,
+ goingToFullShade: Boolean,
+ isOcclusionTransitionRunning: Boolean
+ ) {
+ repository.setKeyguardVisibility(
+ statusBarState,
+ goingToFullShade,
+ isOcclusionTransitionRunning
+ )
}
fun setClockPosition(x: Int, y: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index a48684381345..9c796f846994 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -412,7 +412,11 @@ constructor(
KeyguardPickerFlag(
name = Contract.FlagsTable.FLAG_NAME_PAGE_TRANSITIONS,
value = featureFlags.isEnabled(Flags.WALLPAPER_PICKER_PAGE_TRANSITIONS)
- )
+ ),
+ KeyguardPickerFlag(
+ name = Contract.FlagsTable.FLAG_NAME_WALLPAPER_PICKER_PREVIEW_ANIMATION,
+ value = featureFlags.isEnabled(Flags.WALLPAPER_PICKER_PREVIEW_ANIMATION)
+ ),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
index efc1bd0fff04..ba7b9870103a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
@@ -45,6 +45,7 @@ constructor(
is FromOccludedTransitionInteractor -> Log.d(TAG, "Started $it")
is FromDozingTransitionInteractor -> Log.d(TAG, "Started $it")
is FromAlternateBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
+ is FromDreamingLockscreenHostedTransitionInteractor -> Log.d(TAG, "Started $it")
}
it.start()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 45bf20d3ec44..8c4c7ae53ce6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -24,6 +24,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
+import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING_LOCKSCREEN_HOSTED
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
@@ -89,12 +90,20 @@ constructor(
val dreamingToLockscreenTransition: Flow<TransitionStep> =
repository.transition(DREAMING, LOCKSCREEN)
+ /** DREAMING_LOCKSCREEN_HOSTED->LOCKSCREEN transition information. */
+ val dreamingLockscreenHostedToLockscreenTransition: Flow<TransitionStep> =
+ repository.transition(DREAMING_LOCKSCREEN_HOSTED, LOCKSCREEN)
+
/** GONE->AOD transition information. */
val goneToAodTransition: Flow<TransitionStep> = repository.transition(GONE, AOD)
/** GONE->DREAMING transition information. */
val goneToDreamingTransition: Flow<TransitionStep> = repository.transition(GONE, DREAMING)
+ /** GONE->DREAMING_LOCKSCREEN_HOSTED transition information. */
+ val goneToDreamingLockscreenHostedTransition: Flow<TransitionStep> =
+ repository.transition(GONE, DREAMING_LOCKSCREEN_HOSTED)
+
/** LOCKSCREEN->AOD transition information. */
val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
@@ -102,6 +111,10 @@ constructor(
val lockscreenToDreamingTransition: Flow<TransitionStep> =
repository.transition(LOCKSCREEN, DREAMING)
+ /** LOCKSCREEN->DREAMING_LOCKSCREEN_HOSTED transition information. */
+ val lockscreenToDreamingLockscreenHostedTransition: Flow<TransitionStep> =
+ repository.transition(LOCKSCREEN, DREAMING_LOCKSCREEN_HOSTED)
+
/** LOCKSCREEN->OCCLUDED transition information. */
val lockscreenToOccludedTransition: Flow<TransitionStep> =
repository.transition(LOCKSCREEN, OCCLUDED)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
index 4244e5565a4b..6115d90430b3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
@@ -92,6 +92,7 @@ constructor(
KeyguardState.DOZING -> false
KeyguardState.AOD -> false
KeyguardState.DREAMING -> true
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED -> true
KeyguardState.ALTERNATE_BOUNCER -> true
KeyguardState.PRIMARY_BOUNCER -> true
KeyguardState.LOCKSCREEN -> true
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
index 1c200b086990..278c68d3c55b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
@@ -19,10 +19,9 @@ package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -30,17 +29,14 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** Hosts business and application state accessing logic for the lockscreen scene. */
+@SysUISingleton
class LockscreenSceneInteractor
-@AssistedInject
+@Inject
constructor(
@Application applicationScope: CoroutineScope,
private val authenticationInteractor: AuthenticationInteractor,
- bouncerInteractorFactory: BouncerInteractor.Factory,
- @Assisted private val containerName: String,
+ private val bouncerInteractor: BouncerInteractor,
) {
- private val bouncerInteractor: BouncerInteractor =
- bouncerInteractorFactory.create(containerName)
-
/** Whether the device is currently locked. */
val isDeviceLocked: StateFlow<Boolean> =
authenticationInteractor.isUnlocked
@@ -67,13 +63,6 @@ constructor(
/** Attempts to dismiss the lockscreen. This will cause the bouncer to show, if needed. */
fun dismissLockscreen() {
- bouncerInteractor.showOrUnlockDevice(containerName = containerName)
- }
-
- @AssistedFactory
- interface Factory {
- fun create(
- containerName: String,
- ): LockscreenSceneInteractor
+ bouncerInteractor.showOrUnlockDevice()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
index d9690b7e3b38..56f552961432 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
@@ -50,6 +50,12 @@ abstract class StartKeyguardTransitionModule {
@Binds
@IntoSet
+ abstract fun fromDreamingLockscreenHosted(
+ impl: FromDreamingLockscreenHostedTransitionInteractor
+ ): TransitionInteractor
+
+ @Binds
+ @IntoSet
abstract fun fromOccluded(impl: FromOccludedTransitionInteractor): TransitionInteractor
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index 8f4776fa2ed3..2a3f8520a63c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -35,6 +35,7 @@ import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.log.FaceAuthenticationLogger
+import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -49,6 +50,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/**
* Encapsulates business logic related face authentication being triggered for device entry from
@@ -69,6 +71,7 @@ constructor(
private val faceAuthenticationLogger: FaceAuthenticationLogger,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ private val userRepository: UserRepository,
) : CoreStartable, KeyguardFaceAuthInteractor {
private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf()
@@ -128,6 +131,23 @@ constructor(
}
}
.launchIn(applicationScope)
+
+ // User switching should stop face auth and then when it is complete we should trigger face
+ // auth so that the switched user can unlock the device with face auth.
+ userRepository.userSwitchingInProgress
+ .pairwise(false)
+ .onEach { (wasSwitching, isSwitching) ->
+ if (!wasSwitching && isSwitching) {
+ repository.pauseFaceAuth()
+ } else if (wasSwitching && !isSwitching) {
+ repository.resumeFaceAuth()
+ runFaceAuth(
+ FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING,
+ fallbackToDetect = true
+ )
+ }
+ }
+ .launchIn(applicationScope)
}
override fun onSwipeUpOnBouncer() {
@@ -199,8 +219,10 @@ constructor(
} else {
faceAuthenticationStatusOverride.value = null
applicationScope.launch {
- faceAuthenticationLogger.authRequested(uiEvent)
- repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect)
+ withContext(mainDispatcher) {
+ faceAuthenticationLogger.authRequested(uiEvent)
+ repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect)
+ }
}
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
index 87b4321769b5..1e20cdbed9eb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
@@ -35,6 +35,12 @@ enum class KeyguardState {
* parties to present their own UI over keyguard, like a screensaver.
*/
DREAMING,
+ /*
+ * A device state after the device times out, which can be from both LOCKSCREEN or GONE states.
+ * It is a special version of DREAMING state but not DOZING. The active dream will be windowless
+ * and hosted in the lockscreen.
+ */
+ DREAMING_LOCKSCREEN_HOSTED,
/**
* The device has entered a special low-power mode within SystemUI, also called the Always-on
* Display (AOD). A minimal UI is presented to show critical information. If the device is in
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt
new file mode 100644
index 000000000000..113f01c0b122
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down GONE->DREAMING_LOCKSCREEN_HOSTED transition into discrete steps for corresponding
+ * views to consume.
+ */
+@SysUISingleton
+class GoneToDreamingLockscreenHostedTransitionViewModel
+@Inject
+constructor(
+ interactor: KeyguardTransitionInteractor,
+) {
+
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = TO_DREAMING_DURATION,
+ transitionFlow = interactor.goneToDreamingLockscreenHostedTransition,
+ )
+
+ /** Lockscreen views alpha - hide immediately */
+ val lockscreenAlpha: Flow<Float> =
+ transitionAnimation.createFlow(
+ duration = 1.milliseconds,
+ onStep = { 0f },
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index f212a553aeb3..abd178ca6c1d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -19,12 +19,11 @@ package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.R
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -32,15 +31,13 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** Models UI state and handles user input for the lockscreen scene. */
+@SysUISingleton
class LockscreenSceneViewModel
-@AssistedInject
+@Inject
constructor(
@Application applicationScope: CoroutineScope,
- interactorFactory: LockscreenSceneInteractor.Factory,
- @Assisted containerName: String,
+ private val interactor: LockscreenSceneInteractor,
) {
- private val interactor: LockscreenSceneInteractor = interactorFactory.create(containerName)
-
/** The icon for the "lock" button on the lockscreen. */
val lockButtonIcon: StateFlow<Icon> =
interactor.isDeviceLocked
@@ -98,11 +95,4 @@ constructor(
)
)
}
-
- @AssistedFactory
- interface Factory {
- fun create(
- containerName: String,
- ): LockscreenSceneViewModel
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
index b307f1b43b45..dd586076be83 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
@@ -112,6 +112,7 @@ open class UdfpsLockscreenViewModel(
KeyguardState.OFF,
KeyguardState.DOZING,
KeyguardState.DREAMING,
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
KeyguardState.AOD,
KeyguardState.PRIMARY_BOUNCER,
KeyguardState.GONE,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index 42164c795b06..fdb3ddd7294f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -30,16 +30,11 @@ import android.os.IBinder
import android.os.ResultReceiver
import android.os.UserHandle
import android.view.ViewGroup
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.LifecycleRegistry
+import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider
+import com.android.intentresolver.AbstractMultiProfilePagerAdapter.MyUserIdProvider
+import com.android.intentresolver.ChooserActivity
+import com.android.intentresolver.chooser.TargetInfo
import com.android.internal.annotations.VisibleForTesting
-import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider
-import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider
-import com.android.internal.app.ChooserActivity
-import com.android.internal.app.ResolverListController
-import com.android.internal.app.chooser.NotSelectableTargetInfo
-import com.android.internal.app.chooser.TargetInfo
import com.android.systemui.R
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorComponent
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController
@@ -56,12 +51,8 @@ class MediaProjectionAppSelectorActivity(
private val activityLauncher: AsyncActivityLauncher,
/** This is used to override the dependency in a screenshot test */
@VisibleForTesting
- private val listControllerFactory: ((userHandle: UserHandle) -> ResolverListController)?
-) :
- ChooserActivity(),
- MediaProjectionAppSelectorView,
- MediaProjectionAppSelectorResultHandler,
- LifecycleOwner {
+ private val listControllerFactory: ((userHandle: UserHandle) -> ChooserListController)?
+) : ChooserActivity(), MediaProjectionAppSelectorView, MediaProjectionAppSelectorResultHandler {
@Inject
constructor(
@@ -69,8 +60,6 @@ class MediaProjectionAppSelectorActivity(
activityLauncher: AsyncActivityLauncher
) : this(componentFactory, activityLauncher, listControllerFactory = null)
- private val lifecycleRegistry = LifecycleRegistry(this)
- override val lifecycle = lifecycleRegistry
private lateinit var configurationController: ConfigurationController
private lateinit var controller: MediaProjectionAppSelectorController
private lateinit var recentsViewController: MediaProjectionRecentsViewController
@@ -84,7 +73,6 @@ class MediaProjectionAppSelectorActivity(
override fun getLayoutResource() = R.layout.media_projection_app_selector
public override fun onCreate(bundle: Bundle?) {
- lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
component = componentFactory.create(view = this, resultHandler = this)
component.lifecycleObservers.forEach { lifecycle.addObserver(it) }
@@ -107,26 +95,6 @@ class MediaProjectionAppSelectorActivity(
controller.init()
}
- override fun onStart() {
- super.onStart()
- lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
- }
-
- override fun onResume() {
- super.onResume()
- lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
- }
-
- override fun onPause() {
- lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
- super.onPause()
- }
-
- override fun onStop() {
- lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
- super.onStop()
- }
-
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
configurationController.onConfigurationChanged(newConfig)
@@ -137,13 +105,13 @@ class MediaProjectionAppSelectorActivity(
override fun createBlockerEmptyStateProvider(): EmptyStateProvider =
component.emptyStateProvider
- override fun createListController(userHandle: UserHandle): ResolverListController =
+ override fun createListController(userHandle: UserHandle): ChooserListController =
listControllerFactory?.invoke(userHandle) ?: super.createListController(userHandle)
override fun startSelected(which: Int, always: Boolean, filtered: Boolean) {
val currentListAdapter = mChooserMultiProfilePagerAdapter.activeListAdapter
val targetInfo = currentListAdapter.targetInfoForPosition(which, filtered) ?: return
- if (targetInfo is NotSelectableTargetInfo) return
+ if (targetInfo.isNotSelectableTargetInfo) return
val intent = createIntent(targetInfo)
@@ -183,7 +151,6 @@ class MediaProjectionAppSelectorActivity(
}
override fun onDestroy() {
- lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
component.lifecycleObservers.forEach { lifecycle.removeObserver(it) }
// onDestroy is also called when an app is selected, in that case we only want to send
// RECORD_CONTENT_TASK but not RECORD_CANCEL
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt
index 829b0ddbe3a8..fd14e2b9a96b 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt
@@ -17,10 +17,10 @@ package com.android.systemui.mediaprojection.appselector
import android.content.Context
import android.os.UserHandle
+import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyState
+import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider
+import com.android.intentresolver.ResolverListAdapter
import com.android.internal.R as AndroidR
-import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyState
-import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider
-import com.android.internal.app.ResolverListAdapter
import com.android.systemui.R
import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile
import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 2adc211ef23f..0842fe0dd764 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -31,6 +31,7 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon
+import android.os.Process
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
@@ -317,7 +318,9 @@ constructor(
return
}
- if (user == userTracker.userHandle) {
+ // When switched to a secondary user, the sysUI is still running in the main user, we will
+ // need to update the shortcut in the secondary user.
+ if (user == getCurrentRunningUser()) {
updateNoteTaskAsUserInternal(user)
} else {
// TODO(b/278729185): Replace fire and forget service with a bounded service.
@@ -354,6 +357,9 @@ constructor(
updateNoteTaskAsUser(user)
}
+ // Returns the [UserHandle] that this class is running on.
+ @VisibleForTesting internal fun getCurrentRunningUser(): UserHandle = Process.myUserHandle()
+
private val SecureSettings.preferredUser: UserHandle
get() {
val trackingUserId = userTracker.userHandle.identifier
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 7f0f89415280..d1d3e3de39f0 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -28,6 +28,8 @@ import androidx.activity.ComponentActivity;
import androidx.lifecycle.ViewModelProvider;
import com.android.systemui.compose.ComposeFacade;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.people.ui.view.PeopleViewBinder;
import com.android.systemui.people.ui.viewmodel.PeopleViewModel;
@@ -43,11 +45,14 @@ public class PeopleSpaceActivity extends ComponentActivity {
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
private final PeopleViewModel.Factory mViewModelFactory;
+ private final FeatureFlags mFeatureFlags;
@Inject
- public PeopleSpaceActivity(PeopleViewModel.Factory viewModelFactory) {
+ public PeopleSpaceActivity(PeopleViewModel.Factory viewModelFactory,
+ FeatureFlags featureFlags) {
super();
mViewModelFactory = viewModelFactory;
+ mFeatureFlags = featureFlags;
}
@Override
@@ -67,7 +72,8 @@ public class PeopleSpaceActivity extends ComponentActivity {
return null;
};
- if (ComposeFacade.INSTANCE.isComposeAvailable()) {
+ if (mFeatureFlags.isEnabled(Flags.COMPOSE_PEOPLE_SPACE)
+ && ComposeFacade.INSTANCE.isComposeAvailable()) {
Log.d(TAG, "Using the Compose implementation of the PeopleSpaceActivity");
ComposeFacade.INSTANCE.setPeopleSpaceActivityContent(this, viewModel, onResult);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 8d9475d9a53e..ddb395b6b598 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -52,6 +52,7 @@ import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.compose.ComposeFacade;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.media.controls.ui.MediaHost;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSContainerController;
@@ -285,7 +286,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private void bindFooterActionsView(View root) {
LinearLayout footerActionsView = root.findViewById(R.id.qs_footer_actions);
- if (!ComposeFacade.INSTANCE.isComposeAvailable()) {
+ if (!mFeatureFlags.isEnabled(Flags.COMPOSE_QS_FOOTER_ACTIONS)
+ || !ComposeFacade.INSTANCE.isComposeAvailable()) {
Log.d(TAG, "Binding the View implementation of the QS footer actions");
mFooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
mListeningAndVisibilityLifecycleOwner);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 3e7bdd1a1444..9bb192b4c271 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -34,6 +34,7 @@ import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
import android.service.quicksettings.Tile;
import android.text.TextUtils;
+import android.util.Log;
import android.view.View;
import android.widget.Switch;
@@ -315,6 +316,7 @@ public class DndTile extends QSTileImpl<BooleanState> {
private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
public void onZenChanged(int zen) {
+ Log.d(TAG, "Zen changed to " + zen + ". Requesting refresh of tile.");
refreshState(zen);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
index 36dec1d112b9..5e6a44bf8130 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
@@ -16,30 +16,19 @@
package com.android.systemui.qs.ui.viewmodel
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
/** Models UI state and handles user input for the quick settings scene. */
+@SysUISingleton
class QuickSettingsSceneViewModel
-@AssistedInject
+@Inject
constructor(
- lockscreenSceneInteractorFactory: LockscreenSceneInteractor.Factory,
- @Assisted containerName: String,
+ private val lockscreenSceneInteractor: LockscreenSceneInteractor,
) {
- private val lockscreenSceneInteractor: LockscreenSceneInteractor =
- lockscreenSceneInteractorFactory.create(containerName)
-
/** Notifies that some content in quick settings was clicked. */
fun onContentClicked() {
lockscreenSceneInteractor.dismissLockscreen()
}
-
- @AssistedFactory
- interface Factory {
- fun create(
- containerName: String,
- ): QuickSettingsSceneViewModel
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index bf40a2d0ad51..03bd11bb433e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -97,7 +97,6 @@ import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.buttons.KeyButtonView;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
-import com.android.systemui.scene.shared.model.SceneContainerNames;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeViewController;
@@ -221,8 +220,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
// If scene framework is enabled, set the scene container window to
// visible and let the touch "slip" into that window.
if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
- mSceneInteractor.get().setVisible(
- SceneContainerNames.SYSTEM_UI_DEFAULT, true);
+ mSceneInteractor.get().setVisible(true);
} else {
centralSurfaces.onInputFocusTransfer(
mInputFocusTransferStarted, false /* cancel */,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 26c52199f493..398e64b1981b 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -19,7 +19,6 @@ package com.android.systemui.scene
import com.android.systemui.scene.domain.startable.SceneContainerStartableModule
import com.android.systemui.scene.shared.model.SceneContainerConfigModule
import com.android.systemui.scene.ui.composable.SceneModule
-import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModelModule
import dagger.Module
@Module(
@@ -27,7 +26,6 @@ import dagger.Module
[
SceneContainerConfigModule::class,
SceneContainerStartableModule::class,
- SceneContainerViewModelModule::class,
SceneModule::class,
],
)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index 0a86d35b7b62..1fca4886a31f 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -29,26 +29,20 @@ import kotlinx.coroutines.flow.asStateFlow
class SceneContainerRepository
@Inject
constructor(
- private val containerConfigByName: Map<String, SceneContainerConfig>,
+ private val config: SceneContainerConfig,
) {
- private val containerVisibilityByName: Map<String, MutableStateFlow<Boolean>> =
- containerConfigByName
- .map { (containerName, _) -> containerName to MutableStateFlow(true) }
- .toMap()
- private val currentSceneByContainerName: Map<String, MutableStateFlow<SceneModel>> =
- containerConfigByName
- .map { (containerName, config) ->
- containerName to MutableStateFlow(SceneModel(config.initialSceneKey))
- }
- .toMap()
- private val sceneTransitionProgressByContainerName: Map<String, MutableStateFlow<Float>> =
- containerConfigByName
- .map { (containerName, _) -> containerName to MutableStateFlow(1f) }
- .toMap()
- private val sceneTransitionByContainerName:
- Map<String, MutableStateFlow<SceneTransitionModel?>> =
- containerConfigByName.keys.associateWith { MutableStateFlow(null) }
+ private val _isVisible = MutableStateFlow(true)
+ val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
+
+ private val _currentScene = MutableStateFlow(SceneModel(config.initialSceneKey))
+ val currentScene: StateFlow<SceneModel> = _currentScene.asStateFlow()
+
+ private val _transitionProgress = MutableStateFlow(1f)
+ val transitionProgress: StateFlow<Float> = _transitionProgress.asStateFlow()
+
+ private val _transitions = MutableStateFlow<SceneTransitionModel?>(null)
+ val transitions: StateFlow<SceneTransitionModel?> = _transitions.asStateFlow()
/**
* Returns the keys to all scenes in the container with the given name.
@@ -56,100 +50,50 @@ constructor(
* The scenes will be sorted in z-order such that the last one is the one that should be
* rendered on top of all previous ones.
*/
- fun allSceneKeys(containerName: String): List<SceneKey> {
- return containerConfigByName[containerName]?.sceneKeys
- ?: error(noSuchContainerErrorMessage(containerName))
+ fun allSceneKeys(): List<SceneKey> {
+ return config.sceneKeys
}
/** Sets the current scene in the container with the given name. */
- fun setCurrentScene(containerName: String, scene: SceneModel) {
- check(allSceneKeys(containerName).contains(scene.key)) {
+ fun setCurrentScene(scene: SceneModel) {
+ check(allSceneKeys().contains(scene.key)) {
"""
- Cannot set current scene key to "${scene.key}". The container "$containerName" does
- not contain a scene with that key.
+ Cannot set current scene key to "${scene.key}". The configuration does not contain a
+ scene with that key.
"""
.trimIndent()
}
- currentSceneByContainerName.setValue(containerName, scene)
+ _currentScene.value = scene
}
/** Sets the scene transition in the container with the given name. */
- fun setSceneTransition(containerName: String, from: SceneKey, to: SceneKey) {
- check(allSceneKeys(containerName).contains(from)) {
+ fun setSceneTransition(from: SceneKey, to: SceneKey) {
+ check(allSceneKeys().contains(from)) {
"""
- Cannot set current scene key to "$from". The container "$containerName" does
- not contain a scene with that key.
+ Cannot set current scene key to "$from". The configuration does not contain a scene
+ with that key.
"""
.trimIndent()
}
- check(allSceneKeys(containerName).contains(to)) {
+ check(allSceneKeys().contains(to)) {
"""
- Cannot set current scene key to "$to". The container "$containerName" does
- not contain a scene with that key.
+ Cannot set current scene key to "$to". The configuration does not contain a scene
+ with that key.
"""
.trimIndent()
}
- sceneTransitionByContainerName.setValue(
- containerName,
- SceneTransitionModel(from = from, to = to)
- )
- }
-
- /** The current scene in the container with the given name. */
- fun currentScene(containerName: String): StateFlow<SceneModel> {
- return currentSceneByContainerName.mutableOrError(containerName).asStateFlow()
- }
-
- /**
- * Scene transitions as pairs of keys. A new value is emitted exactly once, each time a scene
- * transition occurs. The flow begins with a `null` value at first, because the initial scene is
- * not something that we transition to from another scene.
- */
- fun sceneTransitions(containerName: String): StateFlow<SceneTransitionModel?> {
- return sceneTransitionByContainerName.mutableOrError(containerName).asStateFlow()
+ _transitions.value = SceneTransitionModel(from = from, to = to)
}
/** Sets whether the container with the given name is visible. */
- fun setVisible(containerName: String, isVisible: Boolean) {
- containerVisibilityByName.setValue(containerName, isVisible)
- }
-
- /** Whether the container with the given name should be visible. */
- fun isVisible(containerName: String): StateFlow<Boolean> {
- return containerVisibilityByName.mutableOrError(containerName).asStateFlow()
+ fun setVisible(isVisible: Boolean) {
+ _isVisible.value = isVisible
}
/** Sets scene transition progress to the current scene in the container with the given name. */
- fun setSceneTransitionProgress(containerName: String, progress: Float) {
- sceneTransitionProgressByContainerName.setValue(containerName, progress)
- }
-
- /** Progress of the transition into the current scene in the container with the given name. */
- fun sceneTransitionProgress(containerName: String): StateFlow<Float> {
- return sceneTransitionProgressByContainerName.mutableOrError(containerName).asStateFlow()
- }
-
- private fun <T> Map<String, MutableStateFlow<T>>.mutableOrError(
- containerName: String,
- ): MutableStateFlow<T> {
- return this[containerName] ?: error(noSuchContainerErrorMessage(containerName))
- }
-
- private fun <T> Map<String, MutableStateFlow<T>>.setValue(
- containerName: String,
- value: T,
- ) {
- val mutable = mutableOrError(containerName)
- mutable.value = value
- }
-
- private fun noSuchContainerErrorMessage(containerName: String): String {
- return """
- No container named "$containerName". Existing containers:
- ${containerConfigByName.values.joinToString(", ") { it.name }}
- """
- .trimIndent()
+ fun setSceneTransitionProgress(progress: Float) {
+ _transitionProgress.value = progress
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index f03f040c206d..39daad33f75e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -30,12 +30,8 @@ import kotlinx.coroutines.flow.asStateFlow
/**
* Generic business logic and app state accessors for the scene framework.
*
- * Note that scene container specific business logic does not belong in this class. Instead, it
- * should be hoisted to a class that is specific to that scene container, for an example, please see
- * [SystemUiDefaultSceneContainerStartable].
- *
- * Also note that this class should not depend on state or logic of other modules or features.
- * Instead, other feature modules should depend on and call into this class when their parts of the
+ * Note that this class should not depend on state or logic of other modules or features. Instead,
+ * other feature modules should depend on and call into this class when their parts of the
* application state change.
*/
@SysUISingleton
@@ -51,50 +47,42 @@ constructor(
* The scenes will be sorted in z-order such that the last one is the one that should be
* rendered on top of all previous ones.
*/
- fun allSceneKeys(containerName: String): List<SceneKey> {
- return repository.allSceneKeys(containerName)
+ fun allSceneKeys(): List<SceneKey> {
+ return repository.allSceneKeys()
}
/** Sets the scene in the container with the given name. */
- fun setCurrentScene(containerName: String, scene: SceneModel) {
- val currentSceneKey = repository.currentScene(containerName).value.key
- repository.setCurrentScene(containerName, scene)
- repository.setSceneTransition(containerName, from = currentSceneKey, to = scene.key)
+ fun setCurrentScene(scene: SceneModel) {
+ val currentSceneKey = repository.currentScene.value.key
+ repository.setCurrentScene(scene)
+ repository.setSceneTransition(from = currentSceneKey, to = scene.key)
}
/** The current scene in the container with the given name. */
- fun currentScene(containerName: String): StateFlow<SceneModel> {
- return repository.currentScene(containerName)
- }
+ val currentScene: StateFlow<SceneModel> = repository.currentScene
/** Sets the visibility of the container with the given name. */
- fun setVisible(containerName: String, isVisible: Boolean) {
- return repository.setVisible(containerName, isVisible)
+ fun setVisible(isVisible: Boolean) {
+ return repository.setVisible(isVisible)
}
/** Whether the container with the given name is visible. */
- fun isVisible(containerName: String): StateFlow<Boolean> {
- return repository.isVisible(containerName)
- }
+ val isVisible: StateFlow<Boolean> = repository.isVisible
/** Sets scene transition progress to the current scene in the container with the given name. */
- fun setSceneTransitionProgress(containerName: String, progress: Float) {
- repository.setSceneTransitionProgress(containerName, progress)
+ fun setSceneTransitionProgress(progress: Float) {
+ repository.setSceneTransitionProgress(progress)
}
/** Progress of the transition into the current scene in the container with the given name. */
- fun sceneTransitionProgress(containerName: String): StateFlow<Float> {
- return repository.sceneTransitionProgress(containerName)
- }
+ val transitionProgress: StateFlow<Float> = repository.transitionProgress
/**
* Scene transitions as pairs of keys. A new value is emitted exactly once, each time a scene
* transition occurs. The flow begins with a `null` value at first, because the initial scene is
* not something that we transition to from another scene.
*/
- fun sceneTransitions(containerName: String): StateFlow<SceneTransitionModel?> {
- return repository.sceneTransitions(containerName)
- }
+ val transitions: StateFlow<SceneTransitionModel?> = repository.transitions
private val _remoteUserInput: MutableStateFlow<RemoteUserInput?> = MutableStateFlow(null)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 92384d68157b..1c87eb25004e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -28,7 +28,6 @@ import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.model.SysUiState
import com.android.systemui.model.updateFlags
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
@@ -44,12 +43,11 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
/**
- * Hooks up business logic that manipulates the state of the [SceneInteractor] for the default
- * system UI scene container (the one named [SceneContainerNames.SYSTEM_UI_DEFAULT]) based on state
- * from other systems.
+ * Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI
+ * scene container based on state from other systems.
*/
@SysUISingleton
-class SystemUiDefaultSceneContainerStartable
+class SceneContainerStartable
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
@@ -72,13 +70,10 @@ constructor(
/** Updates the visibility of the scene container based on the current scene. */
private fun hydrateVisibility() {
applicationScope.launch {
- sceneInteractor
- .currentScene(CONTAINER_NAME)
+ sceneInteractor.currentScene
.map { it.key }
.distinctUntilChanged()
- .collect { sceneKey ->
- sceneInteractor.setVisible(CONTAINER_NAME, sceneKey != SceneKey.Gone)
- }
+ .collect { sceneKey -> sceneInteractor.setVisible(sceneKey != SceneKey.Gone) }
}
}
@@ -87,7 +82,7 @@ constructor(
applicationScope.launch {
authenticationInteractor.isUnlocked
.map { isUnlocked ->
- val currentSceneKey = sceneInteractor.currentScene(CONTAINER_NAME).value.key
+ val currentSceneKey = sceneInteractor.currentScene.value.key
val isBypassEnabled = authenticationInteractor.isBypassEnabled()
when {
isUnlocked ->
@@ -135,8 +130,7 @@ constructor(
/** Keeps [SysUiState] up-to-date */
private fun hydrateSystemUiState() {
applicationScope.launch {
- sceneInteractor
- .currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT)
+ sceneInteractor.currentScene
.map { it.key }
.distinctUntilChanged()
.collect { sceneKey ->
@@ -155,12 +149,7 @@ constructor(
private fun switchToScene(targetSceneKey: SceneKey) {
sceneInteractor.setCurrentScene(
- containerName = CONTAINER_NAME,
scene = SceneModel(targetSceneKey),
)
}
-
- companion object {
- private const val CONTAINER_NAME = SceneContainerNames.SYSTEM_UI_DEFAULT
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt
index b3de2d158a53..8da1803053f4 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt
@@ -27,6 +27,6 @@ interface SceneContainerStartableModule {
@Binds
@IntoMap
- @ClassKey(SystemUiDefaultSceneContainerStartable::class)
- fun bind(impl: SystemUiDefaultSceneContainerStartable): CoreStartable
+ @ClassKey(SceneContainerStartable::class)
+ fun bind(impl: SceneContainerStartable): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
index 354de8ac7aa5..31597c1752db 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
@@ -27,8 +27,6 @@ import kotlinx.coroutines.flow.asStateFlow
* takes care of rendering the current scene and allowing scenes to be switched from one to another
* based on either user action (for example, swiping down while on the lock screen scene may switch
* to the shade scene).
- *
- * The framework also supports multiple containers, each one with its own configuration.
*/
interface Scene {
@@ -59,7 +57,7 @@ interface Scene {
* The API is designed such that it's possible to emit ever-changing values for each
* [UserAction] to enable, disable, or change the destination scene of a given user action.
*/
- fun destinationScenes(containerName: String): StateFlow<Map<UserAction, SceneModel>> =
+ fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
MutableStateFlow(emptyMap<UserAction, SceneModel>()).asStateFlow()
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
index 0327edbb06b4..8204edc33fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
@@ -16,10 +16,8 @@
package com.android.systemui.scene.shared.model
-/** Models the configuration of a single scene container. */
+/** Models the configuration of the scene container. */
data class SceneContainerConfig(
- /** Container name. Must be unique across all containers in System UI. */
- val name: String,
/**
* The keys to all scenes in the container, sorted by z-order such that the last one renders on
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt
index 7562a5a848d8..f74005b03816 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt
@@ -16,44 +16,27 @@
package com.android.systemui.scene.shared.model
-import com.android.systemui.dagger.SysUISingleton
import dagger.Module
import dagger.Provides
-import javax.inject.Named
@Module
object SceneContainerConfigModule {
@Provides
- fun containerConfigs(): Map<String, SceneContainerConfig> {
- return mapOf(
- SceneContainerNames.SYSTEM_UI_DEFAULT to
- SceneContainerConfig(
- name = SceneContainerNames.SYSTEM_UI_DEFAULT,
- // Note that this list is in z-order. The first one is the bottom-most and the
- // last
- // one is top-most.
- sceneKeys =
- listOf(
- SceneKey.Gone,
- SceneKey.Lockscreen,
- SceneKey.Bouncer,
- SceneKey.Shade,
- SceneKey.QuickSettings,
- ),
- initialSceneKey = SceneKey.Lockscreen,
+ fun containerConfig(): SceneContainerConfig {
+ return SceneContainerConfig(
+ // Note that this list is in z-order. The first one is the bottom-most and the
+ // last
+ // one is top-most.
+ sceneKeys =
+ listOf(
+ SceneKey.Gone,
+ SceneKey.Lockscreen,
+ SceneKey.Bouncer,
+ SceneKey.Shade,
+ SceneKey.QuickSettings,
),
+ initialSceneKey = SceneKey.Lockscreen,
)
}
-
- @Provides
- @SysUISingleton
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
- fun provideDefaultSceneContainerConfig(
- configs: Map<String, SceneContainerConfig>,
- ): SceneContainerConfig {
- return checkNotNull(configs[SceneContainerNames.SYSTEM_UI_DEFAULT]) {
- "No SceneContainerConfig named \"${SceneContainerNames.SYSTEM_UI_DEFAULT}\"."
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 005f48d9f250..f44748a99080 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -17,16 +17,20 @@
package com.android.systemui.scene.ui.viewmodel
import android.view.MotionEvent
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.RemoteUserInput
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
+import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow
-/** Models UI state for a single scene container. */
-class SceneContainerViewModel(
+/** Models UI state for the scene container. */
+@SysUISingleton
+class SceneContainerViewModel
+@Inject
+constructor(
private val interactor: SceneInteractor,
- val containerName: String,
) {
/** A flow of motion events originating from outside of the scene framework. */
val remoteUserInput: StateFlow<RemoteUserInput?> = interactor.remoteUserInput
@@ -37,22 +41,22 @@ class SceneContainerViewModel(
* The scenes will be sorted in z-order such that the last one is the one that should be
* rendered on top of all previous ones.
*/
- val allSceneKeys: List<SceneKey> = interactor.allSceneKeys(containerName)
+ val allSceneKeys: List<SceneKey> = interactor.allSceneKeys()
/** The current scene. */
- val currentScene: StateFlow<SceneModel> = interactor.currentScene(containerName)
+ val currentScene: StateFlow<SceneModel> = interactor.currentScene
/** Whether the container is visible. */
- val isVisible: StateFlow<Boolean> = interactor.isVisible(containerName)
+ val isVisible: StateFlow<Boolean> = interactor.isVisible
/** Requests a transition to the scene with the given key. */
fun setCurrentScene(scene: SceneModel) {
- interactor.setCurrentScene(containerName, scene)
+ interactor.setCurrentScene(scene)
}
/** Notifies of the progress of a scene transition. */
fun setSceneTransitionProgress(progress: Float) {
- interactor.setSceneTransitionProgress(containerName, progress)
+ interactor.setSceneTransitionProgress(progress)
}
/** Handles a [MotionEvent] representing remote user input. */
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelModule.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelModule.kt
deleted file mode 100644
index 100f42764322..000000000000
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelModule.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.ui.viewmodel
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneContainerNames
-import dagger.Module
-import dagger.Provides
-import javax.inject.Named
-
-@Module
-object SceneContainerViewModelModule {
-
- @Provides
- @SysUISingleton
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
- fun defaultSceneContainerViewModel(
- interactor: SceneInteractor,
- ): SceneContainerViewModel {
- return SceneContainerViewModel(
- interactor = interactor,
- containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
- )
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 773f35e0c665..2ea63c2a9847 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -140,6 +140,7 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel;
import com.android.systemui.keyguard.ui.binder.KeyguardLongPressViewBinder;
import com.android.systemui.keyguard.ui.view.KeyguardRootView;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingLockscreenHostedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel;
@@ -597,6 +598,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
private final OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
private final LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel;
private final GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
+ private final GoneToDreamingLockscreenHostedTransitionViewModel
+ mGoneToDreamingLockscreenHostedTransitionViewModel;
+
private final LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@@ -605,6 +609,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
private final CoroutineDispatcher mMainDispatcher;
private boolean mIsAnyMultiShadeExpanded;
private boolean mIsOcclusionTransitionRunning = false;
+ private boolean mIsGoneToDreamingLockscreenHostedTransitionRunning;
private int mDreamingToLockscreenTransitionTranslationY;
private int mOccludedToLockscreenTransitionTranslationY;
private int mLockscreenToDreamingTransitionTranslationY;
@@ -652,6 +657,25 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
step.getTransitionState() == TransitionState.RUNNING;
};
+ private final Consumer<TransitionStep> mGoneToDreamingLockscreenHostedTransition =
+ (TransitionStep step) -> {
+ mIsOcclusionTransitionRunning =
+ step.getTransitionState() == TransitionState.RUNNING;
+ mIsGoneToDreamingLockscreenHostedTransitionRunning = mIsOcclusionTransitionRunning;
+ };
+
+ private final Consumer<TransitionStep> mLockscreenToDreamingLockscreenHostedTransition =
+ (TransitionStep step) -> {
+ mIsOcclusionTransitionRunning =
+ step.getTransitionState() == TransitionState.RUNNING;
+ };
+
+ private final Consumer<TransitionStep> mDreamingLockscreenHostedToLockscreenTransition =
+ (TransitionStep step) -> {
+ mIsOcclusionTransitionRunning =
+ step.getTransitionState() == TransitionState.RUNNING;
+ };
+
private final Consumer<TransitionStep> mLockscreenToOccludedTransition =
(TransitionStep step) -> {
mIsOcclusionTransitionRunning =
@@ -734,6 +758,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel,
LockscreenToDreamingTransitionViewModel lockscreenToDreamingTransitionViewModel,
GoneToDreamingTransitionViewModel goneToDreamingTransitionViewModel,
+ GoneToDreamingLockscreenHostedTransitionViewModel
+ goneToDreamingLockscreenHostedTransitionViewModel,
LockscreenToOccludedTransitionViewModel lockscreenToOccludedTransitionViewModel,
@Main CoroutineDispatcher mainDispatcher,
KeyguardTransitionInteractor keyguardTransitionInteractor,
@@ -761,6 +787,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mOccludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel;
mLockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel;
mGoneToDreamingTransitionViewModel = goneToDreamingTransitionViewModel;
+ mGoneToDreamingLockscreenHostedTransitionViewModel =
+ goneToDreamingLockscreenHostedTransitionViewModel;
mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mKeyguardInteractor = keyguardInteractor;
@@ -1091,6 +1119,24 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mDreamingToLockscreenTransitionTranslationY),
setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+ // Gone -> Dreaming hosted in lockscreen
+ collectFlow(mView, mKeyguardTransitionInteractor
+ .getGoneToDreamingLockscreenHostedTransition(),
+ mGoneToDreamingLockscreenHostedTransition, mMainDispatcher);
+ collectFlow(mView, mGoneToDreamingLockscreenHostedTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
+
+ // Lockscreen -> Dreaming hosted in lockscreen
+ collectFlow(mView, mKeyguardTransitionInteractor
+ .getLockscreenToDreamingLockscreenHostedTransition(),
+ mLockscreenToDreamingLockscreenHostedTransition, mMainDispatcher);
+
+ // Dreaming hosted in lockscreen -> Lockscreen
+ collectFlow(mView, mKeyguardTransitionInteractor
+ .getDreamingLockscreenHostedToLockscreenTransition(),
+ mDreamingLockscreenHostedToLockscreenTransition, mMainDispatcher);
+
// Occluded->Lockscreen
collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
mOccludedToLockscreenTransition, mMainDispatcher);
@@ -1496,13 +1542,18 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mAnimateNextPositionUpdate = false;
}
+ private boolean shouldAnimateKeyguardStatusViewAlignment() {
+ // Do not animate when transitioning from Gone->DreamingLockscreenHosted
+ return !mIsGoneToDreamingLockscreenHostedTransitionRunning;
+ }
+
private void updateClockAppearance() {
int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
boolean shouldAnimateClockChange = mScreenOffAnimationController.shouldAnimateClockChange();
mKeyguardStatusViewController.displayClock(computeDesiredClockSize(),
shouldAnimateClockChange);
- updateKeyguardStatusViewAlignment(/* animate= */true);
+ updateKeyguardStatusViewAlignment(/* animate= */shouldAnimateKeyguardStatusViewAlignment());
int userSwitcherHeight = mKeyguardQsUserSwitchController != null
? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
if (mKeyguardUserSwitcherController != null) {
@@ -1625,6 +1676,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
// overlap.
return true;
}
+ if (isActiveDreamLockscreenHosted()) {
+ // Dreaming hosted in lockscreen, no "visible" notifications. Safe to center the clock.
+ return true;
+ }
if (mNotificationListContainer.hasPulsingNotifications()) {
// Pulsing notification appears on the right. Move clock left to avoid overlap.
return false;
@@ -1653,6 +1708,11 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
return mDozing && mDozeParameters.getAlwaysOn();
}
+
+ private boolean isActiveDreamLockscreenHosted() {
+ return mKeyguardInteractor.isActiveDreamLockscreenHosted().getValue();
+ }
+
private boolean hasVisibleNotifications() {
return mNotificationStackScrollLayoutController
.getVisibleNotificationCount() != 0
@@ -2820,7 +2880,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
@Override
public void onScreenTurningOn() {
- mKeyguardStatusViewController.dozeTimeTick();
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ mKeyguardStatusViewController.dozeTimeTick();
+ }
}
private void onMiddleClicked() {
@@ -3070,10 +3132,11 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
}
- @Override
public void dozeTimeTick() {
mLockIconViewController.dozeTimeTick();
- mKeyguardStatusViewController.dozeTimeTick();
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ mKeyguardStatusViewController.dozeTimeTick();
+ }
if (mInterpolatedDarkAmount > 0) {
positionClockAndNotifications();
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index e02c4275f095..29551188c5c7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -36,7 +36,6 @@ import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.privacy.OngoingPrivacyChip
import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.SceneContainerConfig
-import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.scene.ui.view.SceneWindowRootView
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
@@ -73,11 +72,8 @@ abstract class ShadeViewProviderModule {
fun providesWindowRootView(
layoutInflater: LayoutInflater,
featureFlags: FeatureFlags,
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
viewModelProvider: Provider<SceneContainerViewModel>,
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
containerConfigProvider: Provider<SceneContainerConfig>,
- @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
scenesProvider: Provider<Set<@JvmSuppressWildcards Scene>>,
layoutInsetController: NotificationInsetsController,
): WindowRootView {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index 8a96a4764e66..0b3ed5601c2e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -16,12 +16,11 @@
package com.android.systemui.shade.ui.viewmodel
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -29,32 +28,29 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** Models UI state and handles user input for the shade scene. */
+@SysUISingleton
class ShadeSceneViewModel
-@AssistedInject
+@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- lockscreenSceneInteractorFactory: LockscreenSceneInteractor.Factory,
- @Assisted private val containerName: String,
+ private val lockscreenSceneInteractor: LockscreenSceneInteractor,
) {
- private val lockScreenInteractor: LockscreenSceneInteractor =
- lockscreenSceneInteractorFactory.create(containerName)
-
/** The key of the scene we should switch to when swiping up. */
val upDestinationSceneKey: StateFlow<SceneKey> =
- lockScreenInteractor.isDeviceLocked
+ lockscreenSceneInteractor.isDeviceLocked
.map { isLocked -> upDestinationSceneKey(isLocked = isLocked) }
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue =
upDestinationSceneKey(
- isLocked = lockScreenInteractor.isDeviceLocked.value,
+ isLocked = lockscreenSceneInteractor.isDeviceLocked.value,
),
)
/** Notifies that some content in the shade was clicked. */
fun onContentClicked() {
- lockScreenInteractor.dismissLockscreen()
+ lockscreenSceneInteractor.dismissLockscreen()
}
private fun upDestinationSceneKey(
@@ -62,11 +58,4 @@ constructor(
): SceneKey {
return if (isLocked) SceneKey.Lockscreen else SceneKey.Gone
}
-
- @AssistedFactory
- interface Factory {
- fun create(
- containerName: String,
- ): ShadeSceneViewModel
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt
new file mode 100644
index 000000000000..92e9765936d7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.dagger
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.statusbar.notification.logging.NotificationMemoryMonitor
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface NotificationMemoryModule {
+
+ /** Binds memory monitor into startable map. */
+ @Binds
+ @IntoMap
+ @ClassKey(NotificationMemoryMonitor::class)
+ fun bindsNotificationMemoryMonitorStartable(monitor: NotificationMemoryMonitor): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 31d4ab99098e..ea3a8f59d85b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -91,6 +91,7 @@ import javax.inject.Provider;
NotificationSectionHeadersModule.class,
NotificationListViewModelModule.class,
ActivatableNotificationViewModelModule.class,
+ NotificationMemoryModule.class,
})
public interface NotificationsModule {
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index f7bd177594a2..106d11f6bcc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -39,7 +39,6 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
import com.android.systemui.statusbar.notification.logging.NotificationLogger
-import com.android.systemui.statusbar.notification.logging.NotificationMemoryMonitor
import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.wm.shell.bubbles.Bubbles
@@ -72,7 +71,6 @@ class NotificationsControllerImpl @Inject constructor(
private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager,
private val bubblesOptional: Optional<Bubbles>,
private val fgsNotifListener: ForegroundServiceNotificationListener,
- private val memoryMonitor: Lazy<NotificationMemoryMonitor>,
private val featureFlags: FeatureFlags
) : NotificationsController {
@@ -108,7 +106,6 @@ class NotificationsControllerImpl @Inject constructor(
notificationLogger.setUpWithContainer(listContainer)
peopleSpaceWidgetManager.attach(notificationListener)
fgsNotifListener.init()
- memoryMonitor.get().init()
}
// TODO: Convert all functions below this line into listeners instead of public methods
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt
index f38c1e557b25..0fdf681aac26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt
@@ -18,6 +18,7 @@
package com.android.systemui.statusbar.notification.logging
import android.util.Log
+import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -32,13 +33,13 @@ constructor(
private val featureFlags: FeatureFlags,
private val notificationMemoryDumper: NotificationMemoryDumper,
private val notificationMemoryLogger: Lazy<NotificationMemoryLogger>,
-) {
+) : CoreStartable {
companion object {
private const val TAG = "NotificationMemory"
}
- fun init() {
+ override fun start() {
Log.d(TAG, "NotificationMemoryMonitor initialized.")
notificationMemoryDumper.init()
if (featureFlags.isEnabled(Flags.NOTIFICATION_MEMORY_LOGGING_ENABLED)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 36a8e9833d39..5e7e4be60104 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -426,16 +426,21 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
updateAppearAnimationAlpha();
updateAppearRect();
mAppearAnimator.addListener(new AnimatorListenerAdapter() {
- private boolean mWasCancelled;
+ private boolean mRunWithoutInterruptions;
@Override
public void onAnimationEnd(Animator animation) {
if (onFinishedRunnable != null) {
onFinishedRunnable.run();
}
- if (!mWasCancelled) {
+ if (mRunWithoutInterruptions) {
enableAppearDrawing(false);
- onAppearAnimationFinished(isAppearing);
+ }
+
+ // We need to reset the View state, even if the animation was cancelled
+ onAppearAnimationFinished(isAppearing);
+
+ if (mRunWithoutInterruptions) {
InteractionJankMonitor.getInstance().end(getCujType(isAppearing));
} else {
InteractionJankMonitor.getInstance().cancel(getCujType(isAppearing));
@@ -444,7 +449,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
@Override
public void onAnimationStart(Animator animation) {
- mWasCancelled = false;
+ mRunWithoutInterruptions = true;
Configuration.Builder builder = Configuration.Builder
.withView(getCujType(isAppearing), ActivatableNotificationView.this);
InteractionJankMonitor.getInstance().begin(builder);
@@ -452,7 +457,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
@Override
public void onAnimationCancel(Animator animation) {
- mWasCancelled = true;
+ mRunWithoutInterruptions = false;
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index cc087785163e..adff681bb53b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -471,7 +471,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
};
final boolean wakingFromDream = mMode == MODE_WAKE_AND_UNLOCK_FROM_DREAM
- && !mStatusBarStateController.isDozing();
+ && mPowerManager.isInteractive();
if (mMode != MODE_NONE && !wakingFromDream) {
wakeUp.run();
@@ -509,7 +509,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
// later to awaken.
}
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
- mKeyguardViewMediator.onWakeAndUnlocking();
+ mKeyguardViewMediator.onWakeAndUnlocking(wakingFromDream);
Trace.endSection();
break;
case MODE_ONLY_WAKE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index ed9722e04da0..801cdbf0e83e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -38,7 +38,6 @@ import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.keyguard.domain.interactor.BurnInInteractor;
import com.android.systemui.keyguard.domain.interactor.DozeInteractor;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.ShadeViewController;
@@ -94,7 +93,6 @@ public final class DozeServiceHost implements DozeHost {
private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
private final AuthController mAuthController;
private final NotificationIconAreaController mNotificationIconAreaController;
- private final BurnInInteractor mBurnInInteractor;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private ShadeViewController mNotificationPanel;
private View mAmbientIndicationContainer;
@@ -118,8 +116,7 @@ public final class DozeServiceHost implements DozeHost {
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
AuthController authController,
NotificationIconAreaController notificationIconAreaController,
- DozeInteractor dozeInteractor,
- BurnInInteractor burnInInteractor) {
+ DozeInteractor dozeInteractor) {
super();
mDozeLog = dozeLog;
mPowerManager = powerManager;
@@ -138,7 +135,6 @@ public final class DozeServiceHost implements DozeHost {
mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
mAuthController = authController;
mNotificationIconAreaController = notificationIconAreaController;
- mBurnInInteractor = burnInInteractor;
mHeadsUpManagerPhone.addListener(mOnHeadsUpChangedListener);
mDozeInteractor = dozeInteractor;
}
@@ -317,7 +313,6 @@ public final class DozeServiceHost implements DozeHost {
if (mAmbientIndicationContainer instanceof DozeReceiver) {
((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
}
- mBurnInInteractor.dozeTimeTick();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 8c3050d48d53..122728716eee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -30,7 +30,6 @@ import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.RemoteUserInput
-import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.shade.ShadeController
import com.android.systemui.shade.ShadeLogger
import com.android.systemui.shade.ShadeViewController
@@ -183,7 +182,7 @@ class PhoneStatusBarViewController private constructor(
sceneInteractor.get()
.onRemoteUserInput(RemoteUserInput.translateMotionEvent(event))
// TODO(b/291965119): remove once view is expanded to cover the status bar
- sceneInteractor.get().setVisible(SceneContainerNames.SYSTEM_UI_DEFAULT, true)
+ sceneInteractor.get().setVisible(true)
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 68a6b3d62bae..fa9b9d2c571a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -37,7 +37,6 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
-import com.android.systemui.scene.shared.model.SceneContainerNames;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -126,7 +125,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
javaAdapter.get().alwaysCollectFlow(
- sceneInteractor.get().isVisible(SceneContainerNames.SYSTEM_UI_DEFAULT),
+ sceneInteractor.get().isVisible(),
this::onShadeExpansionFullyChanged);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 1c3a8850df8d..dabdcc5fc0f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -46,7 +46,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.qs.SettingObserver;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.Utils;
import com.android.systemui.util.settings.GlobalSettings;
@@ -68,17 +67,17 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable {
private final Context mContext;
private final UserTracker mUserTracker;
private final BroadcastDispatcher mBroadcastDispatcher;
- private final SettingObserver mModeSetting;
- private final SettingObserver mConfigSetting;
private final NotificationManager mNoMan;
private final AlarmManager mAlarmManager;
private final SetupObserver mSetupObserver;
private final UserManager mUserManager;
+ private final GlobalSettings mGlobalSettings;
private int mUserId;
private boolean mRegistered;
private ZenModeConfig mConfig;
- private int mZenMode;
+ // This value is changed in the main thread, but may be read in a background thread.
+ private volatile int mZenMode;
private long mZenUpdateTime;
private NotificationManager.Policy mConsolidatedNotificationPolicy;
@@ -111,18 +110,20 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mUserTracker = userTracker;
- mModeSetting = new SettingObserver(globalSettings, handler, Global.ZEN_MODE,
- userTracker.getUserId()) {
+ mGlobalSettings = globalSettings;
+
+ ContentObserver modeContentObserver = new ContentObserver(handler) {
@Override
- protected void handleValueChanged(int value, boolean observedChange) {
+ public void onChange(boolean selfChange) {
+ int value = getModeSettingValueFromProvider();
+ Log.d(TAG, "Zen mode setting changed to " + value);
updateZenMode(value);
fireZenChanged(value);
}
};
- mConfigSetting = new SettingObserver(globalSettings, handler, Global.ZEN_MODE_CONFIG_ETAG,
- userTracker.getUserId()) {
+ ContentObserver configContentObserver = new ContentObserver(handler) {
@Override
- protected void handleValueChanged(int value, boolean observedChange) {
+ public void onChange(boolean selfChange) {
try {
Trace.beginSection("updateZenModeConfig");
updateZenModeConfig();
@@ -132,9 +133,9 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable {
}
};
mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- mModeSetting.setListening(true);
- updateZenMode(mModeSetting.getValue());
- mConfigSetting.setListening(true);
+ globalSettings.registerContentObserver(Global.ZEN_MODE, modeContentObserver);
+ updateZenMode(getModeSettingValueFromProvider());
+ globalSettings.registerContentObserver(Global.ZEN_MODE_CONFIG_ETAG, configContentObserver);
updateZenModeConfig();
updateConsolidatedNotificationPolicy();
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -146,6 +147,10 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable {
dumpManager.registerDumpable(getClass().getSimpleName(), this);
}
+ private int getModeSettingValueFromProvider() {
+ return mGlobalSettings.getInt(Global.ZEN_MODE, /* default */ Global.ZEN_MODE_OFF);
+ }
+
@Override
public boolean isVolumeRestricted() {
return mUserManager.hasUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
index 06cc96e2e0cd..d696979f1859 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
@@ -46,6 +46,7 @@ public class StatusBarWindowView extends FrameLayout {
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
+ setClipChildren(false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
index 757b4e50c3f8..13c1019591a1 100644
--- a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
@@ -25,16 +25,12 @@ import android.view.ViewGroup;
import androidx.concurrent.futures.CallbackToFutureAdapter;
-import com.android.systemui.dagger.qualifiers.Main;
-
import com.google.common.util.concurrent.ListenableFuture;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.Executor;
-import javax.inject.Inject;
-
/**
* {@link TouchInsetManager} handles setting the touchable inset regions for a given View. This
* is useful for passing through touch events for all but select areas.
@@ -153,8 +149,7 @@ public class TouchInsetManager {
* Default constructor.
* @param executor An {@link Executor} to marshal all operations on.
*/
- @Inject
- public TouchInsetManager(@Main Executor executor) {
+ public TouchInsetManager(Executor executor) {
mExecutor = executor;
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt
index 1e73cb3b9b24..1e6556645afb 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt
@@ -79,15 +79,15 @@ constructor(
private val hapticsScale: Float
get() {
- val intensityString = SystemProperties.get("persist.unfold.haptics_scale", "0.1")
- return intensityString.toFloatOrNull() ?: 0.1f
+ val intensityString = SystemProperties.get("persist.unfold.haptics_scale", "0.5")
+ return intensityString.toFloatOrNull() ?: 0.5f
}
private val hapticsScaleTick: Float
get() {
val intensityString =
- SystemProperties.get("persist.unfold.haptics_scale_end_tick", "0.6")
- return intensityString.toFloatOrNull() ?: 0.6f
+ SystemProperties.get("persist.unfold.haptics_scale_end_tick", "1.0")
+ return intensityString.toFloatOrNull() ?: 1.0f
}
private val primitivesCount: Int
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 3abae6bcd197..e447c29b351f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -733,29 +733,20 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
// is
// not enough to trigger a dismissal of the keyguard.
underTest.onViewAttached()
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer, null)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null))
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
// While listening, going from the bouncer scene to the gone scene, does dismiss the
// keyguard.
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Gone, null)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null))
runCurrent()
verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
// While listening, moving back to the bouncer scene does not dismiss the keyguard
// again.
clearInvocations(viewMediatorCallback)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer, null)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null))
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
@@ -763,18 +754,12 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
// scene
// does not dismiss the keyguard while we're not listening.
underTest.onViewDetached()
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Gone, null)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null))
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
// While not listening, moving back to the bouncer does not dismiss the keyguard.
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer, null)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null))
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
@@ -782,10 +767,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
// gone
// scene now does dismiss the keyguard again.
underTest.onViewAttached()
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Gone, null)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null))
runCurrent()
verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
new file mode 100644
index 000000000000..ba3dbf0a0cb7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 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.keyguard;
+
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.view.View;
+import android.view.ViewTreeObserver;
+
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.keyguard.logging.KeyguardLogger;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import org.junit.Before;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase {
+
+ @Mock protected KeyguardStatusView mKeyguardStatusView;
+ @Mock protected KeyguardSliceViewController mKeyguardSliceViewController;
+ @Mock protected KeyguardClockSwitchController mKeyguardClockSwitchController;
+ @Mock protected KeyguardStateController mKeyguardStateController;
+ @Mock protected KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock protected ConfigurationController mConfigurationController;
+ @Mock protected DozeParameters mDozeParameters;
+ @Mock protected ScreenOffAnimationController mScreenOffAnimationController;
+ @Mock protected KeyguardLogger mKeyguardLogger;
+ @Mock protected KeyguardStatusViewController mControllerMock;
+ @Mock protected FeatureFlags mFeatureFlags;
+ @Mock protected InteractionJankMonitor mInteractionJankMonitor;
+ @Mock protected ViewTreeObserver mViewTreeObserver;
+ @Mock protected DumpManager mDumpManager;
+ protected FakeKeyguardRepository mFakeKeyguardRepository;
+
+ protected KeyguardStatusViewController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ KeyguardInteractorFactory.WithDependencies deps = KeyguardInteractorFactory.create();
+ mFakeKeyguardRepository = deps.getRepository();
+
+ mController = new KeyguardStatusViewController(
+ mKeyguardStatusView,
+ mKeyguardSliceViewController,
+ mKeyguardClockSwitchController,
+ mKeyguardStateController,
+ mKeyguardUpdateMonitor,
+ mConfigurationController,
+ mDozeParameters,
+ mScreenOffAnimationController,
+ mKeyguardLogger,
+ mFeatureFlags,
+ mInteractionJankMonitor,
+ deps.getKeyguardInteractor(),
+ mDumpManager) {
+ @Override
+ void setProperty(
+ AnimatableProperty property,
+ float value,
+ boolean animate) {
+ // Route into the mock version for verification
+ mControllerMock.setProperty(property, value, animate);
+ }
+ };
+
+ when(mKeyguardStatusView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+ }
+
+ protected void givenViewAttached() {
+ ArgumentCaptor<View.OnAttachStateChangeListener> captor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+ verify(mKeyguardStatusView, atLeast(1)).addOnAttachStateChangeListener(captor.capture());
+
+ for (View.OnAttachStateChangeListener listener : captor.getAllValues()) {
+ listener.onViewAttachedToWindow(mKeyguardStatusView);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 7114c22b5701..20d9ef1e86b1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -23,80 +23,21 @@ import static org.mockito.Mockito.when;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
-import com.android.internal.jank.InteractionJankMonitor;
-import com.android.keyguard.logging.KeyguardLogger;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ClockConfig;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
-public class KeyguardStatusViewControllerTest extends SysuiTestCase {
-
- @Mock private KeyguardStatusView mKeyguardStatusView;
- @Mock private KeyguardSliceViewController mKeyguardSliceViewController;
- @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController;
- @Mock private KeyguardStateController mKeyguardStateController;
- @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock private ConfigurationController mConfigurationController;
- @Mock private DozeParameters mDozeParameters;
- @Mock private ScreenOffAnimationController mScreenOffAnimationController;
- @Mock private KeyguardLogger mKeyguardLogger;
- @Mock private KeyguardStatusViewController mControllerMock;
- @Mock private FeatureFlags mFeatureFlags;
- @Mock private InteractionJankMonitor mInteractionJankMonitor;
-
- @Mock private DumpManager mDumpManager;
-
- @Captor
- private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
-
- private KeyguardStatusViewController mController;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
-
- mController = new KeyguardStatusViewController(
- mKeyguardStatusView,
- mKeyguardSliceViewController,
- mKeyguardClockSwitchController,
- mKeyguardStateController,
- mKeyguardUpdateMonitor,
- mConfigurationController,
- mDozeParameters,
- mScreenOffAnimationController,
- mKeyguardLogger,
- mFeatureFlags,
- mInteractionJankMonitor,
- mDumpManager) {
- @Override
- void setProperty(
- AnimatableProperty property,
- float value,
- boolean animate) {
- // Route into the mock version for verification
- mControllerMock.setProperty(property, value, animate);
- }
- };
- }
+public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControllerBaseTest {
@Test
public void dozeTimeTick_updatesSlice() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt
new file mode 100644
index 000000000000..2b9797ee56d4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.systemui.keyguard.shared.model.ScreenModel
+import com.android.systemui.keyguard.shared.model.ScreenState
+import kotlinx.coroutines.cancelChildren
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class KeyguardStatusViewControllerWithCoroutinesTest : KeyguardStatusViewControllerBaseTest() {
+
+ @Test
+ fun dozeTimeTickUpdatesSlices() = runTest {
+ mController.startCoroutines(coroutineContext)
+ givenViewAttached()
+ runCurrent()
+ clearInvocations(mKeyguardSliceViewController)
+
+ mFakeKeyguardRepository.dozeTimeTick()
+ runCurrent()
+ verify(mKeyguardSliceViewController).refresh()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun onScreenTurningOnUpdatesSlices() = runTest {
+ mController.startCoroutines(coroutineContext)
+ givenViewAttached()
+ runCurrent()
+ clearInvocations(mKeyguardSliceViewController)
+
+ mFakeKeyguardRepository.setScreenModel(ScreenModel(ScreenState.SCREEN_ON))
+ runCurrent()
+ verify(mKeyguardSliceViewController, never()).refresh()
+
+ // Should only be called during a 'turning on' event
+ mFakeKeyguardRepository.setScreenModel(ScreenModel(ScreenState.SCREEN_TURNING_ON))
+ runCurrent()
+ verify(mKeyguardSliceViewController).refresh()
+
+ coroutineContext.cancelChildren()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
index 5867a40c78fa..44a2b682bf37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
@@ -20,12 +20,13 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.core.animation.AnimatorTestRule;
+import androidx.core.animation.ObjectAnimator;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
@@ -37,6 +38,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,6 +47,9 @@ import org.junit.runner.RunWith;
@RunWithLooper
public class ExpandHelperTest extends SysuiTestCase {
+ @Rule
+ public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
+
private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
private ExpandableNotificationRow mRow;
private ExpandHelper mExpandHelper;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 58982d13481d..7ab8e8b229a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -23,6 +23,7 @@ import static android.view.MotionEvent.ACTION_UP;
import static com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
+import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -61,6 +62,7 @@ import android.os.RemoteException;
import android.os.VibrationAttributes;
import android.testing.TestableLooper.RunWithLooper;
import android.util.Pair;
+import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
@@ -1128,6 +1130,36 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
+ public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled_oneWayHapticsEnabled()
+ throws RemoteException {
+ when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
+ // Configure UdfpsView to accept the ACTION_DOWN event
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+
+ // GIVEN that the overlay is showing and a11y touch exploration enabled
+ when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN ACTION_HOVER is received
+ verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
+ MotionEvent enterEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
+ mHoverListenerCaptor.getValue().onHover(mUdfpsView, enterEvent);
+ enterEvent.recycle();
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
+ mHoverListenerCaptor.getValue().onHover(mUdfpsView, moveEvent);
+ moveEvent.recycle();
+
+ // THEN context click haptic is played
+ verify(mVibrator).performHapticFeedback(
+ any(),
+ eq(HapticFeedbackConstants.CONTEXT_CLICK)
+ );
+ }
+
+ @Test
public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
@@ -1160,6 +1192,35 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
+ public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled__oneWayHapticsEnabled()
+ throws RemoteException {
+ when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
+ // Configure UdfpsView to accept the ACTION_DOWN event
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+
+ // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
+ when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN ACTION_DOWN is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ mBiometricExecutor.runAllReady();
+ downEvent.recycle();
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ mBiometricExecutor.runAllReady();
+ moveEvent.recycle();
+
+ // THEN NO haptic played
+ verify(mVibrator, never()).performHapticFeedback(any(), anyInt());
+ }
+
+ @Test
public void onTouch_withoutNewTouchDetection_shouldCallOldFingerprintManagerPath()
throws RemoteException {
// Disable new touch detection.
@@ -1514,4 +1575,45 @@ public class UdfpsControllerTest extends SysuiTestCase {
// THEN is fingerDown should be FALSE
assertFalse(mUdfpsController.isFingerDown());
}
+
+ @Test
+ public void playHaptic_onAodInterrupt_oneWayHapticsDisabled_onAcquiredBad_usesVibrate()
+ throws RemoteException {
+ // GIVEN UDFPS overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // GIVEN there's been an AoD interrupt
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
+ mScreenObserver.onScreenTurnedOn();
+ mUdfpsController.onAodInterrupt(0, 0, 0, 0);
+
+ // THEN vibrate is used
+ verify(mVibrator).vibrate(
+ anyInt(),
+ anyString(),
+ eq(UdfpsController.EFFECT_CLICK),
+ eq("aod-lock-icon-longpress"),
+ eq(UdfpsController.LOCK_ICON_VIBRATION_ATTRIBUTES)
+ );
+ }
+
+ @Test
+ public void playHaptic_onAodInterrupt_oneWayHapticsEnabled_onAcquiredBad_performHapticFeedback()
+ throws RemoteException {
+ when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
+ // GIVEN UDFPS overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // GIVEN there's been an AoD interrupt
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
+ mScreenObserver.onScreenTurnedOn();
+ mUdfpsController.onAodInterrupt(0, 0, 0, 0);
+
+ // THEN vibrate is used
+ verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 6babf0490ea9..14fc931522a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -69,13 +69,12 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun pinAuthMethod() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
+ underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
@@ -101,14 +100,13 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun pinAuthMethod_tryAutoConfirm_withAutoConfirmPin() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setAutoConfirmEnabled(true)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
+ underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
underTest.clearMessage()
@@ -138,13 +136,12 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun pinAuthMethod_tryAutoConfirm_withoutAutoConfirmPin() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
+ underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.clearMessage()
@@ -168,14 +165,13 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun passwordAuthMethod() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
+ underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD)
@@ -201,14 +197,13 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun patternAuthMethod() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
+ underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
@@ -239,13 +234,12 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
- underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
+ underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -253,12 +247,11 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
+ underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -266,8 +259,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun showOrUnlockDevice_customMessageShown() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
@@ -275,7 +267,7 @@ class BouncerInteractorTest : SysuiTestCase() {
utils.authenticationRepository.setUnlocked(false)
val customMessage = "Hello there!"
- underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1, customMessage)
+ underTest.showOrUnlockDevice(customMessage)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(customMessage)
@@ -287,11 +279,10 @@ class BouncerInteractorTest : SysuiTestCase() {
val isThrottled by collectLastValue(underTest.isThrottled)
val throttling by collectLastValue(underTest.throttling)
val message by collectLastValue(underTest.message)
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
runCurrent()
- underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
+ underTest.showOrUnlockDevice()
runCurrent()
assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
assertThat(isThrottled).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index b1533fecbc5e..1f089ca8b98e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -72,18 +72,14 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onShown() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -96,18 +92,14 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onPasswordInputChanged() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -122,16 +114,12 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateKeyPressed_whenCorrect() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("password")
@@ -144,18 +132,14 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateKeyPressed_whenWrong() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
@@ -170,18 +154,14 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateKeyPressed_correctAfterWrong() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index f69cbb8fd004..af54989002e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -75,8 +75,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onShown() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -84,10 +83,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -101,8 +97,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragStart() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -110,10 +105,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -129,18 +121,14 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragEnd_whenCorrect() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -180,8 +168,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragEnd_whenWrong() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -189,10 +176,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -216,8 +200,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragEnd_correctAfterWrong() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -225,10 +208,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 8edc6cf8dd54..c12ed033d752 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -75,15 +75,11 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onShown() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -96,16 +92,12 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onPinButtonClicked() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -120,16 +112,12 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onBackspaceButtonClicked() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -146,15 +134,11 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onPinEdit() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -172,16 +156,12 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onBackspaceButtonLongPressed() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -200,14 +180,10 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateButtonClicked_whenCorrect() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
@@ -222,16 +198,12 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateButtonClicked_whenWrong() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -250,16 +222,12 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateButtonClicked_correctAfterWrong() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -286,15 +254,11 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAutoConfirm_whenCorrect() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAutoConfirmEnabled(true)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
@@ -307,17 +271,13 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAutoConfirm_whenWrong() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAutoConfirmEnabled(true)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.dropLast(1).forEach { digit ->
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
index 38372a33f1e6..692d794f21f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
@@ -24,7 +24,6 @@ import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -36,7 +35,6 @@ import org.junit.runner.RunWith
import org.mockito.Answers
import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
@@ -44,6 +42,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import java.util.Optional
@@ -102,14 +101,11 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
metricsLogger,
vibratorHelper,
controlsSettingsRepository,
- controlsSettingsDialogManager,
- featureFlags
))
coordinator.activityContext = mContext
`when`(cvh.cws.ci.controlId).thenReturn(ID)
`when`(cvh.cws.control?.isAuthRequired()).thenReturn(true)
- `when`(featureFlags.isEnabled(Flags.USE_APP_PANELS)).thenReturn(false)
action = spy(coordinator.Action(ID, {}, false, true))
doReturn(action).`when`(coordinator).createAction(any(), any(), anyBoolean(), anyBoolean())
@@ -155,13 +151,11 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
coordinator.toggle(cvh, "", true)
verify(coordinator).bouncerOrRun(action)
- verify(controlsSettingsDialogManager).maybeShowDialog(any(), any())
verify(action).invoke()
}
@Test
fun testToggleWhenLockedDoesNotTriggerDialog_featureFlagEnabled() {
- `when`(featureFlags.isEnabled(Flags.USE_APP_PANELS)).thenReturn(true)
action = spy(coordinator.Action(ID, {}, false, false))
doReturn(action).`when`(coordinator).createAction(any(), any(), anyBoolean(), anyBoolean())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt
index 71d2ec152e5a..bd3d09dfbb20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt
@@ -16,8 +16,6 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlsControllerImpl
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -46,7 +44,6 @@ class ControlsEditingActivityTest : SysuiTestCase() {
}
private val uiExecutor = FakeExecutor(FakeSystemClock())
- private val featureFlags = FakeFeatureFlags()
@Mock lateinit var controller: ControlsControllerImpl
@@ -65,7 +62,6 @@ class ControlsEditingActivityTest : SysuiTestCase() {
ActivityTestRule(
/* activityFactory= */ SingleActivityFactory {
TestableControlsEditingActivity(
- featureFlags,
uiExecutor,
controller,
userTracker,
@@ -81,8 +77,6 @@ class ControlsEditingActivityTest : SysuiTestCase() {
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
-
- featureFlags.set(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS, false)
}
@Test
@@ -101,16 +95,7 @@ class ControlsEditingActivityTest : SysuiTestCase() {
}
@Test
- fun testNewFlowDisabled_addControlsButton_gone() {
- with(launchActivity()) {
- val addControlsButton = requireViewById<Button>(R.id.addControls)
- assertThat(addControlsButton.visibility).isEqualTo(View.GONE)
- }
- }
-
- @Test
- fun testNewFlowEnabled_addControlsButton_visible() {
- featureFlags.set(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS, true)
+ fun testAddControlsButton_visible() {
with(launchActivity()) {
val addControlsButton = requireViewById<Button>(R.id.addControls)
assertThat(addControlsButton.visibility).isEqualTo(View.VISIBLE)
@@ -120,7 +105,6 @@ class ControlsEditingActivityTest : SysuiTestCase() {
@Test
fun testNotLaunchFromFavoriting_saveButton_disabled() {
- featureFlags.set(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS, true)
with(launchActivity(isFromFavoriting = false)) {
val saveButton = requireViewById<Button>(R.id.done)
assertThat(saveButton.isEnabled).isFalse()
@@ -129,7 +113,6 @@ class ControlsEditingActivityTest : SysuiTestCase() {
@Test
fun testLaunchFromFavoriting_saveButton_enabled() {
- featureFlags.set(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS, true)
with(launchActivity(isFromFavoriting = true)) {
val saveButton = requireViewById<Button>(R.id.done)
assertThat(saveButton.isEnabled).isTrue()
@@ -138,7 +121,6 @@ class ControlsEditingActivityTest : SysuiTestCase() {
@Test
fun testNotFromFavoriting_addControlsPressed_launchesFavouriting() {
- featureFlags.set(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS, true)
with(launchActivity(isFromFavoriting = false)) {
val addControls = requireViewById<Button>(R.id.addControls)
@@ -177,7 +159,6 @@ class ControlsEditingActivityTest : SysuiTestCase() {
)
class TestableControlsEditingActivity(
- featureFlags: FakeFeatureFlags,
executor: FakeExecutor,
controller: ControlsControllerImpl,
userTracker: UserTracker,
@@ -186,7 +167,6 @@ class ControlsEditingActivityTest : SysuiTestCase() {
private val latch: CountDownLatch
) :
ControlsEditingActivity(
- featureFlags,
executor,
controller,
userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
index f11c296ad572..70d93a10b445 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
@@ -17,14 +17,11 @@ import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.controls.ControlStatus
-import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.controls.controller.createLoadDataObject
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
@@ -73,8 +70,6 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
@Mock lateinit var controller: ControlsControllerImpl
- @Mock lateinit var listingController: ControlsListingController
-
@Mock lateinit var userTracker: UserTracker
private var latch: CountDownLatch = CountDownLatch(1)
@@ -82,9 +77,6 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
@Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher
@Captor private lateinit var captureCallback: ArgumentCaptor<OnBackInvokedCallback>
@Captor
- private lateinit var listingCallback:
- ArgumentCaptor<ControlsListingController.ControlsListingCallback>
- @Captor
private lateinit var controlsCallback: ArgumentCaptor<Consumer<ControlsController.LoadData>>
@Rule
@@ -93,10 +85,8 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
ActivityTestRule(
/* activityFactory= */ SingleActivityFactory {
TestableControlsFavoritingActivity(
- featureFlags,
executor,
controller,
- listingController,
userTracker,
mockDispatcher,
latch
@@ -109,7 +99,6 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- featureFlags.set(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS, false)
}
// b/259549854 to root-cause and fix
@@ -130,14 +119,8 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
}
@Test
- fun testNewFlowEnabled_buttons() {
- featureFlags.set(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS, true)
+ fun testButtons() {
with(launchActivity()) {
- verify(listingController).addCallback(listingCallback.capture())
- listingCallback.value.onServicesUpdated(
- listOf(mock(ControlsServiceInfo::class.java), mock(ControlsServiceInfo::class.java))
- )
-
val rearrangeButton = requireViewById<Button>(R.id.rearrange)
assertThat(rearrangeButton.visibility).isEqualTo(View.VISIBLE)
assertThat(rearrangeButton.isEnabled).isFalse()
@@ -149,36 +132,8 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
}
@Test
- fun testNewFlowDisabled_buttons() {
- with(launchActivity()) {
- verify(listingController).addCallback(listingCallback.capture())
- activityRule.runOnUiThread {
- listingCallback.value.onServicesUpdated(
- listOf(
- mock(ControlsServiceInfo::class.java),
- mock(ControlsServiceInfo::class.java)
- )
- )
- }
-
- val rearrangeButton = requireViewById<Button>(R.id.rearrange)
- assertThat(rearrangeButton.visibility).isEqualTo(View.GONE)
- assertThat(rearrangeButton.isEnabled).isFalse()
-
- val otherAppsButton = requireViewById<Button>(R.id.other_apps)
- otherAppsButton.waitForPost()
- assertThat(otherAppsButton.visibility).isEqualTo(View.VISIBLE)
- }
- }
-
- @Test
- fun testNewFlowEnabled_rearrangePressed_savesAndlaunchesActivity() {
- featureFlags.set(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS, true)
+ fun testRearrangePressed_savesAndlaunchesActivity() {
with(launchActivity()) {
- verify(listingController).addCallback(capture(listingCallback))
- listingCallback.value.onServicesUpdated(
- listOf(mock(ControlsServiceInfo::class.java), mock(ControlsServiceInfo::class.java))
- )
verify(controller).loadForComponent(any(), capture(controlsCallback), any())
activityRule.runOnUiThread {
controlsCallback.value.accept(
@@ -224,19 +179,15 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
)
class TestableControlsFavoritingActivity(
- featureFlags: FeatureFlags,
executor: Executor,
controller: ControlsControllerImpl,
- listingController: ControlsListingController,
userTracker: UserTracker,
private val mockDispatcher: OnBackInvokedDispatcher,
private val latch: CountDownLatch
) :
ControlsFavoritingActivity(
- featureFlags,
executor,
controller,
- listingController,
userTracker,
) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index ee213f7c4257..b1061ba76c14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -37,7 +37,6 @@ import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.APP_PANELS_ALL_APPS_ALLOWED
-import com.android.systemui.flags.Flags.USE_APP_PANELS
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.ActivityTaskManagerProxy
import com.android.systemui.util.concurrency.FakeExecutor
@@ -124,8 +123,6 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
arrayOf(componentName.packageName)
)
- // Return true by default, we'll test the false path
- `when`(featureFlags.isEnabled(USE_APP_PANELS)).thenReturn(true)
// Return false by default, we'll test the true path
`when`(featureFlags.isEnabled(APP_PANELS_ALL_APPS_ALLOWED)).thenReturn(false)
@@ -445,34 +442,6 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
}
@Test
- fun testActivityDefaultEnabled_flagDisabled_nullPanel() {
- `when`(featureFlags.isEnabled(USE_APP_PANELS)).thenReturn(false)
- val serviceInfo = ServiceInfo(
- componentName,
- activityName,
- )
-
- `when`(packageManager.getComponentEnabledSetting(eq(activityName)))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
-
- setUpQueryResult(listOf(
- ActivityInfo(
- activityName,
- enabled = true,
- exported = true,
- permission = Manifest.permission.BIND_CONTROLS
- )
- ))
-
- val list = listOf(serviceInfo)
- serviceListingCallbackCaptor.value.onServicesReloaded(list)
-
- executor.runAllReady()
-
- assertNull(controller.getCurrentServices()[0].panelActivity)
- }
-
- @Test
fun testActivityDifferentPackage_nullPanel() {
val serviceInfo = ServiceInfo(
componentName,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 0ffa2d7b970e..d8d3f92911ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -275,7 +275,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
TestableLooper.get(this).processAllMessages();
mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
- mViewMediator.onWakeAndUnlocking();
+ mViewMediator.onWakeAndUnlocking(false);
mViewMediator.onStartedWakingUp(OFF_BECAUSE_OF_USER, false);
TestableLooper.get(this).processAllMessages();
@@ -337,6 +337,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mViewMediator.onSystemReady();
TestableLooper.get(this).processAllMessages();
+ when(mPowerManager.isInteractive()).thenReturn(true);
+
// Given device is dreaming
when(mUpdateMonitor.isDreaming()).thenReturn(true);
@@ -707,14 +709,14 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
@Test
public void testWakeAndUnlocking() {
- mViewMediator.onWakeAndUnlocking();
+ mViewMediator.onWakeAndUnlocking(false);
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
}
@Test
public void testWakeAndUnlockingOverDream() {
// Send signal to wake
- mViewMediator.onWakeAndUnlocking();
+ mViewMediator.onWakeAndUnlocking(true);
// Ensure not woken up yet
verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
@@ -743,7 +745,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
@Test
public void testWakeAndUnlockingOverDream_signalAuthenticateIfStillShowing() {
// Send signal to wake
- mViewMediator.onWakeAndUnlocking();
+ mViewMediator.onWakeAndUnlocking(true);
// Ensure not woken up yet
verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
@@ -773,6 +775,35 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
}
@Test
+ public void testWakeAndUnlockingOverNonInteractiveDream_noWakeByKeyguardViewMediator() {
+ // Send signal to wake
+ mViewMediator.onWakeAndUnlocking(false);
+
+ // Ensure not woken up yet
+ verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+
+ // Verify keyguard told of authentication
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ mViewMediator.mViewMediatorCallback.keyguardDonePending(true,
+ mUpdateMonitor.getCurrentUser());
+ mViewMediator.mViewMediatorCallback.readyForKeyguardDone();
+ final ArgumentCaptor<Runnable> animationRunnableCaptor =
+ ArgumentCaptor.forClass(Runnable.class);
+ verify(mStatusBarKeyguardViewManager).startPreHideAnimation(
+ animationRunnableCaptor.capture());
+
+ when(mStatusBarStateController.isDreaming()).thenReturn(true);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+ animationRunnableCaptor.getValue().run();
+
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+ mViewMediator.mViewMediatorCallback.keyguardGone();
+
+ // Verify not woken up.
+ verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+ }
+
+ @Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public void testDoKeyguardWhileInteractive_resets() {
mViewMediator.setShowingLocked(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 01a6c64a6898..85ee0e4d6ec3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -541,10 +541,8 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
}
@Test
- fun authenticateDoesNotRunIfUserIsCurrentlySwitching() =
- testScope.runTest {
- testGatingCheckForFaceAuth { fakeUserRepository.setUserSwitching(true) }
- }
+ fun authenticateDoesNotRunIfFaceAuthIsCurrentlyPaused() =
+ testScope.runTest { testGatingCheckForFaceAuth { underTest.pauseFaceAuth() } }
@Test
fun authenticateDoesNotRunIfKeyguardIsNotShowing() =
@@ -840,7 +838,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
@Test
fun detectDoesNotRunWhenUserSwitchingInProgress() =
- testScope.runTest { testGatingCheckForDetect { fakeUserRepository.setUserSwitching(true) } }
+ testScope.runTest { testGatingCheckForDetect { underTest.pauseFaceAuth() } }
@Test
fun detectDoesNotRunWhenKeyguardGoingAway() =
@@ -1130,7 +1128,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
.addLockoutResetCallback(faceLockoutResetCallback.capture())
biometricSettingsRepository.setFaceEnrolled(true)
biometricSettingsRepository.setIsFaceAuthEnabled(true)
- fakeUserRepository.setUserSwitching(false)
+ underTest.resumeFaceAuth()
trustRepository.setCurrentUserTrusted(false)
keyguardRepository.setKeyguardGoingAway(false)
keyguardRepository.setWakefulnessModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index ba7d3490e56d..5e3376a45488 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -49,6 +49,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
@@ -85,13 +86,14 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
private val mainDispatcher = StandardTestDispatcher()
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
+ private lateinit var systemClock: FakeSystemClock
private lateinit var underTest: KeyguardRepositoryImpl
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
-
+ systemClock = FakeSystemClock()
underTest =
KeyguardRepositoryImpl(
statusBarStateController,
@@ -107,6 +109,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
dreamOverlayCallbackController,
mainDispatcher,
testScope.backgroundScope,
+ systemClock,
)
}
@@ -167,11 +170,15 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
@Test
fun dozeTimeTick() =
testScope.runTest {
- var dozeTimeTickValue = collectLastValue(underTest.dozeTimeTick)
+ val lastDozeTimeTick by collectLastValue(underTest.dozeTimeTick)
+ assertThat(lastDozeTimeTick).isEqualTo(0L)
+
+ // WHEN dozeTimeTick updated
+ systemClock.setUptimeMillis(systemClock.uptimeMillis() + 5)
underTest.dozeTimeTick()
- runCurrent()
- assertThat(dozeTimeTickValue()).isNull()
+ // THEN listeners were updated to the latest uptime millis
+ assertThat(systemClock.uptimeMillis()).isEqualTo(lastDozeTimeTick)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
index 069a4862ccdc..630826954057 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
@@ -23,10 +23,9 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.doze.util.BurnInHelperWrapper
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
-import junit.framework.Assert.assertEquals
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
@@ -48,7 +47,8 @@ class BurnInInteractorTest : SysuiTestCase() {
@Mock private lateinit var burnInHelperWrapper: BurnInHelperWrapper
private lateinit var configurationRepository: FakeConfigurationRepository
- private lateinit var systemClock: FakeSystemClock
+ private lateinit var keyguardInteractor: KeyguardInteractor
+ private lateinit var fakeKeyguardRepository: FakeKeyguardRepository
private lateinit var testScope: TestScope
private lateinit var underTest: BurnInInteractor
@@ -56,8 +56,10 @@ class BurnInInteractorTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
configurationRepository = FakeConfigurationRepository()
- systemClock = FakeSystemClock()
-
+ KeyguardInteractorFactory.create().let {
+ keyguardInteractor = it.keyguardInteractor
+ fakeKeyguardRepository = it.repository
+ }
whenever(burnInHelperWrapper.burnInOffset(anyInt(), anyBoolean())).thenReturn(burnInOffset)
setBurnInProgress(.65f)
@@ -68,26 +70,11 @@ class BurnInInteractorTest : SysuiTestCase() {
burnInHelperWrapper,
testScope.backgroundScope,
configurationRepository,
- systemClock,
+ keyguardInteractor,
)
}
@Test
- fun dozeTimeTick_updatesOnDozeTimeTick() =
- testScope.runTest {
- // Initial state set to 0
- val lastDozeTimeTick by collectLastValue(underTest.dozeTimeTick)
- assertEquals(0L, lastDozeTimeTick)
-
- // WHEN dozeTimeTick updated
- incrementUptimeMillis()
- underTest.dozeTimeTick()
-
- // THEN listeners were updated to the latest uptime millis
- assertThat(systemClock.uptimeMillis()).isEqualTo(lastDozeTimeTick)
- }
-
- @Test
fun udfpsBurnInOffset_updatesOnResolutionScaleChange() =
testScope.runTest {
val udfpsBurnInOffsetX by collectLastValue(underTest.udfpsBurnInXOffset)
@@ -111,25 +98,18 @@ class BurnInInteractorTest : SysuiTestCase() {
assertThat(udfpsBurnInProgress).isEqualTo(burnInProgress)
setBurnInProgress(.88f)
- incrementUptimeMillis()
- underTest.dozeTimeTick()
+ fakeKeyguardRepository.dozeTimeTick(10)
assertThat(udfpsBurnInProgress).isEqualTo(burnInProgress)
setBurnInProgress(.92f)
- incrementUptimeMillis()
- underTest.dozeTimeTick()
+ fakeKeyguardRepository.dozeTimeTick(20)
assertThat(udfpsBurnInProgress).isEqualTo(burnInProgress)
setBurnInProgress(.32f)
- incrementUptimeMillis()
- underTest.dozeTimeTick()
+ fakeKeyguardRepository.dozeTimeTick(30)
assertThat(udfpsBurnInProgress).isEqualTo(burnInProgress)
}
- private fun incrementUptimeMillis() {
- systemClock.setUptimeMillis(systemClock.uptimeMillis() + 5)
- }
-
private fun setBurnInProgress(progress: Float) {
burnInProgress = progress
whenever(burnInHelperWrapper.burnInProgressOffset()).thenReturn(burnInProgress)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 8636dd8df3b0..93f208ee14f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -48,6 +48,7 @@ import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -74,6 +75,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
private lateinit var faceAuthRepository: FakeDeviceEntryFaceAuthRepository
+ private lateinit var fakeUserRepository: FakeUserRepository
private lateinit var fakeDeviceEntryFingerprintAuthRepository:
FakeDeviceEntryFingerprintAuthRepository
@@ -98,6 +100,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
.keyguardTransitionInteractor
fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
+ fakeUserRepository = FakeUserRepository()
underTest =
SystemUIKeyguardFaceAuthInteractor(
mContext,
@@ -131,7 +134,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
featureFlags,
FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")),
keyguardUpdateMonitor,
- fakeDeviceEntryFingerprintAuthRepository
+ fakeDeviceEntryFingerprintAuthRepository,
+ fakeUserRepository,
)
}
@@ -212,6 +216,38 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
}
@Test
+ fun faceAuthIsPausedWhenUserSwitchingIsInProgress() =
+ testScope.runTest {
+ underTest.start()
+
+ fakeUserRepository.setUserSwitching(false)
+ runCurrent()
+ fakeUserRepository.setUserSwitching(true)
+ runCurrent()
+
+ assertThat(faceAuthRepository.isFaceAuthPaused()).isTrue()
+ }
+
+ @Test
+ fun faceAuthIsUnpausedWhenUserSwitchingIsInComplete() =
+ testScope.runTest {
+ underTest.start()
+
+ // previously running
+ fakeUserRepository.setUserSwitching(true)
+ runCurrent()
+ fakeUserRepository.setUserSwitching(false)
+ runCurrent()
+
+ assertThat(faceAuthRepository.isFaceAuthPaused()).isFalse()
+
+ runCurrent()
+ assertThat(faceAuthRepository.runningAuthRequest.value!!.first)
+ .isEqualTo(FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING)
+ assertThat(faceAuthRepository.runningAuthRequest.value!!.second).isEqualTo(true)
+ }
+
+ @Test
fun faceAuthIsRequestedWhenPrimaryBouncerIsVisible() =
testScope.runTest {
underTest.start()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index d01a46e06b9b..daf5ce691df0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -89,6 +89,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
FromAlternateBouncerTransitionInteractor
private lateinit var fromPrimaryBouncerTransitionInteractor:
FromPrimaryBouncerTransitionInteractor
+ private lateinit var fromDreamingLockscreenHostedTransitionInteractor:
+ FromDreamingLockscreenHostedTransitionInteractor
@Before
fun setUp() {
@@ -140,6 +142,15 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
)
.apply { start() }
+ fromDreamingLockscreenHostedTransitionInteractor =
+ FromDreamingLockscreenHostedTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ )
+ .apply { start() }
+
fromAodTransitionInteractor =
FromAodTransitionInteractor(
scope = testScope,
@@ -299,6 +310,38 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
}
@Test
+ fun lockscreenToDreamingLockscreenHosted() =
+ testScope.runTest {
+ // GIVEN a device that is not dreaming or dozing
+ keyguardRepository.setDreamingWithOverlay(false)
+ keyguardRepository.setWakefulnessModel(startingToWake())
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
+ )
+ runCurrent()
+
+ // GIVEN a prior transition has run to LOCKSCREEN
+ runTransition(KeyguardState.GONE, KeyguardState.LOCKSCREEN)
+
+ // WHEN the device begins to dream and the dream is lockscreen hosted
+ keyguardRepository.setDreamingWithOverlay(true)
+ keyguardRepository.setIsActiveDreamLockscreenHosted(true)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition to DREAMING_LOCKSCREEN_HOSTED should occur
+ assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.to).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
fun lockscreenToDozing() =
testScope.runTest {
// GIVEN a device with AOD not available
@@ -353,6 +396,149 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
}
@Test
+ fun dreamingLockscreenHostedToLockscreen() =
+ testScope.runTest {
+ // GIVEN a device dreaming with the lockscreen hosted dream and not dozing
+ keyguardRepository.setIsActiveDreamLockscreenHosted(true)
+ keyguardRepository.setWakefulnessModel(startingToWake())
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
+ )
+ runCurrent()
+
+ // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
+ runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+
+ // WHEN the lockscreen hosted dream stops
+ keyguardRepository.setIsActiveDreamLockscreenHosted(false)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition to Lockscreen should occur
+ assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun dreamingLockscreenHostedToGone() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
+ runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+
+ // WHEN biometrics succeeds with wake and unlock from dream mode
+ keyguardRepository.setBiometricUnlockState(
+ BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM
+ )
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition to Gone should occur
+ assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ assertThat(info.to).isEqualTo(KeyguardState.GONE)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun dreamingLockscreenHostedToPrimaryBouncer() =
+ testScope.runTest {
+ // GIVEN a device dreaming with lockscreen hosted dream and not dozing
+ keyguardRepository.setIsActiveDreamLockscreenHosted(true)
+ keyguardRepository.setWakefulnessModel(startingToWake())
+ runCurrent()
+
+ // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
+ runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+
+ // WHEN the primary bouncer is set to show
+ bouncerRepository.setPrimaryShow(true)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition to PRIMARY_BOUNCER should occur
+ assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun dreamingLockscreenHostedToDozing() =
+ testScope.runTest {
+ // GIVEN a device is dreaming with lockscreen hosted dream
+ keyguardRepository.setIsActiveDreamLockscreenHosted(true)
+ runCurrent()
+
+ // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
+ runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+
+ // WHEN the device begins to sleep
+ keyguardRepository.setIsActiveDreamLockscreenHosted(false)
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(from = DozeStateModel.INITIALIZED, to = DozeStateModel.DOZE)
+ )
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ assertThat(info.to).isEqualTo(KeyguardState.DOZING)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun dreamingLockscreenHostedToOccluded() =
+ testScope.runTest {
+ // GIVEN device is dreaming with lockscreen hosted dream and not occluded
+ keyguardRepository.setIsActiveDreamLockscreenHosted(true)
+ keyguardRepository.setKeyguardOccluded(false)
+ runCurrent()
+
+ // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
+ runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+
+ // WHEN the keyguard is occluded and the lockscreen hosted dream stops
+ keyguardRepository.setIsActiveDreamLockscreenHosted(false)
+ keyguardRepository.setKeyguardOccluded(true)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition to OCCLUDED should occur
+ assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
fun dozingToLockscreen() =
testScope.runTest {
// GIVEN a prior transition has run to DOZING
@@ -533,6 +719,38 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
}
@Test
+ fun goneToDreamingLockscreenHosted() =
+ testScope.runTest {
+ // GIVEN a device that is not dreaming or dozing
+ keyguardRepository.setDreamingWithOverlay(false)
+ keyguardRepository.setWakefulnessModel(startingToWake())
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
+ )
+ runCurrent()
+
+ // GIVEN a prior transition has run to GONE
+ runTransition(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
+
+ // WHEN the device begins to dream with the lockscreen hosted dream
+ keyguardRepository.setDreamingWithOverlay(true)
+ keyguardRepository.setIsActiveDreamLockscreenHosted(true)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition to DREAMING_LOCKSCREEN_HOSTED should occur
+ assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.GONE)
+ assertThat(info.to).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
fun alternateBouncerToPrimaryBouncer() =
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
@@ -726,6 +944,34 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
}
@Test
+ fun primaryBouncerToDreamingLockscreenHosted() =
+ testScope.runTest {
+ // GIVEN device dreaming with the lockscreen hosted dream and not dozing
+ keyguardRepository.setIsActiveDreamLockscreenHosted(true)
+ keyguardRepository.setWakefulnessModel(startingToWake())
+
+ // GIVEN a prior transition has run to PRIMARY_BOUNCER
+ bouncerRepository.setPrimaryShow(true)
+ runTransition(KeyguardState.DREAMING_LOCKSCREEN_HOSTED, KeyguardState.PRIMARY_BOUNCER)
+
+ // WHEN the primary bouncer stops showing and lockscreen hosted dream still active
+ bouncerRepository.setPrimaryShow(false)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition back to DREAMING_LOCKSCREEN_HOSTED should occur
+ assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
fun occludedToGone() =
testScope.runTest {
// GIVEN a device on lockscreen
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
index ca6a5b6234b9..d825c2a01464 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
@@ -21,7 +21,6 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
@@ -91,7 +90,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
@Test
fun dismissLockScreen_deviceLockedWithSecureAuthMethod_switchesToBouncer() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
@@ -104,7 +103,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
@Test
fun dismissLockScreen_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setUnlocked(true)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
@@ -117,7 +116,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
@Test
fun dismissLockScreen_deviceLockedWithInsecureAuthMethod_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
@@ -131,11 +130,11 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
fun switchFromLockScreenToGone_authMethodNotSwipe_doesNotUnlockDevice() =
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Lockscreen))
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(isUnlocked).isFalse()
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone))
assertThat(isUnlocked).isFalse()
}
@@ -145,13 +144,13 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
runCurrent()
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Shade))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade))
runCurrent()
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent()
assertThat(isUnlocked).isFalse()
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone))
assertThat(isUnlocked).isFalse()
}
@@ -159,10 +158,10 @@ class LockscreenSceneInteractorTest : SysuiTestCase() {
@Test
fun authMethodChangedToNone_notOnLockScreenScene_doesNotDismissLockScreen() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent()
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.QuickSettings))
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.QuickSettings))
runCurrent()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt
index b019a21387da..6efec99ba834 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt
@@ -38,7 +38,6 @@ import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
@@ -68,6 +67,7 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() {
private lateinit var featureFlags: FakeFeatureFlags
private lateinit var burnInInteractor: BurnInInteractor
private lateinit var shadeRepository: FakeShadeRepository
+ private lateinit var keyguardInteractor: KeyguardInteractor
@Mock private lateinit var burnInHelper: BurnInHelperWrapper
@Mock private lateinit var dialogManager: SystemUIDialogManager
@@ -79,35 +79,32 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
testScope = TestScope()
configRepository = FakeConfigurationRepository()
- keyguardRepository = FakeKeyguardRepository()
- bouncerRepository = FakeKeyguardBouncerRepository()
- shadeRepository = FakeShadeRepository()
- fakeCommandQueue = FakeCommandQueue()
featureFlags =
FakeFeatureFlags().apply {
set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
set(Flags.FACE_AUTH_REFACTOR, false)
}
+ KeyguardInteractorFactory.create(featureFlags = featureFlags).let {
+ keyguardInteractor = it.keyguardInteractor
+ keyguardRepository = it.repository
+ }
+ bouncerRepository = FakeKeyguardBouncerRepository()
+ shadeRepository = FakeShadeRepository()
+ fakeCommandQueue = FakeCommandQueue()
burnInInteractor =
BurnInInteractor(
context,
burnInHelper,
testScope.backgroundScope,
configRepository,
- FakeSystemClock(),
+ keyguardInteractor
)
underTest =
UdfpsKeyguardInteractor(
configRepository,
burnInInteractor,
- KeyguardInteractor(
- keyguardRepository,
- fakeCommandQueue,
- featureFlags,
- bouncerRepository,
- configRepository,
- ),
+ keyguardInteractor,
shadeRepository,
dialogManager,
)
@@ -215,7 +212,7 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() {
private fun setAwake() {
keyguardRepository.setDozeAmount(0f)
- burnInInteractor.dozeTimeTick()
+ keyguardRepository.dozeTimeTick()
bouncerRepository.setAlternateVisible(false)
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index ba8e0f277b6b..63ee240fd2c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -22,9 +22,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
@@ -51,20 +49,15 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
private val underTest =
LockscreenSceneViewModel(
applicationScope = testScope.backgroundScope,
- interactorFactory =
- object : LockscreenSceneInteractor.Factory {
- override fun create(containerName: String): LockscreenSceneInteractor {
- return utils.lockScreenSceneInteractor(
+ interactor =
+ utils.lockScreenSceneInteractor(
+ authenticationInteractor = authenticationInteractor,
+ bouncerInteractor =
+ utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
- bouncerInteractor =
- utils.bouncerInteractor(
- authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
- ),
- )
- }
- },
- containerName = CONTAINER_1
+ sceneInteractor = sceneInteractor,
+ ),
+ ),
)
@Test
@@ -116,7 +109,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
@@ -129,7 +122,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -142,7 +135,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
@@ -155,7 +148,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
index b985b3ca83da..bd17de3ee939 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
@@ -20,21 +20,19 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.doze.util.BurnInHelperWrapper
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
-import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
@@ -58,9 +56,9 @@ class UdfpsAodViewModelTest : SysuiTestCase() {
private lateinit var configRepository: FakeConfigurationRepository
private lateinit var bouncerRepository: KeyguardBouncerRepository
private lateinit var keyguardRepository: FakeKeyguardRepository
- private lateinit var fakeCommandQueue: FakeCommandQueue
private lateinit var featureFlags: FakeFeatureFlags
private lateinit var shadeRepository: FakeShadeRepository
+ private lateinit var keyguardInteractor: KeyguardInteractor
@Mock private lateinit var dialogManager: SystemUIDialogManager
@Mock private lateinit var burnInHelper: BurnInHelperWrapper
@@ -70,17 +68,21 @@ class UdfpsAodViewModelTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
overrideResource(com.android.systemui.R.dimen.lock_icon_padding, defaultPadding)
testScope = TestScope()
- configRepository = FakeConfigurationRepository()
- keyguardRepository = FakeKeyguardRepository()
- bouncerRepository = FakeKeyguardBouncerRepository()
- fakeCommandQueue = FakeCommandQueue()
shadeRepository = FakeShadeRepository()
featureFlags =
FakeFeatureFlags().apply {
set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
set(Flags.FACE_AUTH_REFACTOR, false)
}
-
+ KeyguardInteractorFactory.create(
+ featureFlags = featureFlags,
+ )
+ .also {
+ keyguardInteractor = it.keyguardInteractor
+ keyguardRepository = it.repository
+ configRepository = it.configurationRepository
+ bouncerRepository = it.bouncerRepository
+ }
val udfpsKeyguardInteractor =
UdfpsKeyguardInteractor(
configRepository,
@@ -89,15 +91,9 @@ class UdfpsAodViewModelTest : SysuiTestCase() {
burnInHelper,
testScope.backgroundScope,
configRepository,
- FakeSystemClock(),
- ),
- KeyguardInteractor(
- keyguardRepository,
- fakeCommandQueue,
- featureFlags,
- bouncerRepository,
- configRepository,
+ keyguardInteractor,
),
+ keyguardInteractor,
shadeRepository,
dialogManager,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsFingerprintViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsFingerprintViewModelTest.kt
index 0fbcec23f247..80ab418fbd30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsFingerprintViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsFingerprintViewModelTest.kt
@@ -30,12 +30,11 @@ import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
-import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
@@ -90,14 +89,10 @@ class UdfpsFingerprintViewModelTest : SysuiTestCase() {
testScope.backgroundScope,
)
val keyguardInteractor =
- KeyguardInteractor(
- keyguardRepository,
- fakeCommandQueue,
- featureFlags,
- bouncerRepository,
- configRepository,
- )
-
+ KeyguardInteractorFactory.create(
+ featureFlags = featureFlags,
+ )
+ .keyguardInteractor
underTest =
FingerprintViewModel(
context,
@@ -109,7 +104,7 @@ class UdfpsFingerprintViewModelTest : SysuiTestCase() {
burnInHelper,
testScope.backgroundScope,
configRepository,
- FakeSystemClock(),
+ keyguardInteractor,
),
keyguardInteractor,
shadeRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModelTest.kt
index 41ae93183850..0456824abfbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModelTest.kt
@@ -29,6 +29,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -39,7 +40,6 @@ import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.time.FakeSystemClock
import com.android.wm.shell.animation.Interpolators
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
@@ -72,6 +72,7 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() {
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
private lateinit var configRepository: FakeConfigurationRepository
private lateinit var keyguardRepository: FakeKeyguardRepository
+ private lateinit var keyguardInteractor: KeyguardInteractor
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var shadeRepository: FakeShadeRepository
private lateinit var featureFlags: FakeFeatureFlags
@@ -81,23 +82,21 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
testScope = TestScope()
transitionRepository = FakeKeyguardTransitionRepository()
- configRepository = FakeConfigurationRepository()
- keyguardRepository = FakeKeyguardRepository()
- bouncerRepository = FakeKeyguardBouncerRepository()
shadeRepository = FakeShadeRepository()
featureFlags =
FakeFeatureFlags().apply {
set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
set(Flags.FACE_AUTH_REFACTOR, false)
}
- val keyguardInteractor =
- KeyguardInteractor(
- keyguardRepository,
- commandQueue = mock(),
- featureFlags,
- bouncerRepository,
- configRepository,
- )
+ KeyguardInteractorFactory.create(
+ featureFlags = featureFlags,
+ )
+ .also {
+ keyguardInteractor = it.keyguardInteractor
+ keyguardRepository = it.repository
+ configRepository = it.configurationRepository
+ bouncerRepository = it.bouncerRepository
+ }
underTest =
UdfpsLockscreenViewModel(
@@ -115,7 +114,7 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() {
burnInHelperWrapper = mock(),
testScope.backgroundScope,
configRepository,
- FakeSystemClock(),
+ keyguardInteractor,
),
keyguardInteractor,
shadeRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index c65a2d36e223..d933b57e8e15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -702,9 +702,10 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
// region updateNoteTaskAsUser
@Test
fun updateNoteTaskAsUser_sameUser_shouldUpdateShortcuts() {
- val user = userTracker.userHandle
+ val user = UserHandle.CURRENT
val controller = spy(createNoteTaskController())
doNothing().whenever(controller).updateNoteTaskAsUserInternal(any())
+ whenever(controller.getCurrentRunningUser()).thenReturn(user)
controller.updateNoteTaskAsUser(user)
@@ -714,10 +715,10 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
@Test
fun updateNoteTaskAsUser_differentUser_shouldUpdateShortcutsInUserProcess() {
- // FakeUserTracker will default to UserHandle.SYSTEM.
val user = UserHandle.CURRENT
val controller = spy(createNoteTaskController(isEnabled = true))
doNothing().whenever(controller).updateNoteTaskAsUserInternal(any())
+ whenever(controller.getCurrentRunningUser()).thenReturn(UserHandle.SYSTEM)
controller.updateNoteTaskAsUser(user)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index ed7a59ea7032..ee42a7011264 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -20,9 +20,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
@@ -48,26 +46,21 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
private val underTest =
QuickSettingsSceneViewModel(
- lockscreenSceneInteractorFactory =
- object : LockscreenSceneInteractor.Factory {
- override fun create(containerName: String): LockscreenSceneInteractor {
- return utils.lockScreenSceneInteractor(
+ lockscreenSceneInteractor =
+ utils.lockScreenSceneInteractor(
+ authenticationInteractor = authenticationInteractor,
+ bouncerInteractor =
+ utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
- bouncerInteractor =
- utils.bouncerInteractor(
- authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
- ),
- )
- }
- },
- containerName = CONTAINER_1
+ sceneInteractor = sceneInteractor,
+ ),
+ ),
)
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -80,7 +73,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 9ce378dd079f..826a6ccfbaec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -41,7 +41,7 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
@Test
fun allSceneKeys() {
val underTest = utils.fakeSceneContainerRepository()
- assertThat(underTest.allSceneKeys(SceneTestUtils.CONTAINER_1))
+ assertThat(underTest.allSceneKeys())
.isEqualTo(
listOf(
SceneKey.QuickSettings,
@@ -53,115 +53,58 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
)
}
- @Test(expected = IllegalStateException::class)
- fun allSceneKeys_noSuchContainer_throws() {
- val underTest = utils.fakeSceneContainerRepository()
- underTest.allSceneKeys("nonExistingContainer")
- }
-
@Test
fun currentScene() = runTest {
val underTest = utils.fakeSceneContainerRepository()
- val currentScene by collectLastValue(underTest.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.Shade))
+ underTest.setCurrentScene(SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
@Test(expected = IllegalStateException::class)
- fun currentScene_noSuchContainer_throws() {
- val underTest = utils.fakeSceneContainerRepository()
- underTest.currentScene("nonExistingContainer")
- }
-
- @Test(expected = IllegalStateException::class)
- fun setCurrentScene_noSuchContainer_throws() {
- val underTest = utils.fakeSceneContainerRepository()
- underTest.setCurrentScene("nonExistingContainer", SceneModel(SceneKey.Shade))
- }
-
- @Test(expected = IllegalStateException::class)
fun setCurrentScene_noSuchSceneInContainer_throws() {
val underTest =
utils.fakeSceneContainerRepository(
- setOf(
- utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1),
- utils.fakeSceneContainerConfig(
- SceneTestUtils.CONTAINER_2,
- listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
- ),
- )
+ utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
)
- underTest.setCurrentScene(SceneTestUtils.CONTAINER_2, SceneModel(SceneKey.Shade))
+ underTest.setCurrentScene(SceneModel(SceneKey.Shade))
}
@Test
fun isVisible() = runTest {
val underTest = utils.fakeSceneContainerRepository()
- val isVisible by collectLastValue(underTest.isVisible(SceneTestUtils.CONTAINER_1))
+ val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isTrue()
- underTest.setVisible(SceneTestUtils.CONTAINER_1, false)
+ underTest.setVisible(false)
assertThat(isVisible).isFalse()
- underTest.setVisible(SceneTestUtils.CONTAINER_1, true)
+ underTest.setVisible(true)
assertThat(isVisible).isTrue()
}
- @Test(expected = IllegalStateException::class)
- fun isVisible_noSuchContainer_throws() {
- val underTest = utils.fakeSceneContainerRepository()
- underTest.isVisible("nonExistingContainer")
- }
-
- @Test(expected = IllegalStateException::class)
- fun setVisible_noSuchContainer_throws() {
- val underTest = utils.fakeSceneContainerRepository()
- underTest.setVisible("nonExistingContainer", false)
- }
-
@Test
- fun sceneTransitionProgress() = runTest {
+ fun transitionProgress() = runTest {
val underTest = utils.fakeSceneContainerRepository()
- val sceneTransitionProgress by
- collectLastValue(underTest.sceneTransitionProgress(SceneTestUtils.CONTAINER_1))
+ val sceneTransitionProgress by collectLastValue(underTest.transitionProgress)
assertThat(sceneTransitionProgress).isEqualTo(1f)
- underTest.setSceneTransitionProgress(SceneTestUtils.CONTAINER_1, 0.1f)
+ underTest.setSceneTransitionProgress(0.1f)
assertThat(sceneTransitionProgress).isEqualTo(0.1f)
- underTest.setSceneTransitionProgress(SceneTestUtils.CONTAINER_1, 0.9f)
+ underTest.setSceneTransitionProgress(0.9f)
assertThat(sceneTransitionProgress).isEqualTo(0.9f)
}
- @Test(expected = IllegalStateException::class)
- fun sceneTransitionProgress_noSuchContainer_throws() {
- val underTest = utils.fakeSceneContainerRepository()
- underTest.sceneTransitionProgress("nonExistingContainer")
- }
-
@Test
fun setSceneTransition() = runTest {
- val underTest =
- utils.fakeSceneContainerRepository(
- setOf(
- utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1),
- utils.fakeSceneContainerConfig(
- SceneTestUtils.CONTAINER_2,
- listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
- ),
- )
- )
- val sceneTransition by
- collectLastValue(underTest.sceneTransitions(SceneTestUtils.CONTAINER_2))
+ val underTest = utils.fakeSceneContainerRepository()
+ val sceneTransition by collectLastValue(underTest.transitions)
assertThat(sceneTransition).isNull()
- underTest.setSceneTransition(
- SceneTestUtils.CONTAINER_2,
- SceneKey.Lockscreen,
- SceneKey.QuickSettings
- )
+ underTest.setSceneTransition(SceneKey.Lockscreen, SceneKey.QuickSettings)
assertThat(sceneTransition)
.isEqualTo(
SceneTransitionModel(from = SceneKey.Lockscreen, to = SceneKey.QuickSettings)
@@ -169,46 +112,20 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
}
@Test(expected = IllegalStateException::class)
- fun setSceneTransition_noSuchContainer_throws() {
- val underTest = utils.fakeSceneContainerRepository()
- underTest.setSceneTransition("nonExistingContainer", SceneKey.Lockscreen, SceneKey.Shade)
- }
-
- @Test(expected = IllegalStateException::class)
fun setSceneTransition_noFromSceneInContainer_throws() {
val underTest =
utils.fakeSceneContainerRepository(
- setOf(
- utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1),
- utils.fakeSceneContainerConfig(
- SceneTestUtils.CONTAINER_2,
- listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
- ),
- )
+ utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
)
- underTest.setSceneTransition(
- SceneTestUtils.CONTAINER_2,
- SceneKey.Shade,
- SceneKey.Lockscreen
- )
+ underTest.setSceneTransition(SceneKey.Shade, SceneKey.Lockscreen)
}
@Test(expected = IllegalStateException::class)
fun setSceneTransition_noToSceneInContainer_throws() {
val underTest =
utils.fakeSceneContainerRepository(
- setOf(
- utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1),
- utils.fakeSceneContainerConfig(
- SceneTestUtils.CONTAINER_2,
- listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
- ),
- )
+ utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
)
- underTest.setSceneTransition(
- SceneTestUtils.CONTAINER_2,
- SceneKey.Shade,
- SceneKey.Lockscreen
- )
+ underTest.setSceneTransition(SceneKey.Shade, SceneKey.Lockscreen)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index d2bbfa85604b..13a602dcddb0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -41,48 +41,46 @@ class SceneInteractorTest : SysuiTestCase() {
@Test
fun allSceneKeys() {
- assertThat(underTest.allSceneKeys(SceneTestUtils.CONTAINER_1))
- .isEqualTo(utils.fakeSceneKeys())
+ assertThat(underTest.allSceneKeys()).isEqualTo(utils.fakeSceneKeys())
}
@Test
fun currentScene() = runTest {
- val currentScene by collectLastValue(underTest.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.Shade))
+ underTest.setCurrentScene(SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
@Test
fun sceneTransitionProgress() = runTest {
- val progress by
- collectLastValue(underTest.sceneTransitionProgress(SceneTestUtils.CONTAINER_1))
+ val progress by collectLastValue(underTest.transitionProgress)
assertThat(progress).isEqualTo(1f)
- underTest.setSceneTransitionProgress(SceneTestUtils.CONTAINER_1, 0.55f)
+ underTest.setSceneTransitionProgress(0.55f)
assertThat(progress).isEqualTo(0.55f)
}
@Test
fun isVisible() = runTest {
- val isVisible by collectLastValue(underTest.isVisible(SceneTestUtils.CONTAINER_1))
+ val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isTrue()
- underTest.setVisible(SceneTestUtils.CONTAINER_1, false)
+ underTest.setVisible(false)
assertThat(isVisible).isFalse()
- underTest.setVisible(SceneTestUtils.CONTAINER_1, true)
+ underTest.setVisible(true)
assertThat(isVisible).isTrue()
}
@Test
fun sceneTransitions() = runTest {
- val transitions by collectLastValue(underTest.sceneTransitions(SceneTestUtils.CONTAINER_1))
+ val transitions by collectLastValue(underTest.transitions)
assertThat(transitions).isNull()
- val initialSceneKey = underTest.currentScene(SceneTestUtils.CONTAINER_1).value.key
- underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.Shade))
+ val initialSceneKey = underTest.currentScene.value.key
+ underTest.setCurrentScene(SceneModel(SceneKey.Shade))
assertThat(transitions)
.isEqualTo(
SceneTransitionModel(
@@ -91,7 +89,7 @@ class SceneInteractorTest : SysuiTestCase() {
)
)
- underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.QuickSettings))
+ underTest.setCurrentScene(SceneModel(SceneKey.QuickSettings))
assertThat(transitions)
.isEqualTo(
SceneTransitionModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 6f6c5a589f44..b6bd31f43d30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -28,7 +28,6 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.model.SysUiState
import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.util.mockito.mock
@@ -47,7 +46,7 @@ import org.mockito.Mockito.verify
@SmallTest
@RunWith(JUnit4::class)
-class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
+class SceneContainerStartableTest : SysuiTestCase() {
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
@@ -66,7 +65,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
private val sysUiState: SysUiState = mock()
private val underTest =
- SystemUiDefaultSceneContainerStartable(
+ SceneContainerStartable(
applicationScope = testScope.backgroundScope,
sceneInteractor = sceneInteractor,
authenticationInteractor = authenticationInteractor,
@@ -84,14 +83,8 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun hydrateVisibility_featureEnabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
- val isVisible by
- collectLastValue(sceneInteractor.isVisible(SceneContainerNames.SYSTEM_UI_DEFAULT))
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val isVisible by collectLastValue(sceneInteractor.isVisible)
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = true,
@@ -104,24 +97,15 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
assertThat(isVisible).isFalse()
- sceneInteractor.setCurrentScene(
- SceneContainerNames.SYSTEM_UI_DEFAULT,
- SceneModel(SceneKey.Shade)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade))
assertThat(isVisible).isTrue()
}
@Test
fun hydrateVisibility_featureDisabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
- val isVisible by
- collectLastValue(sceneInteractor.isVisible(SceneContainerNames.SYSTEM_UI_DEFAULT))
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val isVisible by collectLastValue(sceneInteractor.isVisible)
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = true,
@@ -133,28 +117,17 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
underTest.start()
assertThat(isVisible).isTrue()
- sceneInteractor.setCurrentScene(
- SceneContainerNames.SYSTEM_UI_DEFAULT,
- SceneModel(SceneKey.Gone)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone))
assertThat(isVisible).isTrue()
- sceneInteractor.setCurrentScene(
- SceneContainerNames.SYSTEM_UI_DEFAULT,
- SceneModel(SceneKey.Shade)
- )
+ sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade))
assertThat(isVisible).isTrue()
}
@Test
fun switchToLockscreenWhenDeviceLocks_featureEnabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = true,
@@ -171,12 +144,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToLockscreenWhenDeviceLocks_featureDisabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = false,
@@ -193,12 +161,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromBouncerToGoneWhenDeviceUnlocked_featureEnabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = false,
@@ -215,12 +178,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromBouncerToGoneWhenDeviceUnlocked_featureDisabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = false,
@@ -237,12 +195,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOn() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isBypassEnabled = true,
@@ -259,12 +212,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOff() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isBypassEnabled = false,
@@ -281,12 +229,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOff_bypassOn() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isBypassEnabled = true,
@@ -303,12 +246,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToGoneWhenDeviceSleepsUnlocked_featureEnabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = true,
@@ -325,12 +263,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToGoneWhenDeviceSleepsUnlocked_featureDisabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = true,
@@ -347,12 +280,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToLockscreenWhenDeviceSleepsLocked_featureEnabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = false,
@@ -369,12 +297,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToLockscreenWhenDeviceSleepsLocked_featureDisabled() =
testScope.runTest {
- val currentSceneKey by
- collectLastValue(
- sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
- it.key
- }
- )
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = false,
@@ -403,10 +326,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
SceneKey.QuickSettings,
)
.forEachIndexed { index, sceneKey ->
- sceneInteractor.setCurrentScene(
- SceneContainerNames.SYSTEM_UI_DEFAULT,
- SceneModel(sceneKey),
- )
+ sceneInteractor.setCurrentScene(SceneModel(sceneKey))
runCurrent()
verify(sysUiState, times(index + 1)).commitUpdate(Display.DEFAULT_DISPLAY)
@@ -422,9 +342,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
featureFlags.set(Flags.SCENE_CONTAINER, isFeatureEnabled)
authenticationRepository.setUnlocked(isDeviceUnlocked)
keyguardRepository.setBypassEnabled(isBypassEnabled)
- initialSceneKey?.let {
- sceneInteractor.setCurrentScene(SceneContainerNames.SYSTEM_UI_DEFAULT, SceneModel(it))
- }
+ initialSceneKey?.let { sceneInteractor.setCurrentScene(SceneModel(it)) }
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index 63ea918c904a..0ab98ad512ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -45,7 +45,6 @@ class SceneContainerViewModelTest : SysuiTestCase() {
private val underTest =
SceneContainerViewModel(
interactor = interactor,
- containerName = SceneTestUtils.CONTAINER_1,
)
@Test
@@ -53,10 +52,10 @@ class SceneContainerViewModelTest : SysuiTestCase() {
val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isTrue()
- interactor.setVisible(SceneTestUtils.CONTAINER_1, false)
+ interactor.setVisible(false)
assertThat(isVisible).isFalse()
- interactor.setVisible(SceneTestUtils.CONTAINER_1, true)
+ interactor.setVisible(true)
assertThat(isVisible).isTrue()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 47ca49d03cc7..9bcc8aa0ac12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -99,6 +99,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.view.KeyguardRootView;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingLockscreenHostedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel;
@@ -297,7 +298,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
@Mock protected LockscreenToOccludedTransitionViewModel
mLockscreenToOccludedTransitionViewModel;
@Mock protected GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
-
+ @Mock protected GoneToDreamingLockscreenHostedTransitionViewModel
+ mGoneToDreamingLockscreenHostedTransitionViewModel;
@Mock protected KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Mock protected KeyguardLongPressViewModel mKeyuardLongPressViewModel;
@Mock protected AlternateBouncerInteractor mAlternateBouncerInteractor;
@@ -371,6 +373,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mKeyguardLogger,
mFeatureFlags,
mInteractionJankMonitor,
+ mKeyguardInteractor,
mDumpManager));
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
@@ -477,6 +480,20 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
when(mGoneToDreamingTransitionViewModel.lockscreenTranslationY(anyInt()))
.thenReturn(emptyFlow());
+ // Gone->Dreaming lockscreen hosted
+ when(mKeyguardTransitionInteractor.getGoneToDreamingLockscreenHostedTransition())
+ .thenReturn(emptyFlow());
+ when(mGoneToDreamingLockscreenHostedTransitionViewModel.getLockscreenAlpha())
+ .thenReturn(emptyFlow());
+
+ // Dreaming lockscreen hosted->Lockscreen
+ when(mKeyguardTransitionInteractor.getDreamingLockscreenHostedToLockscreenTransition())
+ .thenReturn(emptyFlow());
+
+ // Lockscreen->Dreaming lockscreen hosted
+ when(mKeyguardTransitionInteractor.getLockscreenToDreamingLockscreenHostedTransition())
+ .thenReturn(emptyFlow());
+
// Lockscreen->Occluded
when(mKeyguardTransitionInteractor.getLockscreenToOccludedTransition())
.thenReturn(emptyFlow());
@@ -612,6 +629,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mOccludedToLockscreenTransitionViewModel,
mLockscreenToDreamingTransitionViewModel,
mGoneToDreamingTransitionViewModel,
+ mGoneToDreamingLockscreenHostedTransitionViewModel,
mLockscreenToOccludedTransitionViewModel,
mMainDispatcher,
mKeyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 6e9fba64263b..8739b28c940e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -20,7 +20,6 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
@@ -48,20 +47,15 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
private val underTest =
ShadeSceneViewModel(
applicationScope = testScope.backgroundScope,
- lockscreenSceneInteractorFactory =
- object : LockscreenSceneInteractor.Factory {
- override fun create(containerName: String): LockscreenSceneInteractor {
- return utils.lockScreenSceneInteractor(
+ lockscreenSceneInteractor =
+ utils.lockScreenSceneInteractor(
+ authenticationInteractor = authenticationInteractor,
+ bouncerInteractor =
+ utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
- bouncerInteractor =
- utils.bouncerInteractor(
- authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
- ),
- )
- }
- },
- containerName = SceneTestUtils.CONTAINER_1
+ sceneInteractor = sceneInteractor,
+ ),
+ ),
)
@Test
@@ -87,8 +81,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -101,8 +94,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
index 0b2da8bfa649..0cfca614a256 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
@@ -24,6 +24,7 @@ import android.util.Pair
import android.view.Gravity
import android.view.View
import android.widget.FrameLayout
+import androidx.core.animation.AnimatorTestRule
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
@@ -38,6 +39,7 @@ import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
@@ -50,6 +52,7 @@ import org.mockito.MockitoAnnotations
class SystemEventChipAnimationControllerTest : SysuiTestCase() {
private lateinit var controller: SystemEventChipAnimationController
+ @get:Rule val animatorTestRule = AnimatorTestRule()
@Mock private lateinit var sbWindowController: StatusBarWindowController
@Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 1dc8453a90ec..ac8b42afd4b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -789,6 +789,50 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
assertThat(row.isExpanded()).isTrue();
}
+ @Test
+ public void onDisappearAnimationFinished_shouldSetFalse_headsUpAnimatingAway()
+ throws Exception {
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+
+ // Initial state: suppose heads up animation in progress
+ row.setHeadsUpAnimatingAway(true);
+ assertThat(row.isHeadsUpAnimatingAway()).isTrue();
+
+ // on disappear animation ends
+ row.onAppearAnimationFinished(/* wasAppearing = */ false);
+ assertThat(row.isHeadsUpAnimatingAway()).isFalse();
+ }
+
+ @Test
+ public void onHUNAppear_cancelAppearDrawing_shouldResetAnimationState() throws Exception {
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+
+ row.performAddAnimation(/* delay */ 0, /* duration */ 1000, /* isHeadsUpAppear */ true);
+
+ waitForIdleSync();
+ assertThat(row.isDrawingAppearAnimation()).isTrue();
+
+ row.cancelAppearDrawing();
+
+ waitForIdleSync();
+ assertThat(row.isDrawingAppearAnimation()).isFalse();
+ }
+
+ @Test
+ public void onHUNDisappear_cancelAppearDrawing_shouldResetAnimationState() throws Exception {
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+
+ row.performAddAnimation(/* delay */ 0, /* duration */ 1000, /* isHeadsUpAppear */ false);
+
+ waitForIdleSync();
+ assertThat(row.isDrawingAppearAnimation()).isTrue();
+
+ row.cancelAppearDrawing();
+
+ waitForIdleSync();
+ assertThat(row.isDrawingAppearAnimation()).isFalse();
+ }
+
private void setDrawableIconsInImageView(CachingIconView icon, Drawable iconDrawable,
Drawable rightIconDrawable) {
ImageView iconView = mock(ImageView.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 91aa1388c31e..481f7f7858b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -199,7 +199,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
- verify(mKeyguardViewMediator).onWakeAndUnlocking();
+ verify(mKeyguardViewMediator).onWakeAndUnlocking(false);
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
}
@@ -217,7 +217,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
- verify(mKeyguardViewMediator).onWakeAndUnlocking();
+ verify(mKeyguardViewMediator).onWakeAndUnlocking(false);
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(MODE_WAKE_AND_UNLOCK);
}
@@ -671,8 +671,9 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
when(mWakefulnessLifecycle.getLastWakeReason())
.thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);
givenDreamingLocked();
+ when(mPowerManager.isInteractive()).thenReturn(true);
mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT, true);
- verify(mKeyguardViewMediator).onWakeAndUnlocking();
+ verify(mKeyguardViewMediator).onWakeAndUnlocking(true);
// Ensure that the power hasn't been told to wake up yet.
verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 57037e0c9c63..ff6f40d539fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -43,7 +43,6 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.keyguard.domain.interactor.BurnInInteractor;
import com.android.systemui.keyguard.domain.interactor.DozeInteractor;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.ShadeViewController;
@@ -96,7 +95,6 @@ public class DozeServiceHostTest extends SysuiTestCase {
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private AuthController mAuthController;
@Mock private DozeHost.Callback mCallback;
- @Mock private BurnInInteractor mBurnInInteractor;
@Mock private DozeInteractor mDozeInteractor;
@Before
@@ -108,8 +106,7 @@ public class DozeServiceHostTest extends SysuiTestCase {
() -> mAssistManager, mDozeScrimController,
mKeyguardUpdateMonitor, mPulseExpansionHandler,
mNotificationShadeWindowController, mNotificationWakeUpCoordinator,
- mAuthController, mNotificationIconAreaController, mDozeInteractor,
- mBurnInInteractor);
+ mAuthController, mNotificationIconAreaController, mDozeInteractor);
mDozeServiceHost.initialize(
mCentralSurfaces,
@@ -234,11 +231,11 @@ public class DozeServiceHostTest extends SysuiTestCase {
verifyZeroInteractions(mDozeInteractor);
}
@Test
- public void dozeTimeTickSentTBurnInInteractor() {
+ public void dozeTimeTickSentToDozeInteractor() {
// WHEN dozeTimeTick
mDozeServiceHost.dozeTimeTick();
- // THEN burnInInteractor's dozeTimeTick is updated
- verify(mBurnInInteractor).dozeTimeTick();
+ // THEN dozeInteractor's dozeTimeTick is updated
+ verify(mDozeInteractor).dozeTimeTick();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index c06dbdcf3a1b..7f3d4b7f9f76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -14,6 +14,7 @@
package com.android.systemui.statusbar.policy;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -24,10 +25,10 @@ import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.os.Handler;
-import android.os.Looper;
import android.provider.Settings;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
@@ -45,6 +46,9 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -61,9 +65,10 @@ public class ZenModeControllerImplTest extends SysuiTestCase {
DumpManager mDumpManager;
@Mock
UserTracker mUserTracker;
-
private ZenModeControllerImpl mController;
+ private final FakeSettings mGlobalSettings = new FakeSettings();
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -72,10 +77,10 @@ public class ZenModeControllerImplTest extends SysuiTestCase {
mController = new ZenModeControllerImpl(
mContext,
- Handler.createAsync(Looper.myLooper()),
+ Handler.createAsync(TestableLooper.get(this).getLooper()),
mBroadcastDispatcher,
mDumpManager,
- new FakeSettings(),
+ mGlobalSettings,
mUserTracker);
}
@@ -131,4 +136,48 @@ public class ZenModeControllerImplTest extends SysuiTestCase {
mController.addCallback(null);
mController.fireConfigChanged(null);
}
+
+ @Test
+ public void testModeChange() {
+ List<Integer> states = List.of(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
+ Settings.Global.ZEN_MODE_ALARMS,
+ Settings.Global.ZEN_MODE_ALARMS
+ );
+
+ for (Integer state : states) {
+ mGlobalSettings.putInt(Settings.Global.ZEN_MODE, state);
+ TestableLooper.get(this).processAllMessages();
+ assertEquals(state.intValue(), mController.getZen());
+ }
+ }
+
+ @Test
+ public void testModeChange_callbackNotified() {
+ final AtomicInteger currentState = new AtomicInteger(-1);
+
+ ZenModeController.Callback callback = new Callback() {
+ @Override
+ public void onZenChanged(int zen) {
+ currentState.set(zen);
+ }
+ };
+
+ mController.addCallback(callback);
+
+ List<Integer> states = List.of(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
+ Settings.Global.ZEN_MODE_ALARMS,
+ Settings.Global.ZEN_MODE_ALARMS
+ );
+
+ for (Integer state : states) {
+ mGlobalSettings.putInt(Settings.Global.ZEN_MODE, state);
+ TestableLooper.get(this).processAllMessages();
+ assertEquals(state.intValue(), currentState.get());
+ }
+
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerNames.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
index 64f5087d99bf..f1fadf6f1a4a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerNames.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
@@ -13,9 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.systemui.surfaceeffects.shaders
-package com.android.systemui.scene.shared.model
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Test
+import org.junit.runner.RunWith
-object SceneContainerNames {
- const val SYSTEM_UI_DEFAULT = "system_ui"
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SolidColorShaderTest : SysuiTestCase() {
+
+ @Test
+ fun compilesShader() {
+ SolidColorShader(Color.RED)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
new file mode 100644
index 000000000000..64ea6a68a518
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.surfaceeffects.shaders
+
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SparkleShaderTest : SysuiTestCase() {
+
+ private lateinit var sparkleShader: SparkleShader
+
+ @Test
+ fun compilesSparkleShader() {
+ sparkleShader =
+ SparkleShader().apply {
+ setPixelateAmount(
+ context.resources.displayMetrics.density *
+ SparkleShader.DEFAULT_SPARKLE_PIXELATE_AMOUNT
+ )
+ setColor(Color.RED)
+ setTime(0.01f)
+ setLumaMatteColor(Color.WHITE)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 2f228a8da0c8..e10a80cce793 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -158,7 +158,6 @@ import com.android.wm.shell.transition.Transitions;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -174,7 +173,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Optional;
-@Ignore("b/292153259")
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -280,8 +278,6 @@ public class BubblesTest extends SysuiTestCase {
@Mock
private TaskStackListenerImpl mTaskStackListener;
@Mock
- private ShellTaskOrganizer mShellTaskOrganizer;
- @Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private ScreenOffAnimationController mScreenOffAnimationController;
@@ -298,6 +294,7 @@ public class BubblesTest extends SysuiTestCase {
@Mock
private Icon mAppBubbleIcon;
+ private ShellTaskOrganizer mShellTaskOrganizer;
private TaskViewTransitions mTaskViewTransitions;
private TestableBubblePositioner mPositioner;
@@ -379,7 +376,13 @@ public class BubblesTest extends SysuiTestCase {
mock(UiEventLogger.class),
mock(UserTracker.class)
);
- when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
+
+ mShellTaskOrganizer = new ShellTaskOrganizer(mock(ShellInit.class),
+ mock(ShellCommandHandler.class),
+ null,
+ Optional.empty(),
+ Optional.empty(),
+ syncExecutor);
mBubbleProperties = new FakeBubbleProperties();
mBubbleController = new TestableBubbleController(
mContext,
diff --git a/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt b/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt
new file mode 100644
index 000000000000..026372f64e2c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt
@@ -0,0 +1,55 @@
+/*
+ * 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 androidx.core.animation
+
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+class AndroidXAnimatorIsolationRule : TestRule {
+
+ private class TestAnimationHandler : AnimationHandler(null) {
+ override fun addAnimationFrameCallback(callback: AnimationFrameCallback?) = doFail()
+ override fun removeCallback(callback: AnimationFrameCallback?) = doFail()
+ override fun onAnimationFrame(frameTime: Long) = doFail()
+ override fun setFrameDelay(frameDelay: Long) = doFail()
+ override fun getFrameDelay(): Long = doFail()
+ }
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+ @Throws(Throwable::class)
+ override fun evaluate() {
+ AnimationHandler.setTestHandler(testHandler)
+ try {
+ base.evaluate()
+ } finally {
+ AnimationHandler.setTestHandler(null)
+ }
+ }
+ }
+ }
+
+ companion object {
+ private val testHandler = TestAnimationHandler()
+ private fun doFail(): Nothing =
+ error(
+ "Test's animations are not isolated! " +
+ "Did you forget to add an AnimatorTestRule to your test class?"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index de177168e20f..28b7d4171df1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -33,6 +33,7 @@ import android.testing.TestWithLooperRule;
import android.testing.TestableLooper;
import android.util.Log;
+import androidx.core.animation.AndroidXAnimatorIsolationRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
@@ -52,6 +53,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.mockito.Mockito;
@@ -69,6 +71,12 @@ public abstract class SysuiTestCase {
private static final String TAG = "SysuiTestCase";
private Handler mHandler;
+
+ // set the lowest order so it's the outermost rule
+ @ClassRule(order = Integer.MIN_VALUE)
+ public static AndroidXAnimatorIsolationRule mAndroidXAnimatorIsolationRule =
+ new AndroidXAnimatorIsolationRule();
+
@Rule
public SysuiTestableContext mContext = new SysuiTestableContext(
InstrumentationRegistry.getContext(), getLeakCheck());
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
index f4c2db1b944e..1e1dc4fc59b1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
@@ -61,6 +61,19 @@ class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository {
_wasDisabled = true
}
+ private val faceAuthPaused = MutableStateFlow(false)
+ override fun pauseFaceAuth() {
+ faceAuthPaused.value = true
+ }
+
+ override fun resumeFaceAuth() {
+ faceAuthPaused.value = false
+ }
+
+ fun isFaceAuthPaused(): Boolean {
+ return faceAuthPaused.value
+ }
+
override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) {
_runningAuthRequest.value = uiEvent to fallbackToDetection
_isAuthRunning.value = true
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index e6894d7240f8..15ce055bcc63 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -30,7 +30,6 @@ import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -60,7 +59,7 @@ class FakeKeyguardRepository : KeyguardRepository {
private val _isDozing = MutableStateFlow(false)
override val isDozing: StateFlow<Boolean> = _isDozing
- private val _dozeTimeTick = MutableSharedFlow<Unit>()
+ private val _dozeTimeTick = MutableStateFlow<Long>(0L)
override val dozeTimeTick = _dozeTimeTick
private val _lastDozeTapToWakePosition = MutableStateFlow<Point?>(null)
@@ -174,7 +173,11 @@ class FakeKeyguardRepository : KeyguardRepository {
}
override fun dozeTimeTick() {
- _dozeTimeTick.tryEmit(Unit)
+ _dozeTimeTick.value = _dozeTimeTick.value + 1
+ }
+
+ fun dozeTimeTick(millis: Long) {
+ _dozeTimeTick.value = millis
}
override fun setLastDozeTapToWakePosition(position: Point) {
@@ -237,6 +240,10 @@ class FakeKeyguardRepository : KeyguardRepository {
_isBypassEnabled = isEnabled
}
+ fun setScreenModel(screenModel: ScreenModel) {
+ _screenModel.value = screenModel
+ }
+
override fun isUdfpsSupported(): Boolean {
return _isUdfpsSupported.value
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index f39982f54441..26a75d0cc70a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -41,7 +41,6 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.RemoteUserInput
import com.android.systemui.scene.shared.model.RemoteUserInputAction
import com.android.systemui.scene.shared.model.SceneContainerConfig
-import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.repository.UserRepository
@@ -96,13 +95,9 @@ class SceneTestUtils(
private val context = test.context
fun fakeSceneContainerRepository(
- containerConfigurations: Set<SceneContainerConfig> =
- setOf(
- fakeSceneContainerConfig(CONTAINER_1),
- fakeSceneContainerConfig(CONTAINER_2),
- )
+ containerConfig: SceneContainerConfig = fakeSceneContainerConfig(),
): SceneContainerRepository {
- return SceneContainerRepository(containerConfigurations.associateBy { it.name })
+ return SceneContainerRepository(containerConfig)
}
fun fakeSceneKeys(): List<SceneKey> {
@@ -116,11 +111,9 @@ class SceneTestUtils(
}
fun fakeSceneContainerConfig(
- name: String,
sceneKeys: List<SceneKey> = fakeSceneKeys(),
): SceneContainerConfig {
return SceneContainerConfig(
- name = name,
sceneKeys = sceneKeys,
initialSceneKey = SceneKey.Lockscreen,
)
@@ -174,7 +167,6 @@ class SceneTestUtils(
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
featureFlags = featureFlags,
- containerName = CONTAINER_1,
)
}
@@ -184,14 +176,8 @@ class SceneTestUtils(
return BouncerViewModel(
applicationContext = context,
applicationScope = applicationScope(),
- interactorFactory =
- object : BouncerInteractor.Factory {
- override fun create(containerName: String): BouncerInteractor {
- return bouncerInteractor
- }
- },
+ interactor = bouncerInteractor,
featureFlags = featureFlags,
- containerName = CONTAINER_1,
)
}
@@ -202,13 +188,7 @@ class SceneTestUtils(
return LockscreenSceneInteractor(
applicationScope = applicationScope(),
authenticationInteractor = authenticationInteractor,
- bouncerInteractorFactory =
- object : BouncerInteractor.Factory {
- override fun create(containerName: String): BouncerInteractor {
- return bouncerInteractor
- }
- },
- containerName = CONTAINER_1,
+ bouncerInteractor = bouncerInteractor,
)
}
@@ -217,9 +197,6 @@ class SceneTestUtils(
}
companion object {
- const val CONTAINER_1 = SceneContainerNames.SYSTEM_UI_DEFAULT
- const val CONTAINER_2 = "container2"
-
val REMOTE_INPUT_DOWN_GESTURE =
listOf(
RemoteUserInput(10f, 10f, RemoteUserInputAction.DOWN),
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 254e6ce14630..cf7eb5122021 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -983,8 +983,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
if (virtualDisplayWrapper == null) {
- throw new IllegalStateException(
- "Virtual device doesn't have a virtual display with ID " + displayId);
+ Slog.w(TAG, "Virtual device " + mDeviceId + " doesn't have a virtual display with ID "
+ + displayId);
+ return;
}
final long ident = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 3f4f981dc0b8..23a0782dc8a3 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -989,21 +989,16 @@ public final class PlaybackActivityMonitor
}
List<AudioPlaybackConfiguration> getActivePlaybackConfigurations(boolean isPrivileged) {
- synchronized(mPlayers) {
+ synchronized (mPlayerLock) {
if (isPrivileged) {
return new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
} else {
- final List<AudioPlaybackConfiguration> configsPublic;
- synchronized (mPlayerLock) {
- configsPublic = anonymizeForPublicConsumption(
+ return anonymizeForPublicConsumption(
new ArrayList<AudioPlaybackConfiguration>(mPlayers.values()));
- }
- return configsPublic;
}
}
}
-
/**
* Inner class to track clients that want to be notified of playback updates
*/
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 060534507c5d..3ba307be2311 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -22,6 +22,7 @@ import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
+import android.app.role.RoleManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -64,6 +65,8 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
private static final int LOCAL_LOG_SIZE = 20;
private static final String TAG = "BugreportManagerService";
private static final boolean DEBUG = false;
+ private static final String ROLE_SYSTEM_AUTOMOTIVE_PROJECTION =
+ "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION";
private static final String BUGREPORT_SERVICE = "bugreportd";
private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
@@ -326,11 +329,22 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
// To gain access through the DUMP permission, the OEM has to allow this package explicitly
// via sysconfig and privileged permissions.
- if (mBugreportAllowlistedPackages.contains(callingPackage)
- && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- == PackageManager.PERMISSION_GRANTED) {
+ boolean allowlisted = mBugreportAllowlistedPackages.contains(callingPackage);
+ if (!allowlisted) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ allowlisted = mContext.getSystemService(RoleManager.class).getRoleHolders(
+ ROLE_SYSTEM_AUTOMOTIVE_PROJECTION).contains(callingPackage);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ if (allowlisted && mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.DUMP) == PackageManager.PERMISSION_GRANTED) {
return;
}
+
// For carrier privileges, this can include user-installed apps. This is essentially a
// function of the current active SIM(s) in the device to let carrier apps through.
final long token = Binder.clearCallingIdentity();
@@ -346,7 +360,8 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
String message =
callingPackage
- + " does not hold the DUMP permission or is not bugreport-whitelisted "
+ + " does not hold the DUMP permission or is not bugreport-whitelisted or "
+ + "does not have an allowed role "
+ (checkCarrierPrivileges ? "and does not have carrier privileges " : "")
+ "to request a bugreport";
Slog.w(TAG, message);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 710e0b72ecfb..dd434fbeecb4 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -37,6 +37,7 @@ import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentProvider;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -1927,11 +1928,32 @@ public class ShortcutService extends IShortcutService.Stub {
}
if (shortcut.getIcon() != null) {
ShortcutInfo.validateIcon(shortcut.getIcon());
+ validateIconURI(shortcut);
}
shortcut.replaceFlags(shortcut.getFlags() & ShortcutInfo.FLAG_LONG_LIVED);
}
+ // Validates the calling process has permission to access shortcut icon's image uri
+ private void validateIconURI(@NonNull final ShortcutInfo si) {
+ final int callingUid = injectBinderCallingUid();
+ final Icon icon = si.getIcon();
+ if (icon == null) {
+ // There's no icon in this shortcut, nothing to validate here.
+ return;
+ }
+ int iconType = icon.getType();
+ if (iconType != Icon.TYPE_URI && iconType != Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ // The icon is not URI-based, nothing to validate.
+ return;
+ }
+ final Uri uri = icon.getUri();
+ mUriGrantsManagerInternal.checkGrantUriPermission(callingUid, si.getPackage(),
+ ContentProvider.getUriWithoutUserId(uri),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(callingUid)));
+ }
+
private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
fixUpIncomingShortcutInfo(shortcut, forUpdate, /*forPinRequest=*/ false);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e93f35802953..62273b5bc445 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -226,6 +226,7 @@ import static com.android.server.wm.IdentifierProto.USER_ID;
import static com.android.server.wm.LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
@@ -2676,7 +2677,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private boolean transferSplashScreenIfNeeded() {
if (finishing || !mHandleExitSplashScreen || mStartingSurface == null
|| mStartingWindow == null
- || mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH) {
+ || mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH
+ // skip copy splash screen to client if it was resized
+ || (mStartingData != null && mStartingData.mResizedFromTransfer)) {
return false;
}
if (isTransferringSplashScreen()) {
@@ -7632,7 +7635,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
void prepareSurfaces() {
final boolean show = isVisible() || isAnimating(PARENTS,
- ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS);
+ ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS
+ | ANIMATION_TYPE_PREDICT_BACK);
if (mSurfaceControl != null) {
if (show && !mLastSurfaceShowing) {
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 0c196d7e99e9..976641b52a16 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -26,7 +26,9 @@ import static android.view.WindowManager.TRANSIT_TO_BACK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
import static com.android.server.wm.BackNavigationProto.ANIMATION_IN_PROGRESS;
+import static com.android.server.wm.BackNavigationProto.ANIMATION_RUNNING;
import static com.android.server.wm.BackNavigationProto.LAST_BACK_TYPE;
+import static com.android.server.wm.BackNavigationProto.MAIN_OPEN_ACTIVITY;
import static com.android.server.wm.BackNavigationProto.SHOW_WALLPAPER;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK;
@@ -50,6 +52,7 @@ import android.view.WindowInsets;
import android.window.BackAnimationAdapter;
import android.window.BackNavigationInfo;
import android.window.IBackAnimationFinishedCallback;
+import android.window.IWindowlessStartingSurfaceCallback;
import android.window.OnBackInvokedCallbackInfo;
import android.window.TaskSnapshot;
@@ -73,6 +76,8 @@ class BackNavigationController {
private @BackNavigationInfo.BackTargetType int mLastBackType;
private boolean mShowWallpaper;
private Runnable mPendingAnimation;
+
+ private boolean mBackAnimationRunning;
private final NavigationMonitor mNavigationMonitor = new NavigationMonitor();
private AnimationHandler mAnimationHandler;
@@ -474,7 +479,7 @@ class BackNavigationController {
final ActivityRecord ar = openApps.valueAt(i);
if (mAnimationHandler.isTarget(ar, true /* open */)) {
openApps.removeAt(i);
- mAnimationHandler.mOpenTransitionTargetMatch = true;
+ mAnimationHandler.markStartingSurfaceMatch();
}
}
for (int i = closeApps.size() - 1; i >= 0; --i) {
@@ -583,8 +588,9 @@ class BackNavigationController {
* The closing target should only exist in close list, but the opening target can be either in
* open or close list.
*/
- void onTransactionReady(Transition transition, ArrayList<Transition.ChangeInfo> targets) {
- if (!isMonitoringTransition()) {
+ void onTransactionReady(Transition transition, ArrayList<Transition.ChangeInfo> targets,
+ SurfaceControl.Transaction startTransaction) {
+ if (!isMonitoringTransition() || targets.isEmpty()) {
return;
}
for (int i = targets.size() - 1; i >= 0; --i) {
@@ -613,6 +619,17 @@ class BackNavigationController {
Slog.e(TAG, "Gesture animation is applied on another transition?");
}
mWaitTransitionFinish = transition;
+ // Flag target matches to defer remove the splash screen.
+ for (int i = mTmpOpenApps.size() - 1; i >= 0; --i) {
+ final WindowContainer wc = mTmpOpenApps.get(i);
+ if (mAnimationHandler.isTarget(wc, true /* open */)) {
+ mAnimationHandler.markStartingSurfaceMatch();
+ break;
+ }
+ }
+ // Because the target will reparent to transition root, so it cannot be controlled by
+ // animation leash. Hide the close target when transition starts.
+ startTransaction.hide(mAnimationHandler.mCloseAdaptor.mTarget.getSurfaceControl());
}
mTmpOpenApps.clear();
mTmpCloseApps.clear();
@@ -633,6 +650,7 @@ class BackNavigationController {
mAnimationHandler.clearBackAnimateTarget();
mNavigationMonitor.stopMonitorTransition();
mWaitTransitionFinish = null;
+ mBackAnimationRunning = false;
}
/**
@@ -717,11 +735,7 @@ class BackNavigationController {
// This will be set before transition happen, to know whether the real opening target
// exactly match animating target. When target match, reparent the starting surface to
// the opening target like starting window do.
- private boolean mOpenTransitionTargetMatch;
- // The starting surface task Id. Used to clear the starting surface if the animation has
- // request one during animating.
- private int mRequestedStartingSurfaceTaskId;
- private SurfaceControl mStartingSurface;
+ private boolean mStartingSurfaceTargetMatch;
private ActivityRecord mOpenActivity;
AnimationHandler(WindowManagerService wms) {
@@ -765,8 +779,8 @@ class BackNavigationController {
return;
}
- mCloseAdaptor = createAdaptor(closeTarget, false /* isOpen */);
- mOpenAdaptor = createAdaptor(open, true /* isOpen */);
+ mCloseAdaptor = createAdaptor(closeTarget, false, mSwitchType);
+ mOpenAdaptor = createAdaptor(open, true, mSwitchType);
mOpenActivity = openActivity;
if (mCloseAdaptor.mAnimationTarget == null || mOpenAdaptor.mAnimationTarget == null) {
Slog.w(TAG, "composeNewAnimations fail, skip");
@@ -774,8 +788,8 @@ class BackNavigationController {
}
}
- boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open,
- ActivityRecord openActivity) {
+ private boolean composeAnimations(@NonNull WindowContainer close,
+ @NonNull WindowContainer open, ActivityRecord openActivity) {
if (mComposed || mWaitTransition) {
Slog.e(TAG, "Previous animation is running " + this);
return false;
@@ -805,28 +819,6 @@ class BackNavigationController {
.isSupportWindowlessStartingSurface();
}
- void createStartingSurface(TaskSnapshot snapshot) {
- if (!mComposed) {
- return;
- }
-
- final ActivityRecord topActivity = getTopOpenActivity();
- if (topActivity == null) {
- Slog.e(TAG, "createStartingSurface fail, no open activity: " + this);
- return;
- }
- // TODO (b/257857570) draw snapshot by starting surface.
- }
-
- private ActivityRecord getTopOpenActivity() {
- if (mSwitchType == ACTIVITY_SWITCH) {
- return mOpenAdaptor.mTarget.asActivityRecord();
- } else if (mSwitchType == TASK_SWITCH) {
- return mOpenAdaptor.mTarget.asTask().getTopNonFinishingActivity();
- }
- return null;
- }
-
boolean containTarget(ArrayList<WindowContainer> wcs, boolean open) {
for (int i = wcs.size() - 1; i >= 0; --i) {
if (isTarget(wcs.get(i), open)) {
@@ -860,13 +852,13 @@ class BackNavigationController {
if (!mComposed) {
return;
}
- cleanUpWindowlessSurface();
if (mCloseAdaptor != null) {
mCloseAdaptor.mTarget.cancelAnimation();
mCloseAdaptor = null;
}
if (mOpenAdaptor != null) {
+ mOpenAdaptor.cleanUpWindowlessSurface(mStartingSurfaceTargetMatch);
mOpenAdaptor.mTarget.cancelAnimation();
mOpenAdaptor = null;
}
@@ -875,36 +867,16 @@ class BackNavigationController {
}
}
- private void cleanUpWindowlessSurface() {
- final ActivityRecord ar = getTopOpenActivity();
- if (ar == null) {
- Slog.w(TAG, "finishPresentAnimations without top activity: " + this);
- }
- final SurfaceControl.Transaction pendingT = ar != null ? ar.getPendingTransaction()
- : mOpenAdaptor.mTarget.getPendingTransaction();
- // ensure open target is visible before cancel animation.
- mOpenTransitionTargetMatch &= ar != null;
- if (mOpenTransitionTargetMatch) {
- pendingT.show(ar.getSurfaceControl());
- }
- if (mRequestedStartingSurfaceTaskId != 0) {
- // If open target match, reparent to open activity
- if (mStartingSurface != null && mOpenTransitionTargetMatch) {
- pendingT.reparent(mStartingSurface, ar.getSurfaceControl());
- }
- // remove starting surface.
- mStartingSurface = null;
- // TODO (b/257857570) draw snapshot by starting surface.
- mRequestedStartingSurfaceTaskId = 0;
- }
+ void markStartingSurfaceMatch() {
+ mStartingSurfaceTargetMatch = true;
+ mOpenAdaptor.reparentWindowlessSurfaceToTarget();
}
void clearBackAnimateTarget() {
finishPresentAnimations();
mComposed = false;
mWaitTransition = false;
- mOpenTransitionTargetMatch = false;
- mRequestedStartingSurfaceTaskId = 0;
+ mStartingSurfaceTargetMatch = false;
mSwitchType = UNKNOWN;
mOpenActivity = null;
}
@@ -935,9 +907,9 @@ class BackNavigationController {
}
private static BackWindowAnimationAdaptor createAdaptor(
- WindowContainer target, boolean isOpen) {
+ WindowContainer target, boolean isOpen, int switchType) {
final BackWindowAnimationAdaptor adaptor =
- new BackWindowAnimationAdaptor(target, isOpen);
+ new BackWindowAnimationAdaptor(target, isOpen, switchType);
final SurfaceControl.Transaction pt = target.getPendingTransaction();
target.startAnimation(pt, adaptor, false /* hidden */, ANIMATION_TYPE_PREDICT_BACK);
// Workaround to show TaskFragment which can be hide in Transitions and won't show
@@ -957,11 +929,19 @@ class BackNavigationController {
private final WindowContainer mTarget;
private final boolean mIsOpen;
private RemoteAnimationTarget mAnimationTarget;
+ private final int mSwitchType;
- BackWindowAnimationAdaptor(WindowContainer closeTarget, boolean isOpen) {
- mBounds.set(closeTarget.getBounds());
- mTarget = closeTarget;
+ // The starting surface task Id. Used to clear the starting surface if the animation has
+ // requested one during animating.
+ private int mRequestedStartingSurfaceId = INVALID_TASK_ID;
+ private SurfaceControl mStartingSurface;
+
+ BackWindowAnimationAdaptor(WindowContainer target, boolean isOpen,
+ int switchType) {
+ mBounds.set(target.getBounds());
+ mTarget = target;
mIsOpen = isOpen;
+ mSwitchType = switchType;
}
@Override
public boolean getShowWallpaper() {
@@ -979,6 +959,8 @@ class BackNavigationController {
public void onAnimationCancelled(SurfaceControl animationLeash) {
if (mCapturedLeash == animationLeash) {
mCapturedLeash = null;
+ mRequestedStartingSurfaceId = INVALID_TASK_ID;
+ mStartingSurface = null;
}
}
@@ -1009,8 +991,15 @@ class BackNavigationController {
return mAnimationTarget;
}
Task t = mTarget.asTask();
- final ActivityRecord r = t != null ? t.getTopNonFinishingActivity()
- : mTarget.asActivityRecord();
+ ActivityRecord r = null;
+ if (t == null && mTarget.asTaskFragment() != null) {
+ t = mTarget.asTaskFragment().getTask();
+ r = mTarget.asTaskFragment().getTopNonFinishingActivity();
+ }
+ if (r == null) {
+ r = t != null ? t.getTopNonFinishingActivity()
+ : mTarget.asActivityRecord();
+ }
if (t == null && r != null) {
t = r.getTask();
}
@@ -1037,6 +1026,77 @@ class BackNavigationController {
r.checkEnterPictureInPictureAppOpsState());
return mAnimationTarget;
}
+
+ void createStartingSurface() {
+ if (!mIsOpen) {
+ return;
+ }
+ final Task openTask = mSwitchType == TASK_SWITCH
+ ? mTarget.asTask() : mSwitchType == ACTIVITY_SWITCH
+ ? mTarget.asActivityRecord().getTask() : null;
+ if (openTask == null) {
+ return;
+ }
+ final ActivityRecord mainActivity = mSwitchType == ACTIVITY_SWITCH
+ ? mTarget.asActivityRecord()
+ : openTask.getTopNonFinishingActivity();
+ if (mainActivity == null) {
+ return;
+ }
+ final TaskSnapshot snapshot = getSnapshot(mTarget);
+ mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController
+ .addWindowlessStartingSurface(openTask, mainActivity,
+ mAnimationTarget.leash, snapshot,
+ new IWindowlessStartingSurfaceCallback.Stub() {
+ // Once the starting surface has been created in shell, it will call
+ // onSurfaceAdded to pass the created surface to core, so if a
+ // transition is triggered by the back gesture, there doesn't need to
+ // create another starting surface for the opening target, just reparent
+ // the starting surface to the opening target.
+ // Note if cleanUpWindowlessSurface happen prior than onSurfaceAdded
+ // called, there won't be able to reparent the starting surface on
+ // opening target. But if that happens and transition target is matched,
+ // the app window should already draw.
+ @Override
+ public void onSurfaceAdded(SurfaceControl sc) {
+ synchronized (mTarget.mWmService.mGlobalLock) {
+ if (mRequestedStartingSurfaceId != INVALID_TASK_ID) {
+ mStartingSurface = sc;
+ }
+ }
+ }
+ });
+ }
+
+ // When back gesture has triggered and transition target matches navigation target,
+ // reparent the starting surface to the opening target as it's starting window.
+ void reparentWindowlessSurfaceToTarget() {
+ if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
+ return;
+ }
+ // If open target matches, reparent to open activity or task
+ if (mStartingSurface != null && mStartingSurface.isValid()) {
+ mTarget.getPendingTransaction()
+ .reparent(mStartingSurface, mTarget.getSurfaceControl());
+ // remove starting surface.
+ mStartingSurface = null;
+ }
+ }
+
+ /**
+ * Ask shell to clear the starting surface.
+ * @param openTransitionMatch if true, shell will play the remove starting window
+ * animation, otherwise remove it directly.
+ */
+ void cleanUpWindowlessSurface(boolean openTransitionMatch) {
+ if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
+ return;
+ }
+ mTarget.mWmService.mAtmService.mTaskOrganizerController
+ .removeWindowlessStartingSurface(mRequestedStartingSurfaceId,
+ !openTransitionMatch);
+ mRequestedStartingSurfaceId = INVALID_TASK_ID;
+ }
}
ScheduleAnimationBuilder prepareAnimation(int backType, BackAnimationAdapter adapter,
@@ -1089,15 +1149,13 @@ class BackNavigationController {
/**
* Apply preview strategy on the opening target
- * @param open The opening target.
+ * @param openAnimationAdaptor The animator who can create starting surface.
* @param visibleOpenActivity The visible activity in opening target.
- * @return If the preview strategy is launch behind, returns the Activity that has
- * launchBehind set, or null otherwise.
*/
- private void applyPreviewStrategy(WindowContainer open,
+ private void applyPreviewStrategy(BackWindowAnimationAdaptor openAnimationAdaptor,
ActivityRecord visibleOpenActivity) {
if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) {
- createStartingSurface(getSnapshot(open));
+ openAnimationAdaptor.createStartingSurface();
return;
}
setLaunchBehind(visibleOpenActivity);
@@ -1119,7 +1177,7 @@ class BackNavigationController {
if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) {
return null;
}
- applyPreviewStrategy(mOpenTarget, openActivity);
+ applyPreviewStrategy(mOpenAdaptor, openActivity);
final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback();
final RemoteAnimationTarget[] targets = getAnimationTargets();
@@ -1220,6 +1278,7 @@ class BackNavigationController {
if (mPendingAnimation != null) {
mPendingAnimation.run();
mPendingAnimation = null;
+ mBackAnimationRunning = true;
}
}
@@ -1236,9 +1295,6 @@ class BackNavigationController {
}
static TaskSnapshot getSnapshot(@NonNull WindowContainer w) {
- if (!isScreenshotEnabled()) {
- return null;
- }
if (w.asTask() != null) {
final Task task = w.asTask();
return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot(
@@ -1247,8 +1303,8 @@ class BackNavigationController {
}
if (w.asActivityRecord() != null) {
- // TODO (b/259497289) return TaskSnapshot when feature complete.
- return null;
+ final ActivityRecord ar = w.asActivityRecord();
+ return ar.mWmService.mSnapshotController.mActivitySnapshotController.getSnapshot(ar);
}
return null;
}
@@ -1270,6 +1326,12 @@ class BackNavigationController {
proto.write(ANIMATION_IN_PROGRESS, mBackAnimationInProgress);
proto.write(LAST_BACK_TYPE, mLastBackType);
proto.write(SHOW_WALLPAPER, mShowWallpaper);
+ if (mAnimationHandler.mOpenActivity != null) {
+ mAnimationHandler.mOpenActivity.writeNameToProto(proto, MAIN_OPEN_ACTIVITY);
+ } else {
+ proto.write(MAIN_OPEN_ACTIVITY, "");
+ }
+ proto.write(ANIMATION_RUNNING, mBackAnimationRunning);
proto.end(token);
}
}
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index cff86add7efc..2b22d75693fe 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -38,6 +38,10 @@ public abstract class StartingData {
*/
Task mAssociatedTask;
+
+ /** Whether the starting window is resized from transfer across activities. */
+ boolean mResizedFromTransfer;
+
/** Whether the starting window is drawn. */
boolean mIsDisplayed;
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index cdb4ad645dc3..b72d02789114 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -790,12 +790,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
boolean isSupportWindowlessStartingSurface() {
- // Enable after ag/20426257
final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
- if (lastOrganizer == null) {
- return false;
- }
- return false;
+ return lastOrganizer != null;
}
/**
* Notify the shell ({@link com.android.wm.shell.ShellTaskOrganizer} that the client has
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index b7c8092e3774..f33af5efb691 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1499,7 +1499,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
mTargets = calculateTargets(mParticipants, mChanges);
// Check whether the participants were animated from back navigation.
- mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets);
+ mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets,
+ transaction);
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);
info.setDebugId(mSyncId);
mController.assignTrack(this, info);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 140255b2f016..b2a2452f1123 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1935,7 +1935,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
final ActivityRecord atoken = mActivityRecord;
if (atoken != null) {
- return ((!isParentWindowHidden() && atoken.isVisible())
+ final boolean isVisible = isStartingWindowAssociatedToTask()
+ ? mStartingData.mAssociatedTask.isVisible() : atoken.isVisible();
+ return ((!isParentWindowHidden() && isVisible)
|| isAnimationRunningSelfOrParent());
}
final WallpaperWindowToken wtoken = mToken.asWallpaperToken();
@@ -2330,6 +2332,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// IME surface association. (e.g. Attach IME surface on the display instead of the
// app when the app bounds being letterboxed.)
mDisplayContent.updateImeControlTarget(isImeLayeringTarget() /* updateImeParent */);
+ // Fix the starting window to task when Activity has changed.
+ if (mStartingData != null && mStartingData.mAssociatedTask == null
+ && !mTempConfiguration.windowConfiguration.getBounds().equals(getBounds())) {
+ mStartingData.mResizedFromTransfer = true;
+ // Lock the starting window to task, so it won't resize from transfer anymore.
+ mActivityRecord.associateStartingWindowWithTaskIfNeeded();
+ }
}
}
@@ -3902,7 +3911,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* LetterboxUiController#shouldShowLetterboxUi} for more context.
*/
boolean areAppWindowBoundsLetterboxed() {
- return mActivityRecord != null
+ return mActivityRecord != null && !isStartingWindowAssociatedToTask()
&& (mActivityRecord.areBoundsLetterboxed() || isLetterboxedForDisplayCutout());
}
@@ -5668,6 +5677,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// TODO(b/233286785): Add sync support to wallpaper.
return true;
}
+ if (mActivityRecord != null && mViewVisibility != View.VISIBLE
+ && mWinAnimator.mAttrType != TYPE_BASE_APPLICATION
+ && mWinAnimator.mAttrType != TYPE_APPLICATION_STARTING) {
+ // Skip sync for invisible app windows which are not managed by activity lifecycle.
+ return false;
+ }
// In the WindowContainer implementation we immediately mark ready
// since a generic WindowContainer only needs to wait for its
// children to finish and is immediately ready from its own
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 35b9bc3b1e06..4a8d73d23904 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -254,12 +254,45 @@ public final class PrintManagerService extends SystemService {
}
final long identity = Binder.clearCallingIdentity();
try {
- return userState.getCustomPrinterIcon(printerId);
+ Icon icon = userState.getCustomPrinterIcon(printerId);
+ return validateIconUserBoundary(icon);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ /**
+ * Validates the custom printer icon to see if it's not in the calling user space.
+ * If the condition is not met, return null. Otherwise, return the original icon.
+ *
+ * @param icon
+ * @return icon (validated)
+ */
+ private Icon validateIconUserBoundary(Icon icon) {
+ // Refer to Icon#getUriString for context. The URI string is invalid for icons of
+ // incompatible types.
+ if (icon != null && (icon.getType() == Icon.TYPE_URI
+ || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
+ String encodedUser = icon.getUri().getEncodedUserInfo();
+
+ // If there is no encoded user, the URI is calling into the calling user space
+ if (encodedUser != null) {
+ int userId = Integer.parseInt(encodedUser);
+ // resolve encoded user
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+
+ synchronized (mLock) {
+ // Only the current group members can get the printer icons.
+ if (resolveCallingProfileParentLocked(resolvedUserId)
+ != getCurrentUserId()) {
+ return null;
+ }
+ }
+ }
+ }
+ return icon;
+ }
+
@Override
public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
if (printJobId == null) {
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 107dde244940..fa0a9713fec0 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -110,6 +110,7 @@
<uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB" />
<uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
<uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
+ <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
<queries>
<package android:name="com.android.servicestests.apps.suspendtestapp" />
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 8884dba217ed..2336374a3c5b 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -789,13 +789,6 @@ public class VirtualDeviceManagerServiceTest {
}
@Test
- public void onVirtualDisplayRemovedLocked_unknownDisplayId_throwsException() {
- final int unknownDisplayId = 999;
- assertThrows(IllegalStateException.class,
- () -> mDeviceImpl.onVirtualDisplayRemoved(unknownDisplayId));
- }
-
- @Test
public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException {
addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index 52c6777b70af..24029b1113ea 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -16,15 +16,18 @@
package com.android.server.os;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import android.app.role.RoleManager;
import android.content.Context;
import android.os.Binder;
import android.os.BugreportManager.BugreportCallback;
import android.os.IBinder;
import android.os.IDumpstateListener;
+import android.os.Process;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Pair;
@@ -37,21 +40,23 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.FileDescriptor;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
public class BugreportManagerServiceImplTest {
- Context mContext;
- BugreportManagerServiceImpl mService;
- BugreportManagerServiceImpl.BugreportFileManager mBugreportFileManager;
+ private Context mContext;
+ private BugreportManagerServiceImpl mService;
+ private BugreportManagerServiceImpl.BugreportFileManager mBugreportFileManager;
- int mCallingUid = 1234;
- String mCallingPackage = "test.package";
+ private int mCallingUid = 1234;
+ private String mCallingPackage = "test.package";
- String mBugreportFile = "bugreport-file.zip";
- String mBugreportFile2 = "bugreport-file2.zip";
+ private String mBugreportFile = "bugreport-file.zip";
+ private String mBugreportFile2 = "bugreport-file2.zip";
@Before
public void setUp() {
@@ -109,6 +114,36 @@ public class BugreportManagerServiceImplTest {
BugreportCallback.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
}
+ @Test
+ public void testCancelBugreportWithoutRole() throws Exception {
+ // Clear out allowlisted packages.
+ mService = new BugreportManagerServiceImpl(
+ new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>()));
+
+ assertThrows(SecurityException.class, () -> mService.cancelBugreport(
+ Binder.getCallingUid(), mContext.getPackageName()));
+ }
+
+ @Test
+ public void testCancelBugreportWithRole() throws Exception {
+ // Clear out allowlisted packages.
+ mService = new BugreportManagerServiceImpl(
+ new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>()));
+ RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+ CallbackFuture future = new CallbackFuture();
+ runWithShellPermissionIdentity(() -> roleManager.setBypassingRoleQualification(true));
+ runWithShellPermissionIdentity(() -> roleManager.addRoleHolderAsUser(
+ "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
+ mContext.getPackageName(),
+ /* flags= */ 0,
+ Process.myUserHandle(),
+ mContext.getMainExecutor(),
+ future));
+
+ assertThat(future.get()).isEqualTo(true);
+ mService.cancelBugreport(Binder.getCallingUid(), mContext.getPackageName());
+ }
+
private static class Listener implements IDumpstateListener {
CountDownLatch mLatch;
int mErrorCode;
@@ -149,4 +184,12 @@ public class BugreportManagerServiceImplTest {
return mErrorCode;
}
}
+
+ private static class CallbackFuture extends CompletableFuture<Boolean>
+ implements Consumer<Boolean> {
+ @Override
+ public void accept(Boolean successful) {
+ complete(successful);
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 6d7f2c13197c..1c86758f28ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -570,6 +570,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
final ContextWrapper contextSpy = Mockito.spy(new ContextWrapper(mWm.mContext));
final Resources resourcesSpy = Mockito.spy(contextSpy.getResources());
+ spyOn(mAtm.mTaskOrganizerController);
when(contextSpy.getResources()).thenReturn(resourcesSpy);
MockitoSession mockitoSession = mockitoSession().mockStatic(BackNavigationController.class)
@@ -597,7 +598,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
mBackAnimationAdapter, task, mRootHomeTask, bottomActivity, homeActivity);
assertTrue(toHomeBuilder.mIsLaunchBehind);
toHomeBuilder.build();
- verify(animationHandler, never()).createStartingSurface(any());
+ verify(mAtm.mTaskOrganizerController, never())
+ .addWindowlessStartingSurface(any(), any(), any(), any(), any());
animationHandler.clearBackAnimateTarget();
// Back to ACTIVITY and TASK have the same logic, just with different target.
@@ -609,9 +611,11 @@ public class BackNavigationControllerTests extends WindowTestsBase {
assertFalse(toActivityBuilder.mIsLaunchBehind);
toActivityBuilder.build();
if (preferWindowlessSurface) {
- verify(animationHandler).createStartingSurface(any());
+ verify(mAtm.mTaskOrganizerController)
+ .addWindowlessStartingSurface(any(), any(), any(), any(), any());
} else {
- verify(animationHandler, never()).createStartingSurface(any());
+ verify(mAtm.mTaskOrganizerController, never())
+ .addWindowlessStartingSurface(any(), any(), any(), any(), any());
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 997015ff1c08..b3db2dea4a27 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -365,7 +365,7 @@ public class SoundTriggerService extends SystemService {
// Validate package name
try {
int uid = mPackageManager.getPackageUid(mOriginatorIdentity.packageName,
- PackageManager.PackageInfoFlags.of(0));
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ANY_USER));
if (!UserHandle.isSameApp(uid, mOriginatorIdentity.uid)) {
throw new SecurityException("Uid " + mOriginatorIdentity.uid +
" attempted to spoof package name " +
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index feef0497c152..d41c0197addc 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -81,6 +81,19 @@ public class SharedConnectivityManager {
mCallback = callback;
}
+ @Override
+ public void onServiceConnected() {
+ if (mCallback != null) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onServiceConnected());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override
public void onHotspotNetworksUpdated(@NonNull List<HotspotNetwork> networks) {
if (mCallback != null) {
final long token = Binder.clearCallingIdentity();
@@ -117,6 +130,7 @@ public class SharedConnectivityManager {
}
}
+ @Override
public void onHotspotNetworkConnectionStatusChanged(
@NonNull HotspotNetworkConnectionStatus status) {
if (mCallback != null) {
@@ -251,7 +265,6 @@ public class SharedConnectivityManager {
synchronized (mProxyDataLock) {
mProxyMap.put(callback, proxy);
}
- callback.onServiceConnected();
} catch (RemoteException e) {
Log.e(TAG, "Exception in registerCallback", e);
callback.onRegisterCallbackFailed(e);
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl
index 737aa6d9964c..521f94367f6f 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl
@@ -31,4 +31,5 @@ interface ISharedConnectivityCallback {
oneway void onKnownNetworksUpdated(in List<KnownNetwork> networks);
oneway void onKnownNetworkConnectionStatusChanged(in KnownNetworkConnectionStatus status);
oneway void onSharedConnectivitySettingsChanged(in SharedConnectivitySettingsState state);
+ oneway void onServiceConnected();
}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
index 2bbe91958383..ebda6f1c5826 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
@@ -276,6 +276,11 @@ public abstract class SharedConnectivityService extends Service {
private void onRegisterCallback(ISharedConnectivityCallback callback) {
mRemoteCallbackList.register(callback);
+ try {
+ callback.onServiceConnected();
+ } catch (RemoteException e) {
+ if (DEBUG) Log.w(TAG, "Exception in onRegisterCallback", e);
+ }
if (mCountDownLatch != null) {
mCountDownLatch.countDown();
}