Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25af1134 authored by Nicolo' Mazzucato's avatar Nicolo' Mazzucato
Browse files

Provide empty ShadeDisplaysInteractor impl for sysui variants without shade window

This splits ShadeDisplaysInteractor into an interface.

This change facilitates providing a no-op implementation of
`ShadeDisplaysInteractor` for Android variants that do not have
a movable shade window, such as Wear OS or Android TV.

A new Dagger module, `ShadeDisplayAwareWindowWithoutShadeModule`,
is introduced to bind this no-op implementation. This allows
modules that depend on `ShadeDisplaysInteractor` (e.g., classes
within `SceneContainerFrameworkModule`) to function correctly on
these platforms without requiring the full shade window infrastructure.

The Wear component has been updated to include this module.

Bug: 362719719
Bug: 417921986
Test: builds in presubmits + manual tests on systemui google
Flag: com.android.systemui.shade_window_goes_around
Change-Id: I1f40de4b3b9e27c183b53e4ccb23be38027789fd
parent 5f309592
Loading
Loading
Loading
Loading
+49 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.shade
import android.content.Context
import android.content.res.Resources
import android.os.Bundle
import android.view.Display
import android.view.LayoutInflater
import android.view.WindowManager
import android.view.WindowManager.LayoutParams
@@ -49,6 +50,7 @@ import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor
import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractorImpl
import com.android.systemui.shade.domain.interactor.ShadeDisplaysDialogInteractor
import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor
import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractorImpl
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHider
import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHiderImpl
@@ -65,6 +67,8 @@ import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
import javax.inject.Provider
import javax.inject.Qualifier
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

/**
 * Module responsible for managing display-specific components and resources for the notification
@@ -324,13 +328,25 @@ object ShadeDisplayAwareModule {
    }
}

/** Module that should be included only if the shade window [WindowRootView] is available. */
/**
 * Module that should be included only if the shade window [WindowRootView] is available.
 *
 * This includes SystemUIGoogle variant.
 */
@Module
object ShadeDisplayAwareWithShadeWindowModule {

    @Provides
    @SysUISingleton
    fun bindShadeDisplaysInteractor(impl: ShadeDisplaysInteractorImpl): ShadeDisplaysInteractor =
        impl

    @Provides
    @IntoMap
    @ClassKey(ShadeDisplaysInteractor::class)
    fun provideShadeDisplaysInteractor(impl: Provider<ShadeDisplaysInteractor>): CoreStartable {
    @ClassKey(ShadeDisplaysInteractorImpl::class)
    fun provideShadeDisplaysInteractorCoreStartable(
        impl: Provider<ShadeDisplaysInteractorImpl>
    ): CoreStartable {
        return if (ShadeWindowGoesAround.isEnabled) {
            impl.get()
        } else {
@@ -350,6 +366,36 @@ object ShadeDisplayAwareWithShadeWindowModule {
        impl
}

/**
 * Dagger module to be included in Android variants where the `WindowRootView` (responsible for the
 * movable shade window) is NOT present, such as Wear OS or Android TV.
 *
 * Since `SystemUIModule` is common to all variants, some of its bound classes may have dependencies
 * expecting the shade window. This module ensures these dependencies are satisfied with no-op
 * implementations when the shade window is unavailable.
 *
 * Ideally, classes having WindowRootView dependencies shouldn't be instantiated at all in variants
 * that don't provide it, but sometimes this is not possible or too complicated.
 *
 * Making a concrete example might help understanding this: the Wear of sysui seems to be including
 * [SceneContainerFrameworkModule] that has some classes depending to the shade window and its
 * position. While it's unclear why Wear needs to depend on the Scene container, providing here a
 * no-op [ShadeDisplaysInteractor] will guarantee no classes depending on the WindowRootView are
 * created (as the window root view is not available).
 */
@Module
object ShadeDisplayAwareWindowWithoutShadeModule {

    @Provides
    @SysUISingleton
    fun bindShadeDisplaysInteractor(): ShadeDisplaysInteractor =
        object : ShadeDisplaysInteractor {
            override val displayId: StateFlow<Int> = MutableStateFlow(Display.DEFAULT_DISPLAY)
            override val pendingDisplayId: StateFlow<Int> =
                MutableStateFlow(Display.DEFAULT_DISPLAY)
        }
}

/**
 * Annotates the boolean value that defines whether the shade window should go back to the default
 * display when the keyguard is visible.
+15 −5
Original line number Diff line number Diff line
@@ -56,8 +56,19 @@ import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull

/** Handles Shade window display change when [ShadeDisplaysRepository.displayId] changes. */
interface ShadeDisplaysInteractor {
    /** Current display id of the shade window. */
    val displayId: StateFlow<Int>
    /**
     * Target display id of the shade window.
     *
     * Triggers the window move. Once committed, [displayId] will match this.
     */
    val pendingDisplayId: StateFlow<Int>
}

@SysUISingleton
class ShadeDisplaysInteractor
class ShadeDisplaysInteractorImpl
@Inject
constructor(
    private val shadePositionRepository: MutableShadeDisplaysRepository,
@@ -73,15 +84,14 @@ constructor(
    private val notificationStackRebindingHider: NotificationStackRebindingHider,
    @ShadeDisplayAware private val configForwarder: ConfigurationForwarder,
    @ShadeDisplayLog private val logBuffer: LogBuffer,
) : CoreStartable {
) : ShadeDisplaysInteractor, CoreStartable {

    private val hasActiveNotifications: Boolean
        get() = activeNotificationsInteractor.areAnyNotificationsPresentValue

    /** Current display id of the shade window. */
    val displayId: StateFlow<Int> = shadePositionRepository.displayId
    override val displayId: StateFlow<Int> = shadePositionRepository.displayId

    val pendingDisplayId: StateFlow<Int> = shadePositionRepository.pendingDisplayId
    override val pendingDisplayId: StateFlow<Int> = shadePositionRepository.pendingDisplayId

    override fun start() {
        ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
+1 −1
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ val Kosmos.mockedShadeDisplayChangeLatencyTracker by
    Kosmos.Fixture { mock<ShadeDisplayChangeLatencyTracker>() }
val Kosmos.shadeDisplaysInteractor by
    Kosmos.Fixture {
        ShadeDisplaysInteractor(
        ShadeDisplaysInteractorImpl(
            fakeShadeDisplaysRepository,
            mockedWindowContext,
            configurationRepository,