diff options
26 files changed, 460 insertions, 34 deletions
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index c1c96eaa098d..014e4660f944 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -285,6 +285,14 @@ public class WallpaperManager { public static final String COMMAND_UNFREEZE = "android.wallpaper.unfreeze"; /** + * Command for {@link #sendWallpaperCommand}: in sendWallpaperCommand put extra to this command + * to give the bounds of space between the bottom of notifications and the top of shortcuts + * @hide + */ + public static final String COMMAND_LOCKSCREEN_LAYOUT_CHANGED = + "android.wallpaper.lockscreen_layout_changed"; + + /** * Extra passed back from setWallpaper() giving the new wallpaper's assigned ID. * @hide */ diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index c6238e848070..1f5d0f512836 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1483,3 +1483,11 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "magic_portrait_wallpapers" + namespace: "systemui" + description: "Magic Portrait related changes in systemui" + bug: "370863642" +} + diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt index fe5024fdc0a3..59676ce126da 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt @@ -17,10 +17,17 @@ package com.android.systemui.wallpapers.data.repository import android.app.WallpaperInfo +import android.view.View import kotlinx.coroutines.flow.MutableStateFlow /** Fake implementation of the wallpaper repository. */ class FakeWallpaperRepository : WallpaperRepository { override val wallpaperInfo = MutableStateFlow<WallpaperInfo?>(null) override val wallpaperSupportsAmbientMode = MutableStateFlow(false) + override var rootView: View? = null + private val _notificationStackAbsoluteBottom = MutableStateFlow(0F) + + override fun setNotificationStackAbsoluteBottom(bottom: Float) { + _notificationStackAbsoluteBottom.value = bottom + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt index ec52055020f2..95d1b5d7fcac 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt @@ -68,11 +68,16 @@ interface KeyguardClockRepository { val previewClock: Flow<ClockController> + /** top of notifications without bcsmartspace in small clock settings */ + val notificationDefaultTop: StateFlow<Float> + val clockEventController: ClockEventController val shouldForceSmallClock: Boolean fun setClockSize(size: ClockSize) + + fun setNotificationDefaultTop(top: Float) } @SysUISingleton @@ -108,7 +113,7 @@ constructor( .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = getClockSize() + initialValue = getClockSize(), ) override val currentClockId: Flow<ClockId> = @@ -138,7 +143,7 @@ constructor( .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = clockRegistry.createCurrentClock() + initialValue = clockRegistry.createCurrentClock(), ) override val previewClock: Flow<ClockController> = @@ -149,6 +154,14 @@ constructor( clockRegistry.createCurrentClock() } + private val _notificationDefaultTop: MutableStateFlow<Float> = MutableStateFlow(0F) + + override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow() + + override fun setNotificationDefaultTop(top: Float) { + _notificationDefaultTop.value = top + } + override val shouldForceSmallClock: Boolean get() = featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE) && @@ -160,7 +173,7 @@ constructor( secureSettings.getIntForUser( Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, /* defaultValue= */ 1, - UserHandle.USER_CURRENT + UserHandle.USER_CURRENT, ) ) } 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 130242f55600..821017418277 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 @@ -269,6 +269,9 @@ interface KeyguardRepository { */ val isEncryptedOrLockdown: Flow<Boolean> + /** The top of shortcut in screen, used by wallpaper to find remaining space in lockscreen */ + val shortcutAbsoluteTop: StateFlow<Float> + /** * Returns `true` if the keyguard is showing; `false` otherwise. * @@ -339,6 +342,8 @@ interface KeyguardRepository { * otherwise. */ fun isShowKeyguardWhenReenabled(): Boolean + + fun setShortcutAbsoluteTop(top: Float) } /** Encapsulates application state for the keyguard. */ @@ -503,7 +508,7 @@ constructor( trySendWithFailureLogging( statusBarStateController.dozeAmount, TAG, - "initial dozeAmount" + "initial dozeAmount", ) awaitClose { statusBarStateController.removeCallback(callback) } @@ -521,7 +526,7 @@ constructor( object : DozeTransitionCallback { override fun onDozeTransition( oldState: DozeMachine.State, - newState: DozeMachine.State + newState: DozeMachine.State, ) { trySendWithFailureLogging( DozeTransitionModel( @@ -529,7 +534,7 @@ constructor( to = dozeMachineStateToModel(newState), ), TAG, - "doze transition model" + "doze transition model", ) } } @@ -541,7 +546,7 @@ constructor( to = dozeMachineStateToModel(dozeTransitionListener.newState), ), TAG, - "initial doze transition model" + "initial doze transition model", ) awaitClose { dozeTransitionListener.removeCallback(callback) } @@ -579,7 +584,7 @@ constructor( trySendWithFailureLogging( statusBarStateIntToObject(state), TAG, - "state" + "state", ) } } @@ -590,7 +595,7 @@ constructor( .stateIn( scope, SharingStarted.Eagerly, - statusBarStateIntToObject(statusBarStateController.state) + statusBarStateIntToObject(statusBarStateController.state), ) private val _biometricUnlockState: MutableStateFlow<BiometricUnlockModel> = @@ -610,7 +615,7 @@ constructor( trySendWithFailureLogging( authController.fingerprintSensorLocation, TAG, - "AuthController.Callback#onFingerprintLocationChanged" + "AuthController.Callback#onFingerprintLocationChanged", ) } @@ -635,6 +640,9 @@ constructor( private val _isActiveDreamLockscreenHosted = MutableStateFlow(false) override val isActiveDreamLockscreenHosted = _isActiveDreamLockscreenHosted.asStateFlow() + private val _shortcutAbsoluteTop = MutableStateFlow(0F) + override val shortcutAbsoluteTop = _shortcutAbsoluteTop.asStateFlow() + init { val callback = object : KeyguardStateController.Callback { @@ -721,6 +729,10 @@ constructor( } } + override fun setShortcutAbsoluteTop(top: Float) { + _shortcutAbsoluteTop.value = top + } + private fun dozeMachineStateToModel(state: DozeMachine.State): DozeStateModel { return when (state) { DozeMachine.State.UNINITIALIZED -> DozeStateModel.UNINITIALIZED diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt index c0049d4e2e6c..5b7eeddfb8e1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt @@ -94,7 +94,7 @@ constructor( .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = ClockSize.LARGE + initialValue = ClockSize.LARGE, ) } else { keyguardClockRepository.clockSize @@ -152,4 +152,8 @@ constructor( clock.largeClock.animations.fold(foldFraction) } } + + fun setNotificationStackDefaultTop(top: Float) { + keyguardClockRepository.setNotificationDefaultTop(top) + } } 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 e6ee11215595..d7f96b55c4a3 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 @@ -526,6 +526,10 @@ constructor( repository.showDismissibleKeyguard() } + fun setShortcutAbsoluteTop(top: Float) { + repository.setShortcutAbsoluteTop(top) + } + companion object { private const val TAG = "KeyguardInteractor" } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt index a1c963b3137a..0b10c8a14633 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt @@ -44,6 +44,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFaceLayout import com.android.systemui.res.R +import com.android.systemui.shade.LargeScreenHeaderHelper import com.android.systemui.shared.R as sharedR import com.android.systemui.util.ui.value import dagger.Lazy @@ -70,6 +71,7 @@ constructor( val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>, private val rootViewModel: KeyguardRootViewModel, private val aodBurnInViewModel: AodBurnInViewModel, + private val largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>, ) : KeyguardSection() { private var disposableHandle: DisposableHandle? = null @@ -172,7 +174,7 @@ constructor( } } - open fun applyDefaultConstraints(constraints: ConstraintSet) { + fun applyDefaultConstraints(constraints: ConstraintSet) { val guideline = if (keyguardClockViewModel.clockShouldBeCentered.value) PARENT_ID else R.id.split_shade_guideline @@ -211,6 +213,28 @@ constructor( // Explicitly clear pivot to force recalculate pivot instead of using legacy value setTransformPivot(R.id.lockscreen_clock_view_large, Float.NaN, Float.NaN) + + val smallClockBottom = + keyguardClockViewModel.getSmallClockTopMargin() + + context.resources.getDimensionPixelSize( + com.android.systemui.customization.R.dimen.small_clock_height + ) + val dateWeatherSmartspaceHeight = getDimen(context, DATE_WEATHER_VIEW_HEIGHT).toFloat() + val marginBetweenSmartspaceAndNotification = + context.resources.getDimensionPixelSize( + R.dimen.keyguard_status_view_bottom_margin + ) + + if (context.resources.getBoolean(R.bool.config_use_large_screen_shade_header)) { + largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight() + } else { + 0 + } + + clockInteractor.setNotificationStackDefaultTop( + smallClockBottom + + dateWeatherSmartspaceHeight + + marginBetweenSmartspaceAndNotification + ) } constrainWeatherClockDateIconsBarrier(constraints) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt index 6c6e14cac84d..d3895def28e0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt @@ -30,6 +30,7 @@ import com.android.systemui.animation.view.LaunchableImageView import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.KeyguardBottomAreaRefactor import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel @@ -52,6 +53,7 @@ constructor( private val indicationController: KeyguardIndicationController, private val keyguardBlueprintInteractor: Lazy<KeyguardBlueprintInteractor>, private val keyguardQuickAffordanceViewBinder: KeyguardQuickAffordanceViewBinder, + private val keyguardInteractor: KeyguardInteractor, ) : BaseShortcutSection() { // Amount to increase the bottom margin by to avoid colliding with inset @@ -117,7 +119,7 @@ constructor( BOTTOM, PARENT_ID, BOTTOM, - verticalOffsetMargin + safeInsetBottom + verticalOffsetMargin + safeInsetBottom, ) constrainWidth(R.id.end_button, width) @@ -128,7 +130,7 @@ constructor( BOTTOM, PARENT_ID, BOTTOM, - verticalOffsetMargin + safeInsetBottom + verticalOffsetMargin + safeInsetBottom, ) // The constraint set visibility for start and end button are default visible, set to @@ -136,5 +138,13 @@ constructor( setVisibilityMode(R.id.start_button, VISIBILITY_MODE_IGNORE) setVisibilityMode(R.id.end_button, VISIBILITY_MODE_IGNORE) } + + val shortcutAbsoluteTopInScreen = + (resources.displayMetrics.heightPixels - + (verticalOffsetMargin + safeInsetBottom) - + height) + .toFloat() + + keyguardInteractor.setShortcutAbsoluteTop(shortcutAbsoluteTopInScreen) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index b466bf02387f..43989a85b045 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -129,6 +129,7 @@ import com.android.systemui.util.Assert; import com.android.systemui.util.ColorUtilKt; import com.android.systemui.util.DumpUtilsKt; import com.android.systemui.util.ListenerSet; +import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor; import com.google.errorprone.annotations.CompileTimeConstant; @@ -627,6 +628,9 @@ public class NotificationStackScrollLayout @Nullable private OnClickListener mManageButtonClickListener; + @Nullable + private WallpaperInteractor mWallpaperInteractor; + public NotificationStackScrollLayout(Context context, AttributeSet attrs) { super(context, attrs, 0, 0); Resources res = getResources(); @@ -1189,6 +1193,7 @@ public class NotificationStackScrollLayout if (!SceneContainerFlag.isEnabled()) { setMaxLayoutHeight(getHeight()); updateContentHeight(); + mWallpaperInteractor.setNotificationStackAbsoluteBottom(mContentHeight); } clampScrollPosition(); requestChildrenUpdate(); @@ -1248,6 +1253,7 @@ public class NotificationStackScrollLayout if (mAmbientState.getStackTop() != stackTop) { mAmbientState.setStackTop(stackTop); onTopPaddingChanged(/* animate = */ isAddOrRemoveAnimationPending()); + mWallpaperInteractor.setNotificationStackAbsoluteBottom((int) stackTop); } } @@ -5875,6 +5881,10 @@ public class NotificationStackScrollLayout mController.getNotificationRoundnessManager().setAnimatedChildren(mChildrenToAddAnimated); } + public void setWallpaperInteractor(WallpaperInteractor wallpaperInteractor) { + mWallpaperInteractor = wallpaperInteractor; + } + void addSwipedOutView(View v) { mSwipedOutViews.add(v); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 7b02d0cebfb3..00c5c40fc8ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -145,6 +145,7 @@ import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.tuner.TunerService; import com.android.systemui.util.Compile; import com.android.systemui.util.settings.SecureSettings; +import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor; import java.io.PrintWriter; import java.util.ArrayList; @@ -226,6 +227,8 @@ public class NotificationStackScrollLayoutController implements Dumpable { private final SensitiveNotificationProtectionController mSensitiveNotificationProtectionController; + private final WallpaperInteractor mWallpaperInteractor; + private View mLongPressedView; private final NotificationListContainerImpl mNotificationListContainer = @@ -756,7 +759,8 @@ public class NotificationStackScrollLayoutController implements Dumpable { NotificationDismissibilityProvider dismissibilityProvider, ActivityStarter activityStarter, SplitShadeStateController splitShadeStateController, - SensitiveNotificationProtectionController sensitiveNotificationProtectionController) { + SensitiveNotificationProtectionController sensitiveNotificationProtectionController, + WallpaperInteractor wallpaperInteractor) { mView = view; mKeyguardTransitionRepo = keyguardTransitionRepo; mViewBinder = viewBinder; @@ -812,6 +816,7 @@ public class NotificationStackScrollLayoutController implements Dumpable { mDismissibilityProvider = dismissibilityProvider; mActivityStarter = activityStarter; mSensitiveNotificationProtectionController = sensitiveNotificationProtectionController; + mWallpaperInteractor = wallpaperInteractor; mView.passSplitShadeStateController(splitShadeStateController); if (SceneContainerFlag.isEnabled()) { mWakeUpCoordinator.setStackScroller(this); @@ -948,6 +953,8 @@ public class NotificationStackScrollLayoutController implements Dumpable { collectFlow(mView, mKeyguardTransitionRepo.getTransitions(), this::onKeyguardTransitionChanged); } + + mView.setWallpaperInteractor(mWallpaperInteractor); } private boolean isInVisibleLocation(NotificationEntry entry) { diff --git a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt index 65a02184f96d..0744b5a0b18c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt +++ b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt @@ -32,19 +32,24 @@ private const val TAG = "WallpaperController" * Note: New logic should be added to [WallpaperRepository], not this class. */ @SysUISingleton -class WallpaperController @Inject constructor( +class WallpaperController +@Inject +constructor( private val wallpaperManager: WallpaperManager, private val wallpaperRepository: WallpaperRepository, ) { var rootView: View? = null + set(value) { + field = value + wallpaperRepository.rootView = value + } private var notificationShadeZoomOut: Float = 0f private var unfoldTransitionZoomOut: Float = 0f private val shouldUseDefaultUnfoldTransition: Boolean - get() = wallpaperRepository.wallpaperInfo.value?.shouldUseDefaultUnfoldTransition() - ?: true + get() = wallpaperRepository.wallpaperInfo.value?.shouldUseDefaultUnfoldTransition() ?: true fun setNotificationShadeZoom(zoomOut: Float) { notificationShadeZoomOut = zoomOut diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt index b45b8cd15bf5..54953c9c2574 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt @@ -17,6 +17,7 @@ package com.android.systemui.wallpapers.data.repository import android.app.WallpaperInfo +import android.view.View import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow @@ -33,4 +34,7 @@ import kotlinx.coroutines.flow.asStateFlow class NoopWallpaperRepository @Inject constructor() : WallpaperRepository { override val wallpaperInfo: StateFlow<WallpaperInfo?> = MutableStateFlow(null).asStateFlow() override val wallpaperSupportsAmbientMode = MutableStateFlow(false).asStateFlow() + override var rootView: View? = null + + override fun setNotificationStackAbsoluteBottom(bottom: Float) {} } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt index 041b6f963e27..203e1da2afcf 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt @@ -21,10 +21,16 @@ import android.app.WallpaperManager import android.content.Context import android.content.Intent import android.content.IntentFilter +import android.os.Bundle import android.os.UserHandle +import android.view.View +import androidx.annotation.VisibleForTesting +import com.android.systemui.Flags import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.keyguard.data.repository.KeyguardClockRepository +import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.user.data.model.SelectedUserModel import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.UserRepository @@ -32,16 +38,19 @@ import com.android.systemui.utils.coroutines.flow.mapLatestConflated import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** A repository storing information about the current wallpaper. */ @@ -51,6 +60,15 @@ interface WallpaperRepository { /** Emits true if the current user's current wallpaper supports ambient mode. */ val wallpaperSupportsAmbientMode: StateFlow<Boolean> + + /** Set rootView to get its windowToken afterwards */ + var rootView: View? + + /** + * Set bottom of notifications from notification stack, and Magic Portrait will layout base on + * this value + */ + fun setNotificationStackAbsoluteBottom(bottom: Float) } @SysUISingleton @@ -61,6 +79,8 @@ constructor( @Background private val bgDispatcher: CoroutineDispatcher, broadcastDispatcher: BroadcastDispatcher, userRepository: UserRepository, + keyguardRepository: KeyguardRepository, + keyguardClockRepository: KeyguardClockRepository, private val wallpaperManager: WallpaperManager, context: Context, ) : WallpaperRepository { @@ -69,10 +89,7 @@ constructor( private val wallpaperChanged: Flow<Unit> = broadcastDispatcher - .broadcastFlow( - IntentFilter(Intent.ACTION_WALLPAPER_CHANGED), - user = UserHandle.ALL, - ) + .broadcastFlow(IntentFilter(Intent.ACTION_WALLPAPER_CHANGED), user = UserHandle.ALL) // The `combine` defining `wallpaperSupportsAmbientMode` will not run until both of the // input flows emit at least once. Since this flow is an input flow, it needs to emit // when it starts up to ensure that the `combine` will run if the user changes before we @@ -87,6 +104,27 @@ constructor( // Only update the wallpaper status once the user selection has finished. .filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE } + /** The bottom of notification stack respect to the top of screen. */ + private val notificationStackAbsoluteBottom: MutableStateFlow<Float> = MutableStateFlow(0F) + + /** The top of shortcut respect to the top of screen. */ + private val shortcutAbsoluteTop: StateFlow<Float> = keyguardRepository.shortcutAbsoluteTop + + /** + * The top of notification stack to give a default state of lockscreen remaining space for + * states with notifications to compare with. It's the bottom of smartspace date and weather + * smartspace in small clock state, plus proper bottom margin. + */ + private val notificationStackDefaultTop = keyguardClockRepository.notificationDefaultTop + @VisibleForTesting var sendLockscreenLayoutJob: Job? = null + private val lockscreenRemainingSpaceWithNotification: Flow<Triple<Float, Float, Float>> = + combine( + notificationStackAbsoluteBottom, + notificationStackDefaultTop, + shortcutAbsoluteTop, + ::Triple, + ) + override val wallpaperInfo: StateFlow<WallpaperInfo?> = if (!wallpaperManager.isWallpaperSupported || !deviceSupportsAodWallpaper) { MutableStateFlow(null).asStateFlow() @@ -116,9 +154,70 @@ constructor( initialValue = wallpaperInfo.value?.supportsAmbientMode() == true, ) + override var rootView: View? = null + + val shouldSendNotificationLayout = + wallpaperInfo + .map { + val shouldSendNotificationLayout = shouldSendNotificationLayout(it) + if (shouldSendNotificationLayout) { + sendLockscreenLayoutJob = + scope.launch { + lockscreenRemainingSpaceWithNotification.collect { + (notificationBottom, notificationDefaultTop, shortcutTop) -> + wallpaperManager.sendWallpaperCommand( + /* windowToken = */ rootView?.windowToken, + /* action = */ WallpaperManager + .COMMAND_LOCKSCREEN_LAYOUT_CHANGED, + /* x = */ 0, + /* y = */ 0, + /* z = */ 0, + /* extras = */ Bundle().apply { + putFloat("screenLeft", 0F) + putFloat("smartspaceBottom", notificationDefaultTop) + putFloat("notificationBottom", notificationBottom) + putFloat( + "screenRight", + context.resources.displayMetrics.widthPixels.toFloat(), + ) + putFloat("shortCutTop", shortcutTop) + }, + ) + } + } + } else { + sendLockscreenLayoutJob?.cancel() + } + shouldSendNotificationLayout + } + .stateIn( + scope, + // Always be listening for wallpaper changes. + if (Flags.magicPortraitWallpapers()) SharingStarted.Eagerly + else SharingStarted.Lazily, + initialValue = false, + ) + + override fun setNotificationStackAbsoluteBottom(bottom: Float) { + notificationStackAbsoluteBottom.value = bottom + } + private suspend fun getWallpaper(selectedUser: SelectedUserModel): WallpaperInfo? { return withContext(bgDispatcher) { wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id) } } + + private fun shouldSendNotificationLayout(wallpaperInfo: WallpaperInfo?): Boolean { + return if (wallpaperInfo != null && wallpaperInfo.component != null) { + wallpaperInfo.component!!.className == MAGIC_PORTRAIT_CLASSNAME + } else { + false + } + } + + companion object { + const val MAGIC_PORTRAIT_CLASSNAME = + "com.google.android.apps.magicportrait.service.MagicPortraitWallpaperService" + } } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt new file mode 100644 index 000000000000..79ebf0128d02 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wallpapers.domain.interactor + +import com.android.systemui.wallpapers.data.repository.WallpaperRepository +import javax.inject.Inject + +class WallpaperInteractor @Inject constructor(val wallpaperRepository: WallpaperRepository) { + fun setNotificationStackAbsoluteBottom(bottom: Float) { + wallpaperRepository.setNotificationStackAbsoluteBottom(bottom) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt index 0b944f04a6a2..96a0aadacbc3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt @@ -39,13 +39,13 @@ import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.res.R +import com.android.systemui.shade.LargeScreenHeaderHelper import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor import com.android.systemui.statusbar.policy.fakeConfigurationController import com.android.systemui.statusbar.ui.fakeSystemBarUtilsProxy import com.android.systemui.testKosmos import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -57,6 +57,7 @@ import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.MockitoAnnotations +import org.mockito.kotlin.mock @OptIn(ExperimentalCoroutinesApi::class) @RunWith(AndroidJUnit4::class) @@ -122,6 +123,7 @@ class ClockSectionTest : SysuiTestCase() { { keyguardBlueprintInteractor }, keyguardRootViewModel, aodBurnInViewModel, + largeScreenHeaderHelperLazy = { mock<LargeScreenHeaderHelper>() }, ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index 7cd306ead027..6425da46fc67 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -83,6 +83,7 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.ColorUpdateLogger; import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.HeadsUpTouchHelper; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -103,7 +104,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback; import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder; import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; -import com.android.systemui.statusbar.notification.HeadsUpTouchHelper; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -113,6 +113,7 @@ import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionCont import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.tuner.TunerService; import com.android.systemui.util.settings.SecureSettings; +import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor; import org.junit.Before; import org.junit.Test; @@ -154,6 +155,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Mock private KeyguardBypassController mKeyguardBypassController; @Mock private PowerInteractor mPowerInteractor; @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor; + @Mock private WallpaperInteractor mWallpaperInteractor; @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager; @Mock private MetricsLogger mMetricsLogger; @Mock private ColorUpdateLogger mColorUpdateLogger; @@ -1070,7 +1072,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mock(NotificationDismissibilityProvider.class), mActivityStarter, new ResourcesSplitShadeStateController(), - mSensitiveNotificationProtectionController); + mSensitiveNotificationProtectionController, + mWallpaperInteractor); } static class LogMatcher implements ArgumentMatcher<LogMaker> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 8a3e5510b561..59fc0d157d54 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -102,6 +102,7 @@ import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.AvalancheController; import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController; +import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor; import kotlin.Unit; @@ -146,6 +147,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private NotificationStackScrollLayoutController mStackScrollLayoutController; @Mock private ScreenOffAnimationController mScreenOffAnimationController; @Mock private NotificationShelf mNotificationShelf; + @Mock private WallpaperInteractor mWallpaperInteractor; @Mock private NotificationStackSizeCalculator mStackSizeCalculator; @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator; @@ -208,6 +210,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { .thenReturn(mNotificationRoundnessManager); mStackScroller.setController(mStackScrollLayoutController); mStackScroller.setShelf(mNotificationShelf); + mStackScroller.setWallpaperInteractor(mWallpaperInteractor); when(mStackScroller.getExpandHelper()).thenReturn(mExpandHelper); doNothing().when(mGroupExpansionManager).collapseGroups(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt index bdecf2bdb53d..b8dd334dcad9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt @@ -18,18 +18,21 @@ package com.android.systemui.wallpapers.data.repository import android.app.WallpaperInfo import android.app.WallpaperManager +import android.content.ComponentName import android.content.Intent import android.content.pm.UserInfo +import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.data.repository.FakeKeyguardClockRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.user.data.model.SelectedUserModel import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.FakeUserRepository -import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.whenever +import com.android.systemui.wallpapers.data.repository.WallpaperRepositoryImpl.Companion.MAGIC_PORTRAIT_CLASSNAME import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher @@ -39,6 +42,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever @SmallTest @OptIn(ExperimentalCoroutinesApi::class) @@ -48,6 +54,8 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { private val testDispatcher = StandardTestDispatcher() private val testScope = TestScope(testDispatcher) private val userRepository = FakeUserRepository() + private val keyguardClockRepository = FakeKeyguardClockRepository() + private val keyguardRepository = FakeKeyguardRepository() private val wallpaperManager: WallpaperManager = mock() private val underTest: WallpaperRepositoryImpl by lazy { @@ -56,6 +64,8 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { testDispatcher, fakeBroadcastDispatcher, userRepository, + keyguardRepository, + keyguardClockRepository, wallpaperManager, context, ) @@ -219,7 +229,7 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { testScope.runTest { context.orCreateTestableResources.addOverride( com.android.internal.R.bool.config_dozeSupportsAodWallpaper, - false + false, ) val latest by collectLastValue(underTest.wallpaperInfo) @@ -407,7 +417,7 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { testScope.runTest { context.orCreateTestableResources.addOverride( com.android.internal.R.bool.config_dozeSupportsAodWallpaper, - false + false, ) val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) @@ -425,6 +435,54 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { assertThat(latest).isFalse() } + @Test + @EnableFlags(Flags.FLAG_MAGIC_PORTRAIT_WALLPAPERS) + fun shouldSendNotificationLayout_setMagicPortraitWallpaper_launchSendLayoutJob() = + testScope.runTest { + val latest by collectLastValue(underTest.shouldSendNotificationLayout) + val magicPortraitWallpaper = + mock<WallpaperInfo>().apply { + whenever(this.component) + .thenReturn(ComponentName(context, MAGIC_PORTRAIT_CLASSNAME)) + } + whenever(wallpaperManager.getWallpaperInfoForUser(any())) + .thenReturn(magicPortraitWallpaper) + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + assertThat(latest).isTrue() + assertThat(underTest.sendLockscreenLayoutJob).isNotNull() + assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true) + } + + @Test + @EnableFlags(Flags.FLAG_MAGIC_PORTRAIT_WALLPAPERS) + fun shouldSendNotificationLayout_setNotMagicPortraitWallpaper_cancelSendLayoutJob() = + testScope.runTest { + val latest by collectLastValue(underTest.shouldSendNotificationLayout) + val magicPortraitWallpaper = MAGIC_PORTRAIT_WP + whenever(wallpaperManager.getWallpaperInfoForUser(any())) + .thenReturn(magicPortraitWallpaper) + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + assertThat(latest).isTrue() + assertThat(underTest.sendLockscreenLayoutJob).isNotNull() + assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true) + + val nonMagicPortraitWallpaper = UNSUPPORTED_WP + whenever(wallpaperManager.getWallpaperInfoForUser(any())) + .thenReturn(nonMagicPortraitWallpaper) + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + assertThat(latest).isFalse() + assertThat(underTest.sendLockscreenLayoutJob?.isCancelled).isEqualTo(true) + } + private companion object { val USER_WITH_UNSUPPORTED_WP = UserInfo(/* id= */ 3, /* name= */ "user3", /* flags= */ 0) val UNSUPPORTED_WP = @@ -433,5 +491,10 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { val USER_WITH_SUPPORTED_WP = UserInfo(/* id= */ 4, /* name= */ "user4", /* flags= */ 0) val SUPPORTED_WP = mock<WallpaperInfo>().apply { whenever(this.supportsAmbientMode()).thenReturn(true) } + + val MAGIC_PORTRAIT_WP = + mock<WallpaperInfo>().apply { + whenever(this.component).thenReturn(ComponentName("", MAGIC_PORTRAIT_CLASSNAME)) + } } } diff --git a/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt new file mode 100644 index 000000000000..2850ab7b1e41 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.app + +import android.app.WallpaperManager +import android.content.applicationContext +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@OptIn(ExperimentalCoroutinesApi::class) +val Kosmos.wallpaperManager: WallpaperManager by Fixture { + WallpaperManager.getInstance(applicationContext) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt index 5e5f8cb1055a..159dd34efbbc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt @@ -46,16 +46,27 @@ class FakeKeyguardClockRepository() : KeyguardClockRepository { private val _previewClock = MutableStateFlow(Mockito.mock(ClockController::class.java)) override val previewClock: Flow<ClockController> get() = _previewClock + + private val _notificationDefaultTop = MutableStateFlow(0F) + override val notificationDefaultTop: StateFlow<Float> + get() = _notificationDefaultTop + override val clockEventController: ClockEventController get() = mock() + override val shouldForceSmallClock: Boolean get() = _shouldForceSmallClock + private var _shouldForceSmallClock: Boolean = false override fun setClockSize(size: ClockSize) { _clockSize.value = size } + override fun setNotificationDefaultTop(top: Float) { + _notificationDefaultTop.value = top + } + fun setSelectedClockSize(size: ClockSizeSetting) { _selectedClockSize.value = size } 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 54a6c0c1d182..e513e8d2a350 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 @@ -131,6 +131,10 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository { private val _isEncryptedOrLockdown = MutableStateFlow(true) override val isEncryptedOrLockdown: Flow<Boolean> = _isEncryptedOrLockdown + private val _shortcutAbsoluteTop = MutableStateFlow(0F) + override val shortcutAbsoluteTop: StateFlow<Float> + get() = _shortcutAbsoluteTop.asStateFlow() + private val _isKeyguardEnabled = MutableStateFlow(true) override val isKeyguardEnabled: StateFlow<Boolean> = _isKeyguardEnabled.asStateFlow() @@ -241,7 +245,7 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository { override fun setBiometricUnlockState( mode: BiometricUnlockMode, - source: BiometricUnlockSource? + source: BiometricUnlockSource?, ) { _biometricUnlockState.tryEmit(BiometricUnlockModel(mode, source)) } @@ -294,6 +298,10 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository { return isShowKeyguardWhenReenabled } + override fun setShortcutAbsoluteTop(top: Float) { + _shortcutAbsoluteTop.value = top + } + override fun setCanIgnoreAuthAndReturnToGone(canWake: Boolean) { _canIgnoreAuthAndReturnToGone.value = canWake } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt index 12d7c49194ff..49a8c1866aa2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt @@ -29,9 +29,10 @@ import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel import com.android.systemui.kosmos.Kosmos -import com.android.systemui.util.mockito.mock +import com.android.systemui.shade.LargeScreenHeaderHelper import java.util.Optional import org.mockito.Mockito.spy +import org.mockito.kotlin.mock val Kosmos.keyguardClockSection: ClockSection by Kosmos.Fixture { @@ -43,6 +44,7 @@ val Kosmos.keyguardClockSection: ClockSection by blueprintInteractor = { keyguardBlueprintInteractor }, rootViewModel = keyguardRootViewModel, aodBurnInViewModel = aodBurnInViewModel, + largeScreenHeaderHelperLazy = { mock<LargeScreenHeaderHelper>() }, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt index d52883eb38af..bdb9abb03c5f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt @@ -27,13 +27,13 @@ import com.android.systemui.statusbar.notification.stack.domain.interactor.heads val Kosmos.keyguardClockInteractor by Kosmos.Fixture { KeyguardClockInteractor( - keyguardClockRepository = keyguardClockRepository, - applicationScope = applicationCoroutineScope, mediaCarouselInteractor = mediaCarouselInteractor, activeNotificationsInteractor = activeNotificationsInteractor, shadeInteractor = shadeInteractor, keyguardInteractor = keyguardInteractor, keyguardTransitionInteractor = keyguardTransitionInteractor, headsUpNotificationInteractor = headsUpNotificationInteractor, + applicationScope = applicationCoroutineScope, + keyguardClockRepository = keyguardClockRepository, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt new file mode 100644 index 000000000000..1d8c891679aa --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wallpapers.data.repository + +import android.content.applicationContext +import com.android.app.wallpaperManager +import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.keyguard.data.repository.keyguardClockRepository +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +import com.android.systemui.user.data.repository.userRepository +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@OptIn(ExperimentalCoroutinesApi::class) +val Kosmos.wallpaperRepository by Fixture { + WallpaperRepositoryImpl( + context = applicationContext, + scope = testScope, + bgDispatcher = testDispatcher, + broadcastDispatcher = broadcastDispatcher, + userRepository = userRepository, + wallpaperManager = wallpaperManager, + keyguardClockRepository = keyguardClockRepository, + keyguardRepository = keyguardRepository, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractorKosmos.kt new file mode 100644 index 000000000000..5278351520f3 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wallpapers.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.wallpapers.data.repository.wallpaperRepository + +val Kosmos.wallpaperInteractor by + Kosmos.Fixture { WallpaperInteractor(wallpaperRepository = wallpaperRepository) } |